@dxos/react-ui-editor 0.8.4-main.a4bbb77 → 0.8.4-main.ae835ea
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/{chunk-22UMM3QJ.mjs → chunk-HL3YF6WC.mjs} +2 -2
- package/dist/lib/browser/chunk-HL3YF6WC.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +4577 -4832
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node-esm/{chunk-YXYQPV6R.mjs → chunk-YJZGD3LY.mjs} +2 -2
- package/dist/lib/node-esm/chunk-YJZGD3LY.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +4577 -4832
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs.map +2 -2
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/components/Editor/Editor.d.ts +13 -4
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts +27 -0
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +17 -2
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/util.d.ts +5 -19
- package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/index.d.ts +5 -0
- package/dist/types/src/extensions/autocomplete/index.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/match.d.ts +13 -0
- package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts +20 -0
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts +10 -0
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/sync.d.ts +3 -3
- package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/autoscroll.d.ts +2 -2
- package/dist/types/src/extensions/autoscroll.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts +1 -1
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -1
- package/dist/types/src/extensions/factories.d.ts +9 -4
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +2 -3
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/json.d.ts +1 -1
- package/dist/types/src/extensions/json.d.ts.map +1 -1
- package/dist/types/src/extensions/listener.d.ts +8 -6
- package/dist/types/src/extensions/listener.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +1 -2
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/modes.d.ts +1 -1
- package/dist/types/src/extensions/modes.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner/menu.d.ts +8 -0
- package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts +36 -0
- package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/index.d.ts +8 -0
- package/dist/types/src/extensions/popover/index.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/menu-presets.d.ts +4 -0
- package/dist/types/src/extensions/popover/menu-presets.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/menu.d.ts +24 -0
- package/dist/types/src/extensions/popover/menu.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/modal.d.ts +7 -0
- package/dist/types/src/extensions/popover/modal.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/popover.d.ts +47 -0
- package/dist/types/src/extensions/popover/popover.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/usePopoverMenu.d.ts +34 -0
- package/dist/types/src/extensions/popover/usePopoverMenu.d.ts.map +1 -0
- package/dist/types/src/extensions/popover/util.d.ts +8 -0
- package/dist/types/src/extensions/popover/util.d.ts.map +1 -0
- package/dist/types/src/extensions/preview/preview.d.ts +6 -3
- package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
- package/dist/types/src/extensions/state.d.ts +2 -0
- package/dist/types/src/extensions/state.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextEditor.d.ts +2 -6
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts +2 -2
- package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Experimental.stories.d.ts +2 -2
- package/dist/types/src/stories/Markdown.stories.d.ts +2 -2
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
- package/dist/types/src/stories/{CommandMenu.stories.d.ts → Popover.stories.d.ts} +6 -5
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Preview.stories.d.ts +2 -2
- package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
- package/dist/types/src/stories/TextEditor.stories.d.ts +2 -3
- package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts +3 -3
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/src/testing/PreviewPopover.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +1 -1
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -38
- package/src/components/Editor/Editor.stories.tsx +69 -0
- package/src/components/Editor/Editor.tsx +25 -17
- package/src/components/EditorToolbar/EditorToolbar.tsx +88 -87
- package/src/components/EditorToolbar/headings.ts +6 -4
- package/src/components/EditorToolbar/util.ts +2 -18
- package/src/components/index.ts +0 -1
- package/src/extensions/{autocomplete.ts → autocomplete/autocomplete.ts} +1 -0
- package/src/extensions/autocomplete/index.ts +8 -0
- package/src/extensions/autocomplete/match.ts +46 -0
- package/src/extensions/{command-menu → autocomplete}/placeholder.ts +21 -17
- package/src/extensions/{command-dialog → autocomplete}/typeahead.ts +6 -48
- package/src/extensions/automerge/automerge.ts +28 -9
- package/src/extensions/automerge/cursor.ts +1 -1
- package/src/extensions/automerge/sync.ts +8 -4
- package/src/extensions/automerge/update-automerge.ts +1 -1
- package/src/extensions/autoscroll.ts +3 -3
- package/src/extensions/awareness/awareness-provider.ts +2 -2
- package/src/extensions/factories.ts +18 -10
- package/src/extensions/hashtag.tsx +2 -2
- package/src/extensions/index.ts +2 -3
- package/src/extensions/json.ts +1 -1
- package/src/extensions/listener.ts +14 -20
- package/src/extensions/markdown/bundle.ts +14 -2
- package/src/extensions/markdown/formatting.ts +8 -8
- package/src/extensions/modes.ts +2 -2
- package/src/extensions/{floating-menu.ts → outliner/menu.ts} +7 -5
- package/src/extensions/outliner/outliner.ts +2 -2
- package/src/extensions/popover/PopoverMenuProvider.tsx +220 -0
- package/src/extensions/popover/index.ts +12 -0
- package/src/extensions/popover/menu-presets.ts +124 -0
- package/src/extensions/popover/menu.ts +67 -0
- package/src/extensions/popover/modal.ts +24 -0
- package/src/extensions/popover/popover.ts +289 -0
- package/src/extensions/popover/usePopoverMenu.ts +173 -0
- package/src/extensions/popover/util.ts +29 -0
- package/src/extensions/preview/index.ts +1 -1
- package/src/extensions/preview/preview.ts +10 -7
- package/src/extensions/state.ts +7 -0
- package/src/hooks/useTextEditor.ts +21 -21
- package/src/stories/CommandDialog.stories.tsx +3 -14
- package/src/stories/EditorToolbar.stories.tsx +4 -5
- package/src/stories/Outliner.stories.tsx +16 -9
- package/src/stories/Popover.stories.tsx +163 -0
- package/src/stories/Preview.stories.tsx +15 -8
- package/src/stories/TextEditor.stories.tsx +3 -29
- package/src/stories/components/EditorStory.tsx +5 -3
- package/src/styles/theme.ts +2 -1
- package/src/testing/PreviewPopover.tsx +2 -0
- package/src/types/types.ts +1 -1
- package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +0 -7
- package/dist/types/src/components/CommandMenu/CommandMenu.d.ts +0 -38
- package/dist/types/src/components/CommandMenu/CommandMenu.d.ts.map +0 -1
- package/dist/types/src/components/CommandMenu/index.d.ts +0 -2
- package/dist/types/src/components/CommandMenu/index.d.ts.map +0 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/action.d.ts +0 -17
- package/dist/types/src/extensions/command-dialog/action.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/command-dialog.d.ts +0 -6
- package/dist/types/src/extensions/command-dialog/command-dialog.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/hint.d.ts +0 -19
- package/dist/types/src/extensions/command-dialog/hint.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/index.d.ts +0 -4
- package/dist/types/src/extensions/command-dialog/index.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/state.d.ts +0 -16
- package/dist/types/src/extensions/command-dialog/state.d.ts.map +0 -1
- package/dist/types/src/extensions/command-dialog/typeahead.d.ts +0 -22
- package/dist/types/src/extensions/command-dialog/typeahead.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/command-menu.d.ts +0 -20
- package/dist/types/src/extensions/command-menu/command-menu.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/index.d.ts +0 -3
- package/dist/types/src/extensions/command-menu/index.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/placeholder.d.ts +0 -10
- package/dist/types/src/extensions/command-menu/placeholder.d.ts.map +0 -1
- package/dist/types/src/extensions/command-menu/useCommandMenu.d.ts +0 -24
- package/dist/types/src/extensions/command-menu/useCommandMenu.d.ts.map +0 -1
- package/dist/types/src/extensions/floating-menu.d.ts +0 -7
- package/dist/types/src/extensions/floating-menu.d.ts.map +0 -1
- package/dist/types/src/stories/CommandMenu.stories.d.ts.map +0 -1
- package/src/components/CommandMenu/CommandMenu.tsx +0 -348
- package/src/components/CommandMenu/index.ts +0 -5
- package/src/extensions/command-dialog/action.ts +0 -55
- package/src/extensions/command-dialog/command-dialog.ts +0 -34
- package/src/extensions/command-dialog/hint.ts +0 -103
- package/src/extensions/command-dialog/index.ts +0 -7
- package/src/extensions/command-dialog/state.ts +0 -90
- package/src/extensions/command-menu/command-menu.ts +0 -210
- package/src/extensions/command-menu/index.ts +0 -6
- package/src/extensions/command-menu/useCommandMenu.ts +0 -134
- package/src/stories/CommandMenu.stories.tsx +0 -158
- /package/dist/types/src/extensions/{autocomplete.d.ts → autocomplete/autocomplete.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-editor",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.ae835ea",
|
|
4
4
|
"description": "Document editing experience within a DXOS shell.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@automerge/automerge": "3.1.2",
|
|
41
41
|
"@codemirror/autocomplete": "^6.19.0",
|
|
42
42
|
"@codemirror/commands": "^6.8.1",
|
|
43
|
+
"@codemirror/lang-html": "^6.4.11",
|
|
43
44
|
"@codemirror/lang-javascript": "^6.2.4",
|
|
44
45
|
"@codemirror/lang-json": "^6.0.2",
|
|
45
46
|
"@codemirror/lang-markdown": "^6.3.4",
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
63
64
|
"@replit/codemirror-vim": "^6.2.1",
|
|
64
65
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
66
|
+
"@uiw/codemirror-theme-vscode": "^4.25.2",
|
|
65
67
|
"ajv": "^8.17.1",
|
|
66
68
|
"codemirror": "^6.0.1",
|
|
67
69
|
"lib0": "^0.2.65",
|
|
@@ -69,27 +71,28 @@
|
|
|
69
71
|
"lodash.merge": "^4.6.2",
|
|
70
72
|
"lodash.sortby": "^4.7.0",
|
|
71
73
|
"style-mod": "^4.1.0",
|
|
72
|
-
"@dxos/app-graph": "0.8.4-main.
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/invariant": "0.8.4-main.
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/log": "0.8.4-main.
|
|
82
|
-
"@dxos/
|
|
83
|
-
"@dxos/react-ui-menu": "0.8.4-main.
|
|
84
|
-
"@dxos/
|
|
85
|
-
"@dxos/
|
|
86
|
-
"@dxos/
|
|
87
|
-
"@dxos/
|
|
74
|
+
"@dxos/app-graph": "0.8.4-main.ae835ea",
|
|
75
|
+
"@dxos/client": "0.8.4-main.ae835ea",
|
|
76
|
+
"@dxos/async": "0.8.4-main.ae835ea",
|
|
77
|
+
"@dxos/context": "0.8.4-main.ae835ea",
|
|
78
|
+
"@dxos/debug": "0.8.4-main.ae835ea",
|
|
79
|
+
"@dxos/display-name": "0.8.4-main.ae835ea",
|
|
80
|
+
"@dxos/invariant": "0.8.4-main.ae835ea",
|
|
81
|
+
"@dxos/live-object": "0.8.4-main.ae835ea",
|
|
82
|
+
"@dxos/lit-ui": "0.8.4-main.ae835ea",
|
|
83
|
+
"@dxos/log": "0.8.4-main.ae835ea",
|
|
84
|
+
"@dxos/react-hooks": "0.8.4-main.ae835ea",
|
|
85
|
+
"@dxos/react-ui-menu": "0.8.4-main.ae835ea",
|
|
86
|
+
"@dxos/protocols": "0.8.4-main.ae835ea",
|
|
87
|
+
"@dxos/echo": "0.8.4-main.ae835ea",
|
|
88
|
+
"@dxos/react-ui-stack": "0.8.4-main.ae835ea",
|
|
89
|
+
"@dxos/util": "0.8.4-main.ae835ea",
|
|
90
|
+
"@dxos/react-ui-types": "0.8.4-main.ae835ea"
|
|
88
91
|
},
|
|
89
92
|
"devDependencies": {
|
|
90
93
|
"@automerge/automerge": "3.1.2",
|
|
91
|
-
"@automerge/automerge-repo": "2.
|
|
92
|
-
"@automerge/automerge-repo-network-broadcastchannel": "2.
|
|
94
|
+
"@automerge/automerge-repo": "2.4.0",
|
|
95
|
+
"@automerge/automerge-repo-network-broadcastchannel": "2.4.0",
|
|
93
96
|
"@effect-rx/rx-react": "0.42.4",
|
|
94
97
|
"@effect/platform": "0.92.1",
|
|
95
98
|
"@types/chai": "^4.2.15",
|
|
@@ -97,14 +100,14 @@
|
|
|
97
100
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
98
101
|
"@types/lodash.merge": "^4.6.6",
|
|
99
102
|
"@types/lodash.sortby": "^4.7.7",
|
|
100
|
-
"@types/react": "~19.2.
|
|
101
|
-
"@types/react-dom": "~19.2.
|
|
103
|
+
"@types/react": "~19.2.2",
|
|
104
|
+
"@types/react-dom": "~19.2.2",
|
|
102
105
|
"@types/react-test-renderer": "^17.0.2",
|
|
103
106
|
"chai": "^4.4.1",
|
|
104
107
|
"chai-dom": "^1.11.0",
|
|
105
108
|
"effect": "3.18.3",
|
|
106
109
|
"happy-dom": "^13.3.1",
|
|
107
|
-
"jsdom": "^
|
|
110
|
+
"jsdom": "^27.0.0",
|
|
108
111
|
"mocha": "^10.6.0",
|
|
109
112
|
"react": "~19.2.0",
|
|
110
113
|
"react-dom": "~19.2.0",
|
|
@@ -112,19 +115,19 @@
|
|
|
112
115
|
"vite": "7.1.9",
|
|
113
116
|
"vite-plugin-top-level-await": "^1.6.0",
|
|
114
117
|
"vite-plugin-wasm": "^3.5.0",
|
|
115
|
-
"@dxos/
|
|
116
|
-
"@dxos/echo
|
|
117
|
-
"@dxos/
|
|
118
|
-
"@dxos/
|
|
119
|
-
"@dxos/
|
|
120
|
-
"@dxos/react-
|
|
121
|
-
"@dxos/
|
|
122
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
123
|
-
"@dxos/react-ui-
|
|
124
|
-
"@dxos/react-ui-
|
|
125
|
-
"@dxos/
|
|
126
|
-
"@dxos/
|
|
127
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
118
|
+
"@dxos/config": "0.8.4-main.ae835ea",
|
|
119
|
+
"@dxos/echo": "0.8.4-main.ae835ea",
|
|
120
|
+
"@dxos/echo-signals": "0.8.4-main.ae835ea",
|
|
121
|
+
"@dxos/random": "0.8.4-main.ae835ea",
|
|
122
|
+
"@dxos/keyboard": "0.8.4-main.ae835ea",
|
|
123
|
+
"@dxos/react-client": "0.8.4-main.ae835ea",
|
|
124
|
+
"@dxos/react-ui": "0.8.4-main.ae835ea",
|
|
125
|
+
"@dxos/react-ui-attention": "0.8.4-main.ae835ea",
|
|
126
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.ae835ea",
|
|
127
|
+
"@dxos/react-ui-theme": "0.8.4-main.ae835ea",
|
|
128
|
+
"@dxos/schema": "0.8.4-main.ae835ea",
|
|
129
|
+
"@dxos/react-ui-stack": "0.8.4-main.ae835ea",
|
|
130
|
+
"@dxos/storybook-utils": "0.8.4-main.ae835ea"
|
|
128
131
|
},
|
|
129
132
|
"peerDependencies": {
|
|
130
133
|
"@effect-rx/rx-react": "^0.34.1",
|
|
@@ -132,9 +135,9 @@
|
|
|
132
135
|
"effect": "^3.13.3",
|
|
133
136
|
"react": "^19.0.0",
|
|
134
137
|
"react-dom": "^19.0.0",
|
|
135
|
-
"@dxos/react-client": "0.8.4-main.
|
|
136
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
137
|
-
"@dxos/react-ui
|
|
138
|
+
"@dxos/react-client": "0.8.4-main.ae835ea",
|
|
139
|
+
"@dxos/react-ui-theme": "0.8.4-main.ae835ea",
|
|
140
|
+
"@dxos/react-ui": "0.8.4-main.ae835ea"
|
|
138
141
|
},
|
|
139
142
|
"publishConfig": {
|
|
140
143
|
"access": "public"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
|
|
9
|
+
import { createDocAccessor, createObject } from '@dxos/client/echo';
|
|
10
|
+
import { useThemeContext } from '@dxos/react-ui';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
|
+
import { DataType } from '@dxos/schema';
|
|
13
|
+
|
|
14
|
+
import { automerge, createBasicExtensions, createThemeExtensions } from '../../extensions';
|
|
15
|
+
import { Editor } from '../Editor';
|
|
16
|
+
|
|
17
|
+
const meta = {
|
|
18
|
+
title: 'ui/react-ui-editor/Editor',
|
|
19
|
+
component: Editor,
|
|
20
|
+
decorators: [withTheme, withLayout({ container: 'column' })],
|
|
21
|
+
} satisfies Meta<typeof Editor>;
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof meta>;
|
|
26
|
+
|
|
27
|
+
export const Default: Story = {
|
|
28
|
+
render: (args) => {
|
|
29
|
+
const { themeMode } = useThemeContext();
|
|
30
|
+
const extensions = useMemo(
|
|
31
|
+
() => [
|
|
32
|
+
// Basic extensions.
|
|
33
|
+
createBasicExtensions(),
|
|
34
|
+
createThemeExtensions({ themeMode }),
|
|
35
|
+
],
|
|
36
|
+
[],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return <Editor classNames='p-2' {...args} extensions={extensions} />;
|
|
40
|
+
},
|
|
41
|
+
args: {
|
|
42
|
+
moveToEnd: true,
|
|
43
|
+
value: 'Hello world!',
|
|
44
|
+
onChange: (value) => console.log(value),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const Automerge: Story = {
|
|
49
|
+
render: ({ value, ...props }) => {
|
|
50
|
+
const { themeMode } = useThemeContext();
|
|
51
|
+
const extensions = useMemo(
|
|
52
|
+
() => [
|
|
53
|
+
// Basic extensions.
|
|
54
|
+
createBasicExtensions(),
|
|
55
|
+
createThemeExtensions({ themeMode }),
|
|
56
|
+
automerge(createDocAccessor(createObject(DataType.makeText(value)), ['content'])),
|
|
57
|
+
],
|
|
58
|
+
[],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// TODO(burdon): Remove the need for initialValue.
|
|
62
|
+
return <Editor classNames='p-2' {...props} initialValue={value} extensions={extensions} />;
|
|
63
|
+
},
|
|
64
|
+
args: {
|
|
65
|
+
moveToEnd: true,
|
|
66
|
+
value: 'Hello world!',
|
|
67
|
+
onChange: (value) => console.log(value),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Transaction } from '@codemirror/state';
|
|
5
6
|
import { EditorView } from '@codemirror/view';
|
|
6
7
|
import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
|
|
7
8
|
|
|
8
9
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
9
10
|
import { mx } from '@dxos/react-ui-theme';
|
|
10
11
|
|
|
12
|
+
import { initialSync } from '../../extensions';
|
|
11
13
|
import { type UseTextEditorProps, useTextEditor } from '../../hooks';
|
|
12
14
|
|
|
15
|
+
// TODO(burdon): Convert to radix-style (support hooks inside).
|
|
16
|
+
// <Editor.Root>
|
|
17
|
+
// <Editor.Toolbar />
|
|
18
|
+
// <Editor.TextEditor />
|
|
19
|
+
// </Editor.Root>
|
|
20
|
+
|
|
13
21
|
export type EditorController = {
|
|
14
22
|
view: EditorView | null;
|
|
15
23
|
focus: () => void;
|
|
@@ -17,10 +25,10 @@ export type EditorController = {
|
|
|
17
25
|
|
|
18
26
|
export type EditorProps = ThemedClassName<
|
|
19
27
|
{
|
|
20
|
-
value?: string;
|
|
21
28
|
moveToEnd?: boolean;
|
|
29
|
+
value?: string;
|
|
22
30
|
onChange?: (value: string) => void;
|
|
23
|
-
} &
|
|
31
|
+
} & UseTextEditorProps
|
|
24
32
|
>;
|
|
25
33
|
|
|
26
34
|
/**
|
|
@@ -28,17 +36,17 @@ export type EditorProps = ThemedClassName<
|
|
|
28
36
|
* NOTE: This shouold not be used with the automerge extension.
|
|
29
37
|
*/
|
|
30
38
|
export const Editor = forwardRef<EditorController, EditorProps>(
|
|
31
|
-
({ classNames, id, extensions
|
|
39
|
+
({ classNames, id, extensions, moveToEnd, value, onChange, ...props }, forwardedRef) => {
|
|
32
40
|
const { parentRef, focusAttributes, view } = useTextEditor(
|
|
33
41
|
() => ({
|
|
34
42
|
id,
|
|
43
|
+
initialValue: value,
|
|
35
44
|
extensions: [
|
|
36
|
-
extensions,
|
|
37
|
-
EditorView.updateListener.of((
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
onChange?.(value);
|
|
45
|
+
extensions ?? [],
|
|
46
|
+
EditorView.updateListener.of(({ view, docChanged, transactions }) => {
|
|
47
|
+
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
|
|
48
|
+
if (!isInitialSync && docChanged) {
|
|
49
|
+
onChange?.(view.state.doc.toString());
|
|
42
50
|
}
|
|
43
51
|
}),
|
|
44
52
|
],
|
|
@@ -57,16 +65,16 @@ export const Editor = forwardRef<EditorController, EditorProps>(
|
|
|
57
65
|
[view],
|
|
58
66
|
);
|
|
59
67
|
|
|
60
|
-
//
|
|
68
|
+
// Set initial value and cursor position.
|
|
61
69
|
useEffect(() => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
});
|
|
70
|
+
requestAnimationFrame(() => {
|
|
71
|
+
view?.dispatch({
|
|
72
|
+
annotations: initialSync,
|
|
73
|
+
changes: value ? [{ from: 0, to: view?.state.doc.length ?? 0, insert: value ?? '' }] : [],
|
|
74
|
+
selection: moveToEnd ? { anchor: view?.state.doc.length ?? 0 } : undefined,
|
|
68
75
|
});
|
|
69
|
-
|
|
76
|
+
view?.focus();
|
|
77
|
+
});
|
|
70
78
|
}, [view, value, moveToEnd]);
|
|
71
79
|
|
|
72
80
|
return <div role='none' className={mx('is-full', classNames)} {...focusAttributes} ref={parentRef} />;
|
|
@@ -6,7 +6,7 @@ import { Rx } from '@effect-rx/rx-react';
|
|
|
6
6
|
import React, { memo, useMemo } from 'react';
|
|
7
7
|
|
|
8
8
|
import { rxFromSignal } from '@dxos/app-graph';
|
|
9
|
-
import { ElevationProvider } from '@dxos/react-ui';
|
|
9
|
+
import { ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
|
|
10
10
|
import {
|
|
11
11
|
type ActionGraphProps,
|
|
12
12
|
MenuProvider,
|
|
@@ -15,120 +15,121 @@ import {
|
|
|
15
15
|
useMenuActions,
|
|
16
16
|
} from '@dxos/react-ui-menu';
|
|
17
17
|
|
|
18
|
+
import { type EditorViewMode } from '../../types';
|
|
19
|
+
|
|
18
20
|
import { createBlocks } from './blocks';
|
|
19
21
|
import { createFormatting } from './formatting';
|
|
20
22
|
import { createHeadings } from './headings';
|
|
21
23
|
import { createImageUpload } from './image';
|
|
22
24
|
import { createLists } from './lists';
|
|
23
25
|
import { createSearch } from './search';
|
|
24
|
-
import { type EditorToolbarActionGraphProps
|
|
26
|
+
import { type EditorToolbarActionGraphProps } from './util';
|
|
25
27
|
import { createViewMode } from './view-mode';
|
|
26
28
|
|
|
29
|
+
export type EditorToolbarFeatureFlags = Partial<{
|
|
30
|
+
showHeadings: boolean;
|
|
31
|
+
showFormatting: boolean;
|
|
32
|
+
showLists: boolean;
|
|
33
|
+
showBlocks: boolean;
|
|
34
|
+
showSearch: boolean;
|
|
35
|
+
|
|
36
|
+
// TODO(wittjosiah): Factor out (depends on plugin-level capabilities.)
|
|
37
|
+
onImageUpload: () => void;
|
|
38
|
+
onViewModeChange: (mode: EditorViewMode) => void;
|
|
39
|
+
}>;
|
|
40
|
+
|
|
41
|
+
export type EditorToolbarProps = ThemedClassName<
|
|
42
|
+
{
|
|
43
|
+
role?: string;
|
|
44
|
+
attendableId?: string;
|
|
45
|
+
} & (EditorToolbarActionGraphProps & EditorToolbarFeatureFlags)
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
// TODO(burdon): Remove role dependency.
|
|
49
|
+
export const EditorToolbar = memo(({ classNames, role, attendableId, ...props }: EditorToolbarProps) => {
|
|
50
|
+
const menuProps = useEditorToolbarActionGraph(props);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
|
|
54
|
+
<MenuProvider {...menuProps} attendableId={attendableId}>
|
|
55
|
+
<ToolbarMenu classNames={classNames} textBlockWidth />
|
|
56
|
+
</MenuProvider>
|
|
57
|
+
</ElevationProvider>
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
type ToolbarActionsProps = Pick<EditorToolbarActionGraphProps, 'state' | 'getView' | 'customActions'> &
|
|
62
|
+
EditorToolbarFeatureFlags;
|
|
63
|
+
|
|
64
|
+
// TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
|
|
65
|
+
// E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
|
|
66
|
+
// This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
|
|
67
|
+
const useEditorToolbarActionGraph = ({ state, getView, customActions, ...features }: ToolbarActionsProps) => {
|
|
68
|
+
const menuCreator = useMemo(
|
|
69
|
+
() => createToolbarActions({ state, getView, customActions, ...features }),
|
|
70
|
+
[
|
|
71
|
+
state,
|
|
72
|
+
getView,
|
|
73
|
+
customActions,
|
|
74
|
+
features?.showHeadings,
|
|
75
|
+
features?.showFormatting,
|
|
76
|
+
features?.showLists,
|
|
77
|
+
features?.showBlocks,
|
|
78
|
+
features?.showSearch,
|
|
79
|
+
features?.onImageUpload,
|
|
80
|
+
features?.onViewModeChange,
|
|
81
|
+
],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return useMenuActions(menuCreator);
|
|
85
|
+
};
|
|
86
|
+
|
|
27
87
|
const createToolbarActions = ({
|
|
28
|
-
getView,
|
|
29
88
|
state,
|
|
89
|
+
getView,
|
|
30
90
|
customActions,
|
|
31
91
|
...features
|
|
32
|
-
}:
|
|
33
|
-
Pick<EditorToolbarActionGraphProps, 'getView' | 'state' | 'customActions'>): Rx.Rx<ActionGraphProps> => {
|
|
92
|
+
}: ToolbarActionsProps): Rx.Rx<ActionGraphProps> => {
|
|
34
93
|
return Rx.make((get) => {
|
|
35
94
|
const graph: ActionGraphProps = {
|
|
36
95
|
nodes: [],
|
|
37
96
|
edges: [],
|
|
38
97
|
};
|
|
39
98
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
graph.nodes.push(...
|
|
43
|
-
graph.edges.push(...
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
graph
|
|
48
|
-
graph.edges.push(...formatting.edges);
|
|
99
|
+
// TODO(burdon): Builder pattern?
|
|
100
|
+
const addSubGraph = (graph: ActionGraphProps, subGraph: ActionGraphProps) => {
|
|
101
|
+
graph.nodes.push(...subGraph.nodes);
|
|
102
|
+
graph.edges.push(...subGraph.edges);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
if (features?.showHeadings ?? true) {
|
|
106
|
+
addSubGraph(graph, get(rxFromSignal(() => createHeadings(state, getView))));
|
|
49
107
|
}
|
|
50
|
-
if (features
|
|
51
|
-
|
|
52
|
-
graph.nodes.push(...lists.nodes);
|
|
53
|
-
graph.edges.push(...lists.edges);
|
|
108
|
+
if (features?.showFormatting ?? true) {
|
|
109
|
+
addSubGraph(graph, get(rxFromSignal(() => createFormatting(state, getView))));
|
|
54
110
|
}
|
|
55
|
-
if (features
|
|
56
|
-
|
|
57
|
-
graph.nodes.push(...blocks.nodes);
|
|
58
|
-
graph.edges.push(...blocks.edges);
|
|
111
|
+
if (features?.showLists ?? true) {
|
|
112
|
+
addSubGraph(graph, get(rxFromSignal(() => createLists(state, getView))));
|
|
59
113
|
}
|
|
60
|
-
if (features
|
|
61
|
-
|
|
62
|
-
graph.nodes.push(...image.nodes);
|
|
63
|
-
graph.edges.push(...image.edges);
|
|
114
|
+
if (features?.showBlocks ?? true) {
|
|
115
|
+
addSubGraph(graph, get(rxFromSignal(() => createBlocks(state, getView))));
|
|
64
116
|
}
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
graph.nodes.push(...gap.nodes);
|
|
68
|
-
graph.edges.push(...gap.edges);
|
|
117
|
+
if (features?.onImageUpload) {
|
|
118
|
+
addSubGraph(graph, get(rxFromSignal(() => createImageUpload(features.onImageUpload!))));
|
|
69
119
|
}
|
|
120
|
+
|
|
121
|
+
addSubGraph(graph, createGapSeparator());
|
|
122
|
+
|
|
70
123
|
if (customActions) {
|
|
71
|
-
|
|
72
|
-
graph.nodes.push(...custom.nodes);
|
|
73
|
-
graph.edges.push(...custom.edges);
|
|
124
|
+
addSubGraph(graph, get(customActions));
|
|
74
125
|
}
|
|
75
|
-
if (features
|
|
76
|
-
|
|
77
|
-
graph.nodes.push(...search.nodes);
|
|
78
|
-
graph.edges.push(...search.edges);
|
|
126
|
+
if (features?.showSearch ?? true) {
|
|
127
|
+
addSubGraph(graph, get(rxFromSignal(() => createSearch(getView))));
|
|
79
128
|
}
|
|
80
|
-
if (features
|
|
81
|
-
|
|
82
|
-
graph.nodes.push(...viewMode.nodes);
|
|
83
|
-
graph.edges.push(...viewMode.edges);
|
|
129
|
+
if (features?.onViewModeChange) {
|
|
130
|
+
addSubGraph(graph, get(rxFromSignal(() => createViewMode(state, features.onViewModeChange!))));
|
|
84
131
|
}
|
|
85
132
|
|
|
86
133
|
return graph;
|
|
87
134
|
});
|
|
88
135
|
};
|
|
89
|
-
|
|
90
|
-
// TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
|
|
91
|
-
// E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
|
|
92
|
-
// This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
|
|
93
|
-
const useEditorToolbarActionGraph = (props: EditorToolbarProps) => {
|
|
94
|
-
const menuCreator = useMemo(
|
|
95
|
-
() =>
|
|
96
|
-
createToolbarActions({
|
|
97
|
-
getView: props.getView,
|
|
98
|
-
state: props.state,
|
|
99
|
-
customActions: props.customActions,
|
|
100
|
-
headings: props.headings,
|
|
101
|
-
formatting: props.formatting,
|
|
102
|
-
lists: props.lists,
|
|
103
|
-
blocks: props.blocks,
|
|
104
|
-
image: props.image,
|
|
105
|
-
search: props.search,
|
|
106
|
-
viewMode: props.viewMode,
|
|
107
|
-
}),
|
|
108
|
-
[
|
|
109
|
-
props.getView,
|
|
110
|
-
props.state,
|
|
111
|
-
props.customActions,
|
|
112
|
-
props.headings,
|
|
113
|
-
props.formatting,
|
|
114
|
-
props.lists,
|
|
115
|
-
props.blocks,
|
|
116
|
-
props.image,
|
|
117
|
-
props.search,
|
|
118
|
-
props.viewMode,
|
|
119
|
-
],
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
return useMenuActions(menuCreator);
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
export const EditorToolbar = memo(({ classNames, attendableId, role, ...props }: EditorToolbarProps) => {
|
|
126
|
-
const menuProps = useEditorToolbarActionGraph(props);
|
|
127
|
-
return (
|
|
128
|
-
<ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
|
|
129
|
-
<MenuProvider {...menuProps} attendableId={attendableId}>
|
|
130
|
-
<ToolbarMenu classNames={classNames} textBlockWidth />
|
|
131
|
-
</MenuProvider>
|
|
132
|
-
</ElevationProvider>
|
|
133
|
-
);
|
|
134
|
-
});
|
|
@@ -19,12 +19,13 @@ const createHeadingGroupAction = (value: string) =>
|
|
|
19
19
|
variant: 'dropdownMenu',
|
|
20
20
|
applyActive: true,
|
|
21
21
|
selectCardinality: 'single',
|
|
22
|
+
// TODO(wittjosiah): Remove? Not sure this does anything.
|
|
22
23
|
value,
|
|
23
24
|
} as ToolbarMenuActionGroupProperties,
|
|
24
25
|
'ph--text-h--regular',
|
|
25
26
|
);
|
|
26
27
|
|
|
27
|
-
const createHeadingActions = (getView: () => EditorView) =>
|
|
28
|
+
const createHeadingActions = (currentLevel: string, getView: () => EditorView) =>
|
|
28
29
|
Object.entries({
|
|
29
30
|
'0': 'ph--paragraph--regular',
|
|
30
31
|
'1': 'ph--text-h-one--regular',
|
|
@@ -40,6 +41,7 @@ const createHeadingActions = (getView: () => EditorView) =>
|
|
|
40
41
|
{
|
|
41
42
|
label: ['heading level label', { count: level, ns: translationKey }],
|
|
42
43
|
icon,
|
|
44
|
+
checked: levelStr === currentLevel,
|
|
43
45
|
},
|
|
44
46
|
() => setHeading(level)(getView()),
|
|
45
47
|
);
|
|
@@ -47,14 +49,14 @@ const createHeadingActions = (getView: () => EditorView) =>
|
|
|
47
49
|
|
|
48
50
|
const computeHeadingValue = (state: EditorToolbarState) => {
|
|
49
51
|
const blockType = state ? state.blockType : 'paragraph';
|
|
50
|
-
const
|
|
51
|
-
return
|
|
52
|
+
const heading = blockType && /heading(\d)/.exec(blockType);
|
|
53
|
+
return heading ? heading[1] : blockType === 'paragraph' || !blockType ? '0' : '';
|
|
52
54
|
};
|
|
53
55
|
|
|
54
56
|
export const createHeadings = (state: EditorToolbarState, getView: () => EditorView) => {
|
|
55
57
|
const headingValue = computeHeadingValue(state);
|
|
56
58
|
const headingGroupAction = createHeadingGroupAction(headingValue);
|
|
57
|
-
const headingActions = createHeadingActions(getView);
|
|
59
|
+
const headingActions = createHeadingActions(headingValue, getView);
|
|
58
60
|
return {
|
|
59
61
|
nodes: [headingGroupAction as NodeArg<any>, ...headingActions],
|
|
60
62
|
edges: [
|
|
@@ -8,7 +8,6 @@ import { useMemo } from 'react';
|
|
|
8
8
|
|
|
9
9
|
import { type Action } from '@dxos/app-graph';
|
|
10
10
|
import { type Live, live } from '@dxos/live-object';
|
|
11
|
-
import { type ThemedClassName } from '@dxos/react-ui';
|
|
12
11
|
import {
|
|
13
12
|
type ActionGraphProps,
|
|
14
13
|
type MenuActionProperties,
|
|
@@ -23,23 +22,12 @@ import type { EditorAction, Formatting } from '../../extensions';
|
|
|
23
22
|
import { translationKey } from '../../translations';
|
|
24
23
|
import { type EditorViewMode } from '../../types';
|
|
25
24
|
|
|
26
|
-
export type EditorToolbarState =
|
|
25
|
+
export type EditorToolbarState = { viewMode?: EditorViewMode } & Formatting;
|
|
27
26
|
|
|
28
|
-
export const useEditorToolbarState = (initialState: Partial<EditorToolbarState> = {}) => {
|
|
27
|
+
export const useEditorToolbarState = (initialState: Partial<EditorToolbarState> = {}): Live<EditorToolbarState> => {
|
|
29
28
|
return useMemo(() => live<EditorToolbarState>(initialState), []);
|
|
30
29
|
};
|
|
31
30
|
|
|
32
|
-
export type EditorToolbarFeatureFlags = Partial<{
|
|
33
|
-
headings: boolean;
|
|
34
|
-
formatting: boolean;
|
|
35
|
-
lists: boolean;
|
|
36
|
-
blocks: boolean;
|
|
37
|
-
search: boolean;
|
|
38
|
-
// TODO(wittjosiah): Factor out. Depend on plugin-level capabilities.
|
|
39
|
-
image: () => void;
|
|
40
|
-
viewMode: (mode: EditorViewMode) => void;
|
|
41
|
-
}>;
|
|
42
|
-
|
|
43
31
|
export type EditorToolbarActionGraphProps = {
|
|
44
32
|
state: Live<EditorToolbarState>;
|
|
45
33
|
getView: () => EditorView;
|
|
@@ -47,10 +35,6 @@ export type EditorToolbarActionGraphProps = {
|
|
|
47
35
|
customActions?: Rx.Rx<ActionGraphProps>;
|
|
48
36
|
};
|
|
49
37
|
|
|
50
|
-
export type EditorToolbarProps = ThemedClassName<
|
|
51
|
-
EditorToolbarActionGraphProps & EditorToolbarFeatureFlags & { attendableId?: string; role?: string }
|
|
52
|
-
>;
|
|
53
|
-
|
|
54
38
|
export type EditorToolbarItem = EditorAction | MenuItemGroup | MenuSeparator;
|
|
55
39
|
|
|
56
40
|
export const createEditorAction = (id: string, props: Partial<MenuActionProperties>, invoke: () => void) => {
|
package/src/components/index.ts
CHANGED
|
@@ -40,6 +40,7 @@ export type AutocompleteOptions = {
|
|
|
40
40
|
* Creates an autocomplete extension that shows inline suggestions.
|
|
41
41
|
* Pressing Tab will complete the suggestion.
|
|
42
42
|
*/
|
|
43
|
+
// TODO(burdon): Reconcile with typeahead.
|
|
43
44
|
export const autocomplete = ({ fireIfEmpty, onSubmit, onSuggest, onCancel }: AutocompleteOptions = {}): Extension => {
|
|
44
45
|
const suggest = ViewPlugin.fromClass(
|
|
45
46
|
class {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
export type CompoetionContext = { line: string };
|
|
6
|
+
|
|
7
|
+
export type CompletionOptions = {
|
|
8
|
+
default?: string;
|
|
9
|
+
minLength?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Util to match current line to a static list of completions.
|
|
14
|
+
*/
|
|
15
|
+
export const staticCompletion =
|
|
16
|
+
(completions: string[], options: CompletionOptions = {}) =>
|
|
17
|
+
({ line }: CompoetionContext) => {
|
|
18
|
+
if (line.length === 0 && options.default) {
|
|
19
|
+
return options.default;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const parts = line.split(/\s+/).filter(Boolean);
|
|
23
|
+
if (parts.length) {
|
|
24
|
+
const str = parts.at(-1)!;
|
|
25
|
+
if (str.length >= (options.minLength ?? 0)) {
|
|
26
|
+
for (const completion of completions) {
|
|
27
|
+
const match = matchCompletion(completion, str);
|
|
28
|
+
if (match) {
|
|
29
|
+
return match;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const matchCompletion = (completion: string, str: string, minLength = 0): string | undefined => {
|
|
37
|
+
if (
|
|
38
|
+
str.length >= minLength &&
|
|
39
|
+
completion.length > str.length &&
|
|
40
|
+
completion.startsWith(str)
|
|
41
|
+
// TODO(burdon): If case insensitive, need to replace existing chars.
|
|
42
|
+
// completion.toLowerCase().startsWith(str.toLowerCase())
|
|
43
|
+
) {
|
|
44
|
+
return completion.slice(str.length);
|
|
45
|
+
}
|
|
46
|
+
};
|