@prosekit/web 0.8.0-beta.0 → 0.8.0-beta.1
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/prosekit-web-autocomplete.d.ts +112 -90
- package/dist/prosekit-web-autocomplete.d.ts.map +1 -1
- package/dist/prosekit-web-autocomplete.js +292 -217
- package/dist/prosekit-web-autocomplete.js.map +1 -1
- package/dist/prosekit-web-block-handle.d.ts +95 -62
- package/dist/prosekit-web-block-handle.d.ts.map +1 -1
- package/dist/prosekit-web-block-handle.js +219 -114
- package/dist/prosekit-web-block-handle.js.map +1 -1
- package/dist/prosekit-web-drop-indicator.d.ts +13 -15
- package/dist/prosekit-web-drop-indicator.d.ts.map +1 -1
- package/dist/prosekit-web-drop-indicator.js +34 -30
- package/dist/prosekit-web-drop-indicator.js.map +1 -1
- package/dist/prosekit-web-inline-popover.d.ts +88 -54
- package/dist/prosekit-web-inline-popover.d.ts.map +1 -1
- package/dist/prosekit-web-inline-popover.js +129 -79
- package/dist/prosekit-web-inline-popover.js.map +1 -1
- package/dist/prosekit-web-menu.d.ts +13 -0
- package/dist/prosekit-web-menu.d.ts.map +1 -0
- package/dist/prosekit-web-menu.js +53 -0
- package/dist/prosekit-web-menu.js.map +1 -0
- package/dist/prosekit-web-popover.d.ts +7 -26
- package/dist/prosekit-web-popover.d.ts.map +1 -1
- package/dist/prosekit-web-popover.js +31 -29
- package/dist/prosekit-web-popover.js.map +1 -1
- package/dist/prosekit-web-resizable.d.ts +92 -51
- package/dist/prosekit-web-resizable.d.ts.map +1 -1
- package/dist/prosekit-web-resizable.js +139 -131
- package/dist/prosekit-web-resizable.js.map +1 -1
- package/dist/prosekit-web-table-handle.d.ts +166 -199
- package/dist/prosekit-web-table-handle.d.ts.map +1 -1
- package/dist/prosekit-web-table-handle.js +495 -496
- package/dist/prosekit-web-table-handle.js.map +1 -1
- package/dist/prosekit-web-tooltip.d.ts +7 -26
- package/dist/prosekit-web-tooltip.d.ts.map +1 -1
- package/dist/prosekit-web-tooltip.js +31 -29
- package/dist/prosekit-web-tooltip.js.map +1 -1
- package/dist/use-editor-extension.js +2 -2
- package/dist/use-editor-extension.js.map +1 -1
- package/dist/use-scrolling.js +17 -8
- package/dist/use-scrolling.js.map +1 -1
- package/package.json +28 -23
- package/src/components/autocomplete/autocomplete-empty.ts +45 -0
- package/src/components/autocomplete/autocomplete-item.ts +65 -0
- package/src/components/autocomplete/autocomplete-popup.ts +95 -0
- package/src/components/autocomplete/autocomplete-positioner.ts +98 -0
- package/src/components/autocomplete/autocomplete-root.ts +280 -0
- package/src/components/autocomplete/context.ts +16 -14
- package/src/components/autocomplete/index.ts +65 -0
- package/src/components/block-handle/block-handle-add.ts +71 -0
- package/src/components/block-handle/block-handle-draggable.ts +158 -0
- package/src/components/block-handle/block-handle-popup.ts +43 -0
- package/src/components/block-handle/block-handle-positioner.ts +89 -0
- package/src/components/block-handle/block-handle-root.ts +116 -0
- package/src/components/block-handle/context.ts +9 -18
- package/src/components/block-handle/hover-state.ts +16 -0
- package/src/components/block-handle/index.ts +59 -0
- package/src/components/block-handle/{block-handle-popover/pointer-move.ts → pointer-move.ts} +8 -7
- package/src/components/block-handle/{block-handle-draggable/set-drag-preview.ts → set-drag-preview.ts} +4 -4
- package/src/components/block-handle/use-hover-extension.ts +65 -0
- package/src/components/drop-indicator/drop-indicator.ts +128 -0
- package/src/components/drop-indicator/index.ts +18 -0
- package/src/components/inline-popover/index.ts +41 -0
- package/src/components/inline-popover/inline-popover-popup.ts +52 -0
- package/src/components/inline-popover/inline-popover-positioner.ts +98 -0
- package/src/components/inline-popover/inline-popover-root.ts +122 -0
- package/src/components/inline-popover/store.ts +6 -0
- package/src/components/menu/index.ts +92 -0
- package/src/components/popover/index.ts +53 -0
- package/src/components/resizable/{resizable-handle/calc-resize.ts → calc-resize.ts} +1 -1
- package/src/components/resizable/context.ts +3 -6
- package/src/components/resizable/index.ts +32 -0
- package/src/components/resizable/resizable-handle.ts +134 -0
- package/src/components/resizable/resizable-root.ts +184 -0
- package/src/components/table-handle/dnd.ts +16 -27
- package/src/components/table-handle/index.ts +125 -0
- package/src/components/table-handle/{table-handle-drag-preview/render-preview.ts → render-preview.ts} +5 -5
- package/src/components/table-handle/shared.ts +61 -0
- package/src/components/table-handle/store.ts +117 -0
- package/src/components/table-handle/table-handle-column-menu-root.ts +51 -0
- package/src/components/table-handle/table-handle-column-menu-trigger.ts +107 -0
- package/src/components/table-handle/table-handle-column-popup.ts +44 -0
- package/src/components/table-handle/table-handle-column-positioner.ts +67 -0
- package/src/components/table-handle/table-handle-drag-preview.ts +169 -0
- package/src/components/table-handle/table-handle-drop-indicator.ts +166 -0
- package/src/components/table-handle/table-handle-root.ts +103 -0
- package/src/components/table-handle/table-handle-row-menu-root.ts +51 -0
- package/src/components/table-handle/table-handle-row-menu-trigger.ts +107 -0
- package/src/components/table-handle/table-handle-row-popup.ts +42 -0
- package/src/components/table-handle/table-handle-row-positioner.ts +67 -0
- package/src/components/table-handle/use-drop.ts +74 -0
- package/src/components/table-handle/{hooks/use-empty-image.ts → use-empty-image.ts} +2 -3
- package/src/components/table-handle/utils.ts +0 -11
- package/src/components/tooltip/index.ts +52 -0
- package/src/hooks/use-editor-extension.ts +4 -4
- package/src/hooks/use-editor-focus-event.ts +4 -4
- package/src/hooks/use-editor-typing.ts +12 -16
- package/src/hooks/use-editor-update-event.ts +4 -4
- package/src/hooks/use-keymap.ts +4 -4
- package/src/hooks/use-scrolling.ts +11 -10
- package/src/hooks/use-selecting.ts +8 -15
- package/src/utils/event.ts +28 -0
- package/src/utils/lazy-signal.spec.ts +68 -0
- package/src/utils/lazy-signal.ts +17 -0
- package/src/utils/prefers-reduced-motion.ts +6 -0
- package/src/utils/prevent-default.ts +3 -0
- package/src/utils/use-html-element-at.ts +17 -0
- package/src/utils/use-no-focus.ts +7 -0
- package/dist/get-default-state.js +0 -11
- package/dist/get-default-state.js.map +0 -1
- package/src/components/autocomplete/autocomplete-empty/element.gen.ts +0 -18
- package/src/components/autocomplete/autocomplete-empty/setup.ts +0 -6
- package/src/components/autocomplete/autocomplete-empty/types.ts +0 -13
- package/src/components/autocomplete/autocomplete-item/element.gen.ts +0 -18
- package/src/components/autocomplete/autocomplete-item/setup.ts +0 -30
- package/src/components/autocomplete/autocomplete-item/types.ts +0 -25
- package/src/components/autocomplete/autocomplete-list/element.gen.ts +0 -18
- package/src/components/autocomplete/autocomplete-list/setup.ts +0 -125
- package/src/components/autocomplete/autocomplete-list/types.ts +0 -22
- package/src/components/autocomplete/autocomplete-popover/element.gen.ts +0 -18
- package/src/components/autocomplete/autocomplete-popover/setup.ts +0 -169
- package/src/components/autocomplete/autocomplete-popover/types.ts +0 -100
- package/src/components/autocomplete/index.gen.ts +0 -17
- package/src/components/block-handle/block-handle-add/element.gen.ts +0 -18
- package/src/components/block-handle/block-handle-add/setup.ts +0 -33
- package/src/components/block-handle/block-handle-add/types.ts +0 -23
- package/src/components/block-handle/block-handle-draggable/element.gen.ts +0 -18
- package/src/components/block-handle/block-handle-draggable/setup.ts +0 -113
- package/src/components/block-handle/block-handle-draggable/types.ts +0 -23
- package/src/components/block-handle/block-handle-popover/element.gen.ts +0 -18
- package/src/components/block-handle/block-handle-popover/setup.ts +0 -68
- package/src/components/block-handle/block-handle-popover/types.ts +0 -81
- package/src/components/block-handle/index.gen.ts +0 -13
- package/src/components/drop-indicator/drop-indicator/element.gen.ts +0 -18
- package/src/components/drop-indicator/drop-indicator/setup.ts +0 -75
- package/src/components/drop-indicator/drop-indicator/types.ts +0 -31
- package/src/components/drop-indicator/index.gen.ts +0 -5
- package/src/components/inline-popover/index.gen.ts +0 -5
- package/src/components/inline-popover/inline-popover/element.gen.ts +0 -18
- package/src/components/inline-popover/inline-popover/setup.ts +0 -111
- package/src/components/inline-popover/inline-popover/types.ts +0 -112
- package/src/components/popover/index.gen.ts +0 -13
- package/src/components/popover/popover-content/element.gen.ts +0 -18
- package/src/components/popover/popover-content/setup.ts +0 -1
- package/src/components/popover/popover-content/types.ts +0 -6
- package/src/components/popover/popover-root/element.gen.ts +0 -18
- package/src/components/popover/popover-root/setup.ts +0 -1
- package/src/components/popover/popover-root/types.ts +0 -6
- package/src/components/popover/popover-trigger/element.gen.ts +0 -18
- package/src/components/popover/popover-trigger/setup.ts +0 -1
- package/src/components/popover/popover-trigger/types.ts +0 -6
- package/src/components/resizable/index.gen.ts +0 -9
- package/src/components/resizable/resizable-handle/element.gen.ts +0 -18
- package/src/components/resizable/resizable-handle/setup.ts +0 -106
- package/src/components/resizable/resizable-handle/types.ts +0 -29
- package/src/components/resizable/resizable-root/element.gen.ts +0 -18
- package/src/components/resizable/resizable-root/setup.ts +0 -84
- package/src/components/resizable/resizable-root/types.ts +0 -59
- package/src/components/table-handle/context.ts +0 -43
- package/src/components/table-handle/hooks/use-drop.ts +0 -85
- package/src/components/table-handle/index.gen.ts +0 -37
- package/src/components/table-handle/table-handle-column-root/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-column-root/setup.ts +0 -60
- package/src/components/table-handle/table-handle-column-root/types.ts +0 -73
- package/src/components/table-handle/table-handle-column-trigger/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-column-trigger/setup.ts +0 -64
- package/src/components/table-handle/table-handle-column-trigger/types.ts +0 -20
- package/src/components/table-handle/table-handle-drag-preview/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-drag-preview/setup.ts +0 -57
- package/src/components/table-handle/table-handle-drag-preview/types.ts +0 -14
- package/src/components/table-handle/table-handle-drag-preview/updater.ts +0 -90
- package/src/components/table-handle/table-handle-drop-indicator/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-drop-indicator/setup.ts +0 -52
- package/src/components/table-handle/table-handle-drop-indicator/types.ts +0 -15
- package/src/components/table-handle/table-handle-drop-indicator/updater.ts +0 -96
- package/src/components/table-handle/table-handle-popover-content/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-popover-content/setup.ts +0 -83
- package/src/components/table-handle/table-handle-popover-content/types.ts +0 -32
- package/src/components/table-handle/table-handle-popover-item/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-popover-item/setup.ts +0 -17
- package/src/components/table-handle/table-handle-popover-item/types.ts +0 -16
- package/src/components/table-handle/table-handle-root/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-root/setup.ts +0 -86
- package/src/components/table-handle/table-handle-root/types.ts +0 -23
- package/src/components/table-handle/table-handle-row-root/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-row-root/setup.ts +0 -70
- package/src/components/table-handle/table-handle-row-root/types.ts +0 -68
- package/src/components/table-handle/table-handle-row-trigger/element.gen.ts +0 -18
- package/src/components/table-handle/table-handle-row-trigger/setup.ts +0 -63
- package/src/components/table-handle/table-handle-row-trigger/types.ts +0 -23
- package/src/components/tooltip/index.gen.ts +0 -13
- package/src/components/tooltip/tooltip-content/element.gen.ts +0 -18
- package/src/components/tooltip/tooltip-content/setup.ts +0 -1
- package/src/components/tooltip/tooltip-content/types.ts +0 -6
- package/src/components/tooltip/tooltip-root/element.gen.ts +0 -18
- package/src/components/tooltip/tooltip-root/setup.ts +0 -1
- package/src/components/tooltip/tooltip-root/types.ts +0 -6
- package/src/components/tooltip/tooltip-trigger/element.gen.ts +0 -18
- package/src/components/tooltip/tooltip-trigger/setup.ts +0 -1
- package/src/components/tooltip/tooltip-trigger/types.ts +0 -6
- package/src/hooks/use-first-rendering.ts +0 -15
- package/src/utils/get-default-state.spec.ts +0 -42
- package/src/utils/get-default-state.ts +0 -18
- /package/src/components/autocomplete/{autocomplete-popover/helpers.spec.ts → helpers.spec.ts} +0 -0
- /package/src/components/autocomplete/{autocomplete-popover/helpers.ts → helpers.ts} +0 -0
- /package/src/components/inline-popover/{inline-popover/virtual-selection-element.ts → virtual-selection-element.ts} +0 -0
- /package/src/components/resizable/{resizable-handle/calc-resize.spec.ts → calc-resize.spec.ts} +0 -0
- /package/src/components/table-handle/{table-handle-drop-indicator/calc-drag-over.ts → calc-drag-over.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scrolling.js","names":[],"sources":["../src/utils/assign-styles.ts","../src/hooks/use-scrolling.ts"],"sourcesContent":["import type { ConditionalPick } from 'type-fest'\n\n// Only include CSS properties whose value type is `string`\ntype StringStyleDeclaration = Partial<ConditionalPick<CSSStyleDeclaration, string>>\n\n/**\n * A type-safe version of `Object.assign` for `element.style`.\n */\nexport function assignStyles(\n element: HTMLElement | SVGElement | MathMLElement,\n styles: StringStyleDeclaration,\n): void {\n Object.assign(element.style, styles)\n}\n","import { createSignal, useEffect, type
|
|
1
|
+
{"version":3,"file":"use-scrolling.js","names":[],"sources":["../src/utils/assign-styles.ts","../src/hooks/use-scrolling.ts"],"sourcesContent":["import type { ConditionalPick } from 'type-fest'\n\n// Only include CSS properties whose value type is `string`\ntype StringStyleDeclaration = Partial<ConditionalPick<CSSStyleDeclaration, string>>\n\n/**\n * A type-safe version of `Object.assign` for `element.style`.\n */\nexport function assignStyles(\n element: HTMLElement | SVGElement | MathMLElement,\n styles: StringStyleDeclaration,\n): void {\n Object.assign(element.style, styles)\n}\n","import { createSignal, useEffect, type HostElement } from '@aria-ui/core'\nimport { getNearestOverflowAncestor } from '@aria-ui/utils'\n\nexport function useScrolling(host: HostElement): () => boolean {\n const scrolling = createSignal(false)\n\n useEffect(host, () => {\n const scrollableParent = getNearestOverflowAncestor(host)\n\n const handleScroll = () => {\n scrolling.set(true)\n }\n\n const handleMouseMove = () => {\n scrolling.set(false)\n }\n\n const abortController = new AbortController()\n const abortSignal = abortController.signal\n\n scrollableParent.addEventListener('scroll', handleScroll, { passive: true, signal: abortSignal })\n window.addEventListener('mousemove', handleMouseMove, { passive: true, signal: abortSignal })\n window.addEventListener('pointermove', handleMouseMove, { passive: true, signal: abortSignal })\n\n return () => {\n abortController.abort()\n }\n })\n\n return scrolling.get\n}\n"],"mappings":";;;;;;AAQA,SAAgB,aACd,SACA,QACM;AACN,QAAO,OAAO,QAAQ,OAAO,OAAO;;;;ACTtC,SAAgB,aAAa,MAAkC;CAC7D,MAAM,YAAY,aAAa,MAAM;AAErC,WAAU,YAAY;EACpB,MAAM,mBAAmB,2BAA2B,KAAK;EAEzD,MAAM,qBAAqB;AACzB,aAAU,IAAI,KAAK;;EAGrB,MAAM,wBAAwB;AAC5B,aAAU,IAAI,MAAM;;EAGtB,MAAM,kBAAkB,IAAI,iBAAiB;EAC7C,MAAM,cAAc,gBAAgB;AAEpC,mBAAiB,iBAAiB,UAAU,cAAc;GAAE,SAAS;GAAM,QAAQ;GAAa,CAAC;AACjG,SAAO,iBAAiB,aAAa,iBAAiB;GAAE,SAAS;GAAM,QAAQ;GAAa,CAAC;AAC7F,SAAO,iBAAiB,eAAe,iBAAiB;GAAE,SAAS;GAAM,QAAQ;GAAa,CAAC;AAE/F,eAAa;AACX,mBAAgB,OAAO;;GAEzB;AAEF,QAAO,UAAU"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosekit/web",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.8.0-beta.
|
|
4
|
+
"version": "0.8.0-beta.1",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "A collection of web components for ProseKit",
|
|
7
7
|
"author": {
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
"types": "./dist/prosekit-web-inline-popover.d.ts",
|
|
47
47
|
"default": "./dist/prosekit-web-inline-popover.js"
|
|
48
48
|
},
|
|
49
|
+
"./menu": {
|
|
50
|
+
"types": "./dist/prosekit-web-menu.d.ts",
|
|
51
|
+
"default": "./dist/prosekit-web-menu.js"
|
|
52
|
+
},
|
|
49
53
|
"./popover": {
|
|
50
54
|
"types": "./dist/prosekit-web-popover.d.ts",
|
|
51
55
|
"default": "./dist/prosekit-web-popover.js"
|
|
@@ -68,28 +72,24 @@
|
|
|
68
72
|
"src"
|
|
69
73
|
],
|
|
70
74
|
"dependencies": {
|
|
71
|
-
"@aria-ui/core": "^0.0
|
|
72
|
-
"@aria-ui/
|
|
73
|
-
"@aria-ui/
|
|
74
|
-
"@aria-ui/overlay": "^0.0.25",
|
|
75
|
-
"@aria-ui/popover": "^0.0.28",
|
|
76
|
-
"@aria-ui/presence": "^0.0.20",
|
|
77
|
-
"@aria-ui/tooltip": "^0.0.30",
|
|
75
|
+
"@aria-ui/core": "^0.1.0",
|
|
76
|
+
"@aria-ui/elements": "^0.1.1",
|
|
77
|
+
"@aria-ui/utils": "^0.1.0",
|
|
78
78
|
"@floating-ui/dom": "^1.7.6",
|
|
79
79
|
"@ocavue/utils": "^1.6.0",
|
|
80
|
-
"@zag-js/dom-query": "^1.37.0",
|
|
81
80
|
"prosemirror-tables": "^1.8.5",
|
|
82
|
-
"@prosekit/extensions": "^0.16.0-beta.0",
|
|
83
81
|
"@prosekit/core": "^0.12.0-beta.0",
|
|
84
|
-
"@prosekit/pm": "^0.1.15"
|
|
82
|
+
"@prosekit/pm": "^0.1.15",
|
|
83
|
+
"@prosekit/extensions": "^0.16.0-beta.0"
|
|
85
84
|
},
|
|
86
85
|
"devDependencies": {
|
|
87
|
-
"
|
|
86
|
+
"@aria-ui/cli": "^0.1.0",
|
|
87
|
+
"tsdown": "^0.21.7",
|
|
88
88
|
"type-fest": "^5.5.0",
|
|
89
89
|
"typescript": "~5.9.3",
|
|
90
|
-
"vitest": "^4.1.
|
|
91
|
-
"@prosekit/config-tsdown": "0.0.0",
|
|
90
|
+
"vitest": "^4.1.4",
|
|
92
91
|
"@prosekit/config-ts": "0.0.0",
|
|
92
|
+
"@prosekit/config-tsdown": "0.0.0",
|
|
93
93
|
"@prosekit/config-vitest": "0.0.0"
|
|
94
94
|
},
|
|
95
95
|
"publishConfig": {
|
|
@@ -98,19 +98,21 @@
|
|
|
98
98
|
"dev": {
|
|
99
99
|
"entry": {
|
|
100
100
|
"prosekit-web": "./src/index.ts",
|
|
101
|
-
"prosekit-web-autocomplete": "./src/components/autocomplete/index.
|
|
102
|
-
"prosekit-web-block-handle": "./src/components/block-handle/index.
|
|
103
|
-
"prosekit-web-drop-indicator": "./src/components/drop-indicator/index.
|
|
104
|
-
"prosekit-web-inline-popover": "./src/components/inline-popover/index.
|
|
105
|
-
"prosekit-web-
|
|
106
|
-
"prosekit-web-
|
|
107
|
-
"prosekit-web-
|
|
108
|
-
"prosekit-web-
|
|
101
|
+
"prosekit-web-autocomplete": "./src/components/autocomplete/index.ts",
|
|
102
|
+
"prosekit-web-block-handle": "./src/components/block-handle/index.ts",
|
|
103
|
+
"prosekit-web-drop-indicator": "./src/components/drop-indicator/index.ts",
|
|
104
|
+
"prosekit-web-inline-popover": "./src/components/inline-popover/index.ts",
|
|
105
|
+
"prosekit-web-menu": "./src/components/menu/index.ts",
|
|
106
|
+
"prosekit-web-popover": "./src/components/popover/index.ts",
|
|
107
|
+
"prosekit-web-resizable": "./src/components/resizable/index.ts",
|
|
108
|
+
"prosekit-web-table-handle": "./src/components/table-handle/index.ts",
|
|
109
|
+
"prosekit-web-tooltip": "./src/components/tooltip/index.ts"
|
|
109
110
|
}
|
|
110
111
|
},
|
|
111
112
|
"scripts": {
|
|
112
113
|
"build:tsc": "tsc -b tsconfig.json",
|
|
113
|
-
"build:tsdown": "tsdown"
|
|
114
|
+
"build:tsdown": "tsdown",
|
|
115
|
+
"build:aria-ui": "node build.mjs"
|
|
114
116
|
},
|
|
115
117
|
"types": "./dist/prosekit-web.d.ts",
|
|
116
118
|
"typesVersions": {
|
|
@@ -130,6 +132,9 @@
|
|
|
130
132
|
"inline-popover": [
|
|
131
133
|
"./dist/prosekit-web-inline-popover.d.ts"
|
|
132
134
|
],
|
|
135
|
+
"menu": [
|
|
136
|
+
"./dist/prosekit-web-menu.d.ts"
|
|
137
|
+
],
|
|
133
138
|
"popover": [
|
|
134
139
|
"./dist/prosekit-web-popover.d.ts"
|
|
135
140
|
],
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCustomElement,
|
|
3
|
+
defineProps,
|
|
4
|
+
registerCustomElement,
|
|
5
|
+
type HostElement,
|
|
6
|
+
type HostElementConstructor,
|
|
7
|
+
type PropsDeclaration,
|
|
8
|
+
type State,
|
|
9
|
+
} from '@aria-ui/core'
|
|
10
|
+
import { setupListboxEmpty, type ListboxEmptyProps } from '@aria-ui/elements/listbox'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export interface AutocompleteEmptyProps extends ListboxEmptyProps {}
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
export const AutocompleteEmptyPropsDeclaration: PropsDeclaration<AutocompleteEmptyProps> = /* @__PURE__ */ defineProps<
|
|
19
|
+
AutocompleteEmptyProps
|
|
20
|
+
>({})
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export function setupAutocompleteEmpty(
|
|
26
|
+
host: HostElement,
|
|
27
|
+
props: State<AutocompleteEmptyProps>,
|
|
28
|
+
): void {
|
|
29
|
+
setupListboxEmpty(host, props)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const AutocompleteEmptyElementBase: HostElementConstructor<AutocompleteEmptyProps> = defineCustomElement(
|
|
33
|
+
setupAutocompleteEmpty,
|
|
34
|
+
AutocompleteEmptyPropsDeclaration,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export class AutocompleteEmptyElement extends AutocompleteEmptyElementBase {}
|
|
41
|
+
|
|
42
|
+
/** @internal */
|
|
43
|
+
export function registerAutocompleteEmptyElement(): void {
|
|
44
|
+
registerCustomElement('prosekit-autocomplete-empty', AutocompleteEmptyElement)
|
|
45
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCustomElement,
|
|
3
|
+
defineProps,
|
|
4
|
+
registerCustomElement,
|
|
5
|
+
useEventListener,
|
|
6
|
+
type HostElement,
|
|
7
|
+
type HostElementConstructor,
|
|
8
|
+
type PropsDeclaration,
|
|
9
|
+
type State,
|
|
10
|
+
} from '@aria-ui/core'
|
|
11
|
+
import { SelectEvent, setupListboxItem, type ListboxItemEvents, type ListboxItemProps } from '@aria-ui/elements/listbox'
|
|
12
|
+
|
|
13
|
+
import { preventDefault } from '../../utils/prevent-default.ts'
|
|
14
|
+
|
|
15
|
+
export { SelectEvent }
|
|
16
|
+
|
|
17
|
+
export interface AutocompleteItemProps extends ListboxItemProps {
|
|
18
|
+
/**
|
|
19
|
+
* The value of the item, which will be matched against the query.
|
|
20
|
+
*
|
|
21
|
+
* If not provided, the value is the item's text content.
|
|
22
|
+
*
|
|
23
|
+
* @default ""
|
|
24
|
+
*/
|
|
25
|
+
value: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** @internal */
|
|
29
|
+
export const AutocompleteItemPropsDeclaration: PropsDeclaration<AutocompleteItemProps> = /* @__PURE__ */ defineProps<AutocompleteItemProps>(
|
|
30
|
+
{
|
|
31
|
+
value: { default: '', attribute: 'value', type: 'string' },
|
|
32
|
+
disabled: { default: false, attribute: 'disabled', type: 'boolean' },
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
export interface AutocompleteItemEvents extends ListboxItemEvents {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
export function setupAutocompleteItem(
|
|
42
|
+
host: HostElement,
|
|
43
|
+
props: State<AutocompleteItemProps>,
|
|
44
|
+
): void {
|
|
45
|
+
setupListboxItem(host, props)
|
|
46
|
+
|
|
47
|
+
// Prevent the editor from losing focus
|
|
48
|
+
useEventListener(host, 'pointerdown', preventDefault)
|
|
49
|
+
useEventListener(host, 'mousedown', preventDefault)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const AutocompleteItemElementBase: HostElementConstructor<AutocompleteItemProps> = defineCustomElement(
|
|
53
|
+
setupAutocompleteItem,
|
|
54
|
+
AutocompleteItemPropsDeclaration,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
export class AutocompleteItemElement extends AutocompleteItemElementBase {}
|
|
61
|
+
|
|
62
|
+
/** @internal */
|
|
63
|
+
export function registerAutocompleteItemElement(): void {
|
|
64
|
+
registerCustomElement('prosekit-autocomplete-item', AutocompleteItemElement)
|
|
65
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
defineCustomElement,
|
|
4
|
+
defineProps,
|
|
5
|
+
registerCustomElement,
|
|
6
|
+
type HostElement,
|
|
7
|
+
type HostElementConstructor,
|
|
8
|
+
type PropsDeclaration,
|
|
9
|
+
type Signal,
|
|
10
|
+
type State,
|
|
11
|
+
} from '@aria-ui/core'
|
|
12
|
+
import {
|
|
13
|
+
defaultItemFilter,
|
|
14
|
+
setupListboxRoot,
|
|
15
|
+
type ItemFilter,
|
|
16
|
+
type ListboxRootEvents,
|
|
17
|
+
type ListboxRootProps,
|
|
18
|
+
} from '@aria-ui/elements/listbox'
|
|
19
|
+
import { OverlayPopupPropsDeclaration, setupOverlayPopup, type OverlayPopupProps } from '@aria-ui/elements/overlay'
|
|
20
|
+
|
|
21
|
+
import { createLazySignal } from '../../utils/lazy-signal.ts'
|
|
22
|
+
import { useNoFocus } from '../../utils/use-no-focus.ts'
|
|
23
|
+
|
|
24
|
+
import { autocompleteStoreContext } from './context.ts'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export interface AutocompletePopupProps extends OverlayPopupProps {}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export interface AutocompletePopupEvents extends ListboxRootEvents {}
|
|
35
|
+
|
|
36
|
+
/** @internal */
|
|
37
|
+
export const AutocompletePopupPropsDeclaration: PropsDeclaration<AutocompletePopupProps> = /* @__PURE__ */ defineProps<
|
|
38
|
+
AutocompletePopupProps
|
|
39
|
+
>(OverlayPopupPropsDeclaration)
|
|
40
|
+
|
|
41
|
+
/** @internal */
|
|
42
|
+
export function setupAutocompletePopup(
|
|
43
|
+
host: HostElement,
|
|
44
|
+
_props: State<AutocompletePopupProps>,
|
|
45
|
+
): void {
|
|
46
|
+
const getStore = autocompleteStoreContext.consume(host)
|
|
47
|
+
const getOverlayStore = () => getStore()?.overlayStore
|
|
48
|
+
|
|
49
|
+
setupOverlayPopup(host, getOverlayStore)
|
|
50
|
+
|
|
51
|
+
const query = createLazySignal<string>(() => getStore()?.query, ' ')
|
|
52
|
+
const eventTarget = createLazySignal<EventTarget | null>(() => getStore()?.eventTarget, null)
|
|
53
|
+
const filter = createLazySignal<ItemFilter | null>(() => getStore()?.filter, defaultItemFilter)
|
|
54
|
+
const getDisabled = () => (!(getOverlayStore()?.getIsOpen?.()))
|
|
55
|
+
const disabled: Signal<boolean> = { get: getDisabled, set: () => {} }
|
|
56
|
+
const listboxProps = createPopupListboxProps(filter, query, eventTarget, disabled)
|
|
57
|
+
|
|
58
|
+
setupListboxRoot(host, listboxProps)
|
|
59
|
+
useNoFocus(host)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function createPopupListboxProps(
|
|
63
|
+
filter: Signal<ItemFilter | null>,
|
|
64
|
+
query: Signal<string>,
|
|
65
|
+
eventTarget: Signal<EventTarget | null>,
|
|
66
|
+
disabled: Signal<boolean>,
|
|
67
|
+
): State<ListboxRootProps> {
|
|
68
|
+
return {
|
|
69
|
+
value: createSignal(''),
|
|
70
|
+
values: createSignal<string[]>([]),
|
|
71
|
+
multiple: createSignal(false),
|
|
72
|
+
disabled,
|
|
73
|
+
orientation: createSignal<'vertical' | 'horizontal'>('vertical'),
|
|
74
|
+
loop: createSignal(false),
|
|
75
|
+
autoHighlight: createSignal(true),
|
|
76
|
+
query,
|
|
77
|
+
eventTarget,
|
|
78
|
+
filter,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const AutocompletePopupElementBase: HostElementConstructor<AutocompletePopupProps> = defineCustomElement(
|
|
83
|
+
setupAutocompletePopup,
|
|
84
|
+
AutocompletePopupPropsDeclaration,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @public
|
|
89
|
+
*/
|
|
90
|
+
export class AutocompletePopupElement extends AutocompletePopupElementBase {}
|
|
91
|
+
|
|
92
|
+
/** @internal */
|
|
93
|
+
export function registerAutocompletePopupElement(): void {
|
|
94
|
+
registerCustomElement('prosekit-autocomplete-popup', AutocompletePopupElement)
|
|
95
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCustomElement,
|
|
3
|
+
defineProps,
|
|
4
|
+
registerCustomElement,
|
|
5
|
+
type HostElement,
|
|
6
|
+
type HostElementConstructor,
|
|
7
|
+
type PropsDeclaration,
|
|
8
|
+
type State,
|
|
9
|
+
} from '@aria-ui/core'
|
|
10
|
+
import { OverlayPositionerPropsDeclaration, setupOverlayPositioner, type OverlayPositionerProps } from '@aria-ui/elements/overlay'
|
|
11
|
+
|
|
12
|
+
import { autocompleteStoreContext } from './context.ts'
|
|
13
|
+
|
|
14
|
+
const body = typeof document !== 'undefined' && document.querySelector('body')
|
|
15
|
+
const defaultBoundary = body || 'clippingAncestors'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export interface AutocompletePositionerProps extends OverlayPositionerProps {
|
|
21
|
+
/**
|
|
22
|
+
* The placement of the popover, relative to the text cursor.
|
|
23
|
+
*
|
|
24
|
+
* @default "bottom-start"
|
|
25
|
+
*/
|
|
26
|
+
placement: OverlayPositionerProps['placement']
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The distance between the popover and the hovered block.
|
|
30
|
+
*
|
|
31
|
+
* @default 4
|
|
32
|
+
*/
|
|
33
|
+
offset: OverlayPositionerProps['offset']
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @default true
|
|
37
|
+
*/
|
|
38
|
+
inline: OverlayPositionerProps['inline']
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
hoist: OverlayPositionerProps['hoist']
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
fitViewport: OverlayPositionerProps['fitViewport']
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @default "The body element"
|
|
52
|
+
*/
|
|
53
|
+
boundary: OverlayPositionerProps['boundary']
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @default 8
|
|
57
|
+
*/
|
|
58
|
+
overflowPadding: OverlayPositionerProps['overflowPadding']
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @internal */
|
|
62
|
+
export const AutocompletePositionerPropsDeclaration: PropsDeclaration<AutocompletePositionerProps> = /* @__PURE__ */ defineProps<
|
|
63
|
+
AutocompletePositionerProps
|
|
64
|
+
>({
|
|
65
|
+
...OverlayPositionerPropsDeclaration,
|
|
66
|
+
placement: { default: 'bottom-start', attribute: 'placement', type: 'string' },
|
|
67
|
+
offset: { default: 4, attribute: false, type: 'json' },
|
|
68
|
+
inline: { default: true, attribute: 'inline', type: 'boolean' },
|
|
69
|
+
hoist: { default: true, attribute: 'hoist', type: 'boolean' },
|
|
70
|
+
fitViewport: { default: true, attribute: 'fit-viewport', type: 'boolean' },
|
|
71
|
+
boundary: { default: defaultBoundary, attribute: false, type: 'json' },
|
|
72
|
+
overflowPadding: { default: 8, attribute: 'overflow-padding', type: 'number' },
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
/** @internal */
|
|
76
|
+
export function setupAutocompletePositioner(
|
|
77
|
+
host: HostElement,
|
|
78
|
+
props: State<AutocompletePositionerProps>,
|
|
79
|
+
): void {
|
|
80
|
+
const getStore = autocompleteStoreContext.consume(host)
|
|
81
|
+
const getOverlayStore = () => getStore()?.overlayStore
|
|
82
|
+
setupOverlayPositioner(host, props as unknown as State<OverlayPositionerProps>, getOverlayStore)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const AutocompletePositionerElementBase: HostElementConstructor<AutocompletePositionerProps> = defineCustomElement(
|
|
86
|
+
setupAutocompletePositioner,
|
|
87
|
+
AutocompletePositionerPropsDeclaration,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @public
|
|
92
|
+
*/
|
|
93
|
+
export class AutocompletePositionerElement extends AutocompletePositionerElementBase {}
|
|
94
|
+
|
|
95
|
+
/** @internal */
|
|
96
|
+
export function registerAutocompletePositionerElement(): void {
|
|
97
|
+
registerCustomElement('prosekit-autocomplete-positioner', AutocompletePositionerElement)
|
|
98
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
defineCustomElement,
|
|
4
|
+
defineProps,
|
|
5
|
+
registerCustomElement,
|
|
6
|
+
useEffect,
|
|
7
|
+
useEventListener,
|
|
8
|
+
type HostElement,
|
|
9
|
+
type HostElementConstructor,
|
|
10
|
+
type PropsDeclaration,
|
|
11
|
+
type Signal,
|
|
12
|
+
type State,
|
|
13
|
+
} from '@aria-ui/core'
|
|
14
|
+
import { defaultItemFilter, type ItemFilter, type ListboxRootEvents } from '@aria-ui/elements/listbox'
|
|
15
|
+
import { createOverlayStore, OpenChangeEvent, type OverlayStore } from '@aria-ui/elements/overlay'
|
|
16
|
+
import { defineDOMEventHandler, defineKeymap, withPriority, type Editor, type Extension, type Priority } from '@prosekit/core'
|
|
17
|
+
import { AutocompleteRule, defineAutocomplete, type MatchHandler } from '@prosekit/extensions/autocomplete'
|
|
18
|
+
|
|
19
|
+
import { useEditorExtension } from '../../hooks/use-editor-extension.ts'
|
|
20
|
+
import { KeyboardEventTarget } from '../../utils/event.ts'
|
|
21
|
+
import { getSafeEditorView } from '../../utils/get-safe-editor-view.ts'
|
|
22
|
+
|
|
23
|
+
import { autocompleteStoreContext, type AutocompleteStore } from './context.ts'
|
|
24
|
+
import { defaultQueryBuilder } from './helpers.ts'
|
|
25
|
+
|
|
26
|
+
export { OpenChangeEvent }
|
|
27
|
+
|
|
28
|
+
export interface AutocompleteRootProps {
|
|
29
|
+
/**
|
|
30
|
+
* The ProseKit editor instance.
|
|
31
|
+
*
|
|
32
|
+
* @default null
|
|
33
|
+
* @hidden
|
|
34
|
+
*/
|
|
35
|
+
editor: Editor | null
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The regular expression to match the query text to autocomplete.
|
|
39
|
+
*
|
|
40
|
+
* @default null
|
|
41
|
+
*/
|
|
42
|
+
regex: RegExp | null
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The filter function to determine if an item should be shown in the
|
|
46
|
+
* listbox.
|
|
47
|
+
*
|
|
48
|
+
* @default defaultItemFilter
|
|
49
|
+
*/
|
|
50
|
+
filter: ItemFilter | null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** @internal */
|
|
54
|
+
export const AutocompleteRootPropsDeclaration: PropsDeclaration<AutocompleteRootProps> = /* @__PURE__ */ defineProps<
|
|
55
|
+
AutocompleteRootProps
|
|
56
|
+
>({
|
|
57
|
+
editor: { default: null, attribute: false, type: 'json' },
|
|
58
|
+
regex: { default: null, attribute: false, type: 'json' },
|
|
59
|
+
filter: { default: defaultItemFilter, attribute: false, type: 'json' },
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export class QueryChangeEvent extends Event {
|
|
66
|
+
/**
|
|
67
|
+
* The current query string.
|
|
68
|
+
*/
|
|
69
|
+
readonly detail: string
|
|
70
|
+
|
|
71
|
+
constructor(query: string) {
|
|
72
|
+
super('queryChange', { bubbles: true })
|
|
73
|
+
this.detail = query
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
export interface AutocompleteRootEvents extends ListboxRootEvents {
|
|
81
|
+
/**
|
|
82
|
+
* Fired when the open state changes.
|
|
83
|
+
*/
|
|
84
|
+
openChange: OpenChangeEvent
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Fired when the query changes.
|
|
88
|
+
*/
|
|
89
|
+
queryChange: QueryChangeEvent
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface RuleHandlers {
|
|
93
|
+
submit?: VoidFunction
|
|
94
|
+
dismiss?: VoidFunction
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
interface AutocompleteRuleDeps {
|
|
98
|
+
reference: Signal<Element | undefined>
|
|
99
|
+
handlers: RuleHandlers
|
|
100
|
+
setQuery: (next: string) => void
|
|
101
|
+
requestOpenChange: (open: boolean) => void
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
export function setupAutocompleteRoot(
|
|
108
|
+
host: HostElement,
|
|
109
|
+
props: State<AutocompleteRootProps>,
|
|
110
|
+
): void {
|
|
111
|
+
const getEditor = props.editor.get
|
|
112
|
+
|
|
113
|
+
const reference = createSignal<Element | undefined>(undefined)
|
|
114
|
+
const open = createSignal(false)
|
|
115
|
+
const query = createSignal('')
|
|
116
|
+
const keyboardTarget = new KeyboardEventTarget()
|
|
117
|
+
const eventTarget = createSignal<EventTarget | null>(keyboardTarget)
|
|
118
|
+
const handlers: RuleHandlers = {}
|
|
119
|
+
|
|
120
|
+
// Create overlay store for positioning. The open state is managed by the
|
|
121
|
+
// overlay store via requestOpenChange(), which dispatches OpenChangeEvent and
|
|
122
|
+
// updates the open signal.
|
|
123
|
+
const overlayStore: OverlayStore = createOverlayStore(
|
|
124
|
+
open.get,
|
|
125
|
+
open.set,
|
|
126
|
+
() => false,
|
|
127
|
+
() => false,
|
|
128
|
+
(event) => host.dispatchEvent(event),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
useEffect(host, () => {
|
|
132
|
+
overlayStore.setAnchorElement(reference.get())
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const autocompleteStore: AutocompleteStore = {
|
|
136
|
+
overlayStore,
|
|
137
|
+
query,
|
|
138
|
+
eventTarget,
|
|
139
|
+
filter: props.filter,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
autocompleteStoreContext.provide(host, autocompleteStore)
|
|
143
|
+
|
|
144
|
+
useEventListener(host, 'valueChange', () => {
|
|
145
|
+
handlers.submit?.()
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
useKeyboardBridge(host, getEditor, open.get, keyboardTarget)
|
|
149
|
+
|
|
150
|
+
useEscapeKeydown(host, getEditor, () => {
|
|
151
|
+
if (!open.get() || !handlers.dismiss) return false
|
|
152
|
+
handlers.dismiss()
|
|
153
|
+
return true
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
const setQuery = (next: string): void => {
|
|
157
|
+
if (query.get() === next) return
|
|
158
|
+
query.set(next)
|
|
159
|
+
host.dispatchEvent(new QueryChangeEvent(next))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
useAutocompleteExtension(host, getEditor, props.regex.get, {
|
|
163
|
+
reference,
|
|
164
|
+
handlers,
|
|
165
|
+
setQuery,
|
|
166
|
+
requestOpenChange: (open) => overlayStore.requestOpenChange(open),
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const EVENT_KEYS = [
|
|
171
|
+
'ArrowDown',
|
|
172
|
+
'ArrowRight',
|
|
173
|
+
'ArrowUp',
|
|
174
|
+
'ArrowLeft',
|
|
175
|
+
'Home',
|
|
176
|
+
'End',
|
|
177
|
+
'Enter',
|
|
178
|
+
] as const
|
|
179
|
+
|
|
180
|
+
function useKeyboardBridge(
|
|
181
|
+
host: HostElement,
|
|
182
|
+
getEditor: () => Editor | null,
|
|
183
|
+
getOpen: () => boolean,
|
|
184
|
+
target: EventTarget,
|
|
185
|
+
): void {
|
|
186
|
+
const extension: Extension = defineDOMEventHandler('keydown', (view, event): boolean => {
|
|
187
|
+
if (
|
|
188
|
+
view.composing
|
|
189
|
+
|| event.defaultPrevented
|
|
190
|
+
|| !getOpen()
|
|
191
|
+
|| !EVENT_KEYS.includes(event.key as (typeof EVENT_KEYS)[number])
|
|
192
|
+
) {
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
target.dispatchEvent(event)
|
|
196
|
+
return event.defaultPrevented
|
|
197
|
+
})
|
|
198
|
+
useEditorExtension(host, getEditor, withPriority(extension, 4 satisfies typeof Priority.highest))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function useAutocompleteExtension(
|
|
202
|
+
host: HostElement,
|
|
203
|
+
getEditor: () => Editor | null,
|
|
204
|
+
getRegex: () => RegExp | null,
|
|
205
|
+
deps: AutocompleteRuleDeps,
|
|
206
|
+
) {
|
|
207
|
+
useEffect(host, () => {
|
|
208
|
+
const editor = getEditor()
|
|
209
|
+
const regex = getRegex()
|
|
210
|
+
|
|
211
|
+
if (!editor || !regex) {
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const rule = createAutocompleteRule(editor, regex, deps)
|
|
216
|
+
const extension = defineAutocomplete(rule)
|
|
217
|
+
return editor.use(extension)
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function createAutocompleteRule(
|
|
222
|
+
editor: Editor,
|
|
223
|
+
regex: RegExp,
|
|
224
|
+
deps: AutocompleteRuleDeps,
|
|
225
|
+
) {
|
|
226
|
+
const { reference, handlers, setQuery, requestOpenChange } = deps
|
|
227
|
+
|
|
228
|
+
const handleEnter: MatchHandler = (options) => {
|
|
229
|
+
const view = getSafeEditorView(editor)
|
|
230
|
+
const span = view?.dom.querySelector('.prosekit-autocomplete-match')
|
|
231
|
+
|
|
232
|
+
if (span) {
|
|
233
|
+
reference.set(span)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
handlers.submit = options.deleteMatch
|
|
237
|
+
handlers.dismiss = options.ignoreMatch
|
|
238
|
+
setQuery(defaultQueryBuilder(options.match))
|
|
239
|
+
requestOpenChange(true)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const handleLeave = () => {
|
|
243
|
+
reference.set(undefined)
|
|
244
|
+
setQuery('')
|
|
245
|
+
handlers.submit = undefined
|
|
246
|
+
handlers.dismiss = undefined
|
|
247
|
+
requestOpenChange(false)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return new AutocompleteRule({
|
|
251
|
+
regex,
|
|
252
|
+
onEnter: handleEnter,
|
|
253
|
+
onLeave: handleLeave,
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function useEscapeKeydown(
|
|
258
|
+
host: HostElement,
|
|
259
|
+
getEditor: () => Editor | null,
|
|
260
|
+
handler: () => boolean,
|
|
261
|
+
): void {
|
|
262
|
+
const keymap = { Escape: handler }
|
|
263
|
+
const extension = withPriority(defineKeymap(keymap), 4 satisfies typeof Priority.highest)
|
|
264
|
+
useEditorExtension(host, getEditor, extension)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const AutocompleteRootElementBase: HostElementConstructor<AutocompleteRootProps> = defineCustomElement(
|
|
268
|
+
setupAutocompleteRoot,
|
|
269
|
+
AutocompleteRootPropsDeclaration,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* @public
|
|
274
|
+
*/
|
|
275
|
+
export class AutocompleteRootElement extends AutocompleteRootElementBase {}
|
|
276
|
+
|
|
277
|
+
/** @internal */
|
|
278
|
+
export function registerAutocompleteRootElement(): void {
|
|
279
|
+
registerCustomElement('prosekit-autocomplete-root', AutocompleteRootElement)
|
|
280
|
+
}
|