@prosekit/web 0.7.13 → 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.
Files changed (207) hide show
  1. package/dist/prosekit-web-autocomplete.d.ts +112 -90
  2. package/dist/prosekit-web-autocomplete.d.ts.map +1 -1
  3. package/dist/prosekit-web-autocomplete.js +292 -217
  4. package/dist/prosekit-web-autocomplete.js.map +1 -1
  5. package/dist/prosekit-web-block-handle.d.ts +95 -62
  6. package/dist/prosekit-web-block-handle.d.ts.map +1 -1
  7. package/dist/prosekit-web-block-handle.js +219 -114
  8. package/dist/prosekit-web-block-handle.js.map +1 -1
  9. package/dist/prosekit-web-drop-indicator.d.ts +13 -15
  10. package/dist/prosekit-web-drop-indicator.d.ts.map +1 -1
  11. package/dist/prosekit-web-drop-indicator.js +34 -30
  12. package/dist/prosekit-web-drop-indicator.js.map +1 -1
  13. package/dist/prosekit-web-inline-popover.d.ts +88 -54
  14. package/dist/prosekit-web-inline-popover.d.ts.map +1 -1
  15. package/dist/prosekit-web-inline-popover.js +129 -79
  16. package/dist/prosekit-web-inline-popover.js.map +1 -1
  17. package/dist/prosekit-web-menu.d.ts +13 -0
  18. package/dist/prosekit-web-menu.d.ts.map +1 -0
  19. package/dist/prosekit-web-menu.js +53 -0
  20. package/dist/prosekit-web-menu.js.map +1 -0
  21. package/dist/prosekit-web-popover.d.ts +7 -26
  22. package/dist/prosekit-web-popover.d.ts.map +1 -1
  23. package/dist/prosekit-web-popover.js +31 -29
  24. package/dist/prosekit-web-popover.js.map +1 -1
  25. package/dist/prosekit-web-resizable.d.ts +92 -51
  26. package/dist/prosekit-web-resizable.d.ts.map +1 -1
  27. package/dist/prosekit-web-resizable.js +139 -131
  28. package/dist/prosekit-web-resizable.js.map +1 -1
  29. package/dist/prosekit-web-table-handle.d.ts +166 -199
  30. package/dist/prosekit-web-table-handle.d.ts.map +1 -1
  31. package/dist/prosekit-web-table-handle.js +495 -496
  32. package/dist/prosekit-web-table-handle.js.map +1 -1
  33. package/dist/prosekit-web-tooltip.d.ts +7 -26
  34. package/dist/prosekit-web-tooltip.d.ts.map +1 -1
  35. package/dist/prosekit-web-tooltip.js +31 -29
  36. package/dist/prosekit-web-tooltip.js.map +1 -1
  37. package/dist/use-editor-extension.js +2 -2
  38. package/dist/use-editor-extension.js.map +1 -1
  39. package/dist/use-scrolling.js +17 -8
  40. package/dist/use-scrolling.js.map +1 -1
  41. package/package.json +30 -25
  42. package/src/components/autocomplete/autocomplete-empty.ts +45 -0
  43. package/src/components/autocomplete/autocomplete-item.ts +65 -0
  44. package/src/components/autocomplete/autocomplete-popup.ts +95 -0
  45. package/src/components/autocomplete/autocomplete-positioner.ts +98 -0
  46. package/src/components/autocomplete/autocomplete-root.ts +280 -0
  47. package/src/components/autocomplete/context.ts +16 -14
  48. package/src/components/autocomplete/index.ts +65 -0
  49. package/src/components/block-handle/block-handle-add.ts +71 -0
  50. package/src/components/block-handle/block-handle-draggable.ts +158 -0
  51. package/src/components/block-handle/block-handle-popup.ts +43 -0
  52. package/src/components/block-handle/block-handle-positioner.ts +89 -0
  53. package/src/components/block-handle/block-handle-root.ts +116 -0
  54. package/src/components/block-handle/context.ts +9 -18
  55. package/src/components/block-handle/hover-state.ts +16 -0
  56. package/src/components/block-handle/index.ts +59 -0
  57. package/src/components/block-handle/{block-handle-popover/pointer-move.ts → pointer-move.ts} +8 -7
  58. package/src/components/block-handle/{block-handle-draggable/set-drag-preview.ts → set-drag-preview.ts} +4 -4
  59. package/src/components/block-handle/use-hover-extension.ts +65 -0
  60. package/src/components/drop-indicator/drop-indicator.ts +128 -0
  61. package/src/components/drop-indicator/index.ts +18 -0
  62. package/src/components/inline-popover/index.ts +41 -0
  63. package/src/components/inline-popover/inline-popover-popup.ts +52 -0
  64. package/src/components/inline-popover/inline-popover-positioner.ts +98 -0
  65. package/src/components/inline-popover/inline-popover-root.ts +122 -0
  66. package/src/components/inline-popover/store.ts +6 -0
  67. package/src/components/menu/index.ts +92 -0
  68. package/src/components/popover/index.ts +53 -0
  69. package/src/components/resizable/{resizable-handle/calc-resize.ts → calc-resize.ts} +1 -1
  70. package/src/components/resizable/context.ts +3 -6
  71. package/src/components/resizable/index.ts +32 -0
  72. package/src/components/resizable/resizable-handle.ts +134 -0
  73. package/src/components/resizable/resizable-root.ts +184 -0
  74. package/src/components/table-handle/dnd.ts +16 -27
  75. package/src/components/table-handle/index.ts +125 -0
  76. package/src/components/table-handle/{table-handle-drag-preview/render-preview.ts → render-preview.ts} +5 -5
  77. package/src/components/table-handle/shared.ts +61 -0
  78. package/src/components/table-handle/store.ts +117 -0
  79. package/src/components/table-handle/table-handle-column-menu-root.ts +51 -0
  80. package/src/components/table-handle/table-handle-column-menu-trigger.ts +107 -0
  81. package/src/components/table-handle/table-handle-column-popup.ts +44 -0
  82. package/src/components/table-handle/table-handle-column-positioner.ts +67 -0
  83. package/src/components/table-handle/table-handle-drag-preview.ts +169 -0
  84. package/src/components/table-handle/table-handle-drop-indicator.ts +166 -0
  85. package/src/components/table-handle/table-handle-root.ts +103 -0
  86. package/src/components/table-handle/table-handle-row-menu-root.ts +51 -0
  87. package/src/components/table-handle/table-handle-row-menu-trigger.ts +107 -0
  88. package/src/components/table-handle/table-handle-row-popup.ts +42 -0
  89. package/src/components/table-handle/table-handle-row-positioner.ts +67 -0
  90. package/src/components/table-handle/use-drop.ts +74 -0
  91. package/src/components/table-handle/{hooks/use-empty-image.ts → use-empty-image.ts} +2 -3
  92. package/src/components/table-handle/utils.ts +0 -11
  93. package/src/components/tooltip/index.ts +52 -0
  94. package/src/hooks/use-editor-extension.ts +4 -4
  95. package/src/hooks/use-editor-focus-event.ts +4 -4
  96. package/src/hooks/use-editor-typing.ts +12 -16
  97. package/src/hooks/use-editor-update-event.ts +4 -4
  98. package/src/hooks/use-keymap.ts +4 -4
  99. package/src/hooks/use-scrolling.ts +11 -10
  100. package/src/hooks/use-selecting.ts +8 -15
  101. package/src/utils/event.ts +28 -0
  102. package/src/utils/lazy-signal.spec.ts +68 -0
  103. package/src/utils/lazy-signal.ts +17 -0
  104. package/src/utils/prefers-reduced-motion.ts +6 -0
  105. package/src/utils/prevent-default.ts +3 -0
  106. package/src/utils/use-html-element-at.ts +17 -0
  107. package/src/utils/use-no-focus.ts +7 -0
  108. package/dist/get-default-state.js +0 -11
  109. package/dist/get-default-state.js.map +0 -1
  110. package/src/components/autocomplete/autocomplete-empty/element.gen.ts +0 -18
  111. package/src/components/autocomplete/autocomplete-empty/setup.ts +0 -6
  112. package/src/components/autocomplete/autocomplete-empty/types.ts +0 -13
  113. package/src/components/autocomplete/autocomplete-item/element.gen.ts +0 -18
  114. package/src/components/autocomplete/autocomplete-item/setup.ts +0 -30
  115. package/src/components/autocomplete/autocomplete-item/types.ts +0 -25
  116. package/src/components/autocomplete/autocomplete-list/element.gen.ts +0 -18
  117. package/src/components/autocomplete/autocomplete-list/setup.ts +0 -125
  118. package/src/components/autocomplete/autocomplete-list/types.ts +0 -22
  119. package/src/components/autocomplete/autocomplete-popover/element.gen.ts +0 -18
  120. package/src/components/autocomplete/autocomplete-popover/setup.ts +0 -169
  121. package/src/components/autocomplete/autocomplete-popover/types.ts +0 -100
  122. package/src/components/autocomplete/index.gen.ts +0 -17
  123. package/src/components/block-handle/block-handle-add/element.gen.ts +0 -18
  124. package/src/components/block-handle/block-handle-add/setup.ts +0 -33
  125. package/src/components/block-handle/block-handle-add/types.ts +0 -23
  126. package/src/components/block-handle/block-handle-draggable/element.gen.ts +0 -18
  127. package/src/components/block-handle/block-handle-draggable/setup.ts +0 -113
  128. package/src/components/block-handle/block-handle-draggable/types.ts +0 -23
  129. package/src/components/block-handle/block-handle-popover/element.gen.ts +0 -18
  130. package/src/components/block-handle/block-handle-popover/setup.ts +0 -68
  131. package/src/components/block-handle/block-handle-popover/types.ts +0 -81
  132. package/src/components/block-handle/index.gen.ts +0 -13
  133. package/src/components/drop-indicator/drop-indicator/element.gen.ts +0 -18
  134. package/src/components/drop-indicator/drop-indicator/setup.ts +0 -75
  135. package/src/components/drop-indicator/drop-indicator/types.ts +0 -31
  136. package/src/components/drop-indicator/index.gen.ts +0 -5
  137. package/src/components/inline-popover/index.gen.ts +0 -5
  138. package/src/components/inline-popover/inline-popover/element.gen.ts +0 -18
  139. package/src/components/inline-popover/inline-popover/setup.ts +0 -111
  140. package/src/components/inline-popover/inline-popover/types.ts +0 -112
  141. package/src/components/popover/index.gen.ts +0 -13
  142. package/src/components/popover/popover-content/element.gen.ts +0 -18
  143. package/src/components/popover/popover-content/setup.ts +0 -1
  144. package/src/components/popover/popover-content/types.ts +0 -6
  145. package/src/components/popover/popover-root/element.gen.ts +0 -18
  146. package/src/components/popover/popover-root/setup.ts +0 -1
  147. package/src/components/popover/popover-root/types.ts +0 -6
  148. package/src/components/popover/popover-trigger/element.gen.ts +0 -18
  149. package/src/components/popover/popover-trigger/setup.ts +0 -1
  150. package/src/components/popover/popover-trigger/types.ts +0 -6
  151. package/src/components/resizable/index.gen.ts +0 -9
  152. package/src/components/resizable/resizable-handle/element.gen.ts +0 -18
  153. package/src/components/resizable/resizable-handle/setup.ts +0 -106
  154. package/src/components/resizable/resizable-handle/types.ts +0 -29
  155. package/src/components/resizable/resizable-root/element.gen.ts +0 -18
  156. package/src/components/resizable/resizable-root/setup.ts +0 -84
  157. package/src/components/resizable/resizable-root/types.ts +0 -59
  158. package/src/components/table-handle/context.ts +0 -43
  159. package/src/components/table-handle/hooks/use-drop.ts +0 -85
  160. package/src/components/table-handle/index.gen.ts +0 -37
  161. package/src/components/table-handle/table-handle-column-root/element.gen.ts +0 -18
  162. package/src/components/table-handle/table-handle-column-root/setup.ts +0 -60
  163. package/src/components/table-handle/table-handle-column-root/types.ts +0 -73
  164. package/src/components/table-handle/table-handle-column-trigger/element.gen.ts +0 -18
  165. package/src/components/table-handle/table-handle-column-trigger/setup.ts +0 -64
  166. package/src/components/table-handle/table-handle-column-trigger/types.ts +0 -20
  167. package/src/components/table-handle/table-handle-drag-preview/element.gen.ts +0 -18
  168. package/src/components/table-handle/table-handle-drag-preview/setup.ts +0 -57
  169. package/src/components/table-handle/table-handle-drag-preview/types.ts +0 -14
  170. package/src/components/table-handle/table-handle-drag-preview/updater.ts +0 -90
  171. package/src/components/table-handle/table-handle-drop-indicator/element.gen.ts +0 -18
  172. package/src/components/table-handle/table-handle-drop-indicator/setup.ts +0 -52
  173. package/src/components/table-handle/table-handle-drop-indicator/types.ts +0 -15
  174. package/src/components/table-handle/table-handle-drop-indicator/updater.ts +0 -96
  175. package/src/components/table-handle/table-handle-popover-content/element.gen.ts +0 -18
  176. package/src/components/table-handle/table-handle-popover-content/setup.ts +0 -83
  177. package/src/components/table-handle/table-handle-popover-content/types.ts +0 -32
  178. package/src/components/table-handle/table-handle-popover-item/element.gen.ts +0 -18
  179. package/src/components/table-handle/table-handle-popover-item/setup.ts +0 -17
  180. package/src/components/table-handle/table-handle-popover-item/types.ts +0 -16
  181. package/src/components/table-handle/table-handle-root/element.gen.ts +0 -18
  182. package/src/components/table-handle/table-handle-root/setup.ts +0 -86
  183. package/src/components/table-handle/table-handle-root/types.ts +0 -23
  184. package/src/components/table-handle/table-handle-row-root/element.gen.ts +0 -18
  185. package/src/components/table-handle/table-handle-row-root/setup.ts +0 -70
  186. package/src/components/table-handle/table-handle-row-root/types.ts +0 -68
  187. package/src/components/table-handle/table-handle-row-trigger/element.gen.ts +0 -18
  188. package/src/components/table-handle/table-handle-row-trigger/setup.ts +0 -63
  189. package/src/components/table-handle/table-handle-row-trigger/types.ts +0 -23
  190. package/src/components/tooltip/index.gen.ts +0 -13
  191. package/src/components/tooltip/tooltip-content/element.gen.ts +0 -18
  192. package/src/components/tooltip/tooltip-content/setup.ts +0 -1
  193. package/src/components/tooltip/tooltip-content/types.ts +0 -6
  194. package/src/components/tooltip/tooltip-root/element.gen.ts +0 -18
  195. package/src/components/tooltip/tooltip-root/setup.ts +0 -1
  196. package/src/components/tooltip/tooltip-root/types.ts +0 -6
  197. package/src/components/tooltip/tooltip-trigger/element.gen.ts +0 -18
  198. package/src/components/tooltip/tooltip-trigger/setup.ts +0 -1
  199. package/src/components/tooltip/tooltip-trigger/types.ts +0 -6
  200. package/src/hooks/use-first-rendering.ts +0 -15
  201. package/src/utils/get-default-state.spec.ts +0 -42
  202. package/src/utils/get-default-state.ts +0 -18
  203. /package/src/components/autocomplete/{autocomplete-popover/helpers.spec.ts → helpers.spec.ts} +0 -0
  204. /package/src/components/autocomplete/{autocomplete-popover/helpers.ts → helpers.ts} +0 -0
  205. /package/src/components/inline-popover/{inline-popover/virtual-selection-element.ts → virtual-selection-element.ts} +0 -0
  206. /package/src/components/resizable/{resizable-handle/calc-resize.spec.ts → calc-resize.spec.ts} +0 -0
  207. /package/src/components/table-handle/{table-handle-drop-indicator/calc-drag-over.ts → calc-drag-over.ts} +0 -0
@@ -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
+ }
@@ -1,16 +1,18 @@
1
- import { createContext, type Context } from '@aria-ui/core'
1
+ import { createContext, type Context, type Signal } from '@aria-ui/core'
2
+ import type { ItemFilter } from '@aria-ui/elements/listbox'
3
+ import type { OverlayStore } from '@aria-ui/elements/overlay'
2
4
 
3
- export const queryContext: Context<string> = createContext(
4
- 'prosekit/autocomplete-popover/query',
5
- '',
6
- )
5
+ /**
6
+ * @internal
7
+ */
8
+ export interface AutocompleteStore {
9
+ overlayStore: OverlayStore
10
+ query: Signal<string>
11
+ eventTarget: Signal<EventTarget | null>
12
+ filter: Signal<ItemFilter | null>
13
+ }
7
14
 
8
- export const onSubmitContext: Context<VoidFunction | null> = createContext(
9
- 'prosekit/autocomplete-popover/onSubmit',
10
- null,
11
- )
12
-
13
- export const openContext: Context<boolean> = createContext(
14
- 'prosekit/autocomplete-popover/open',
15
- false,
16
- )
15
+ /**
16
+ * @internal
17
+ */
18
+ export const autocompleteStoreContext: Context<AutocompleteStore> = createContext<AutocompleteStore>('prosekit-autocomplete-store')
@@ -0,0 +1,65 @@
1
+ /**
2
+
3
+ @module
4
+
5
+ ## Anatomy
6
+
7
+ ```html
8
+ <prosekit-autocomplete-root>
9
+ <prosekit-autocomplete-positioner>
10
+ <prosekit-autocomplete-popup>
11
+ <prosekit-autocomplete-item>...</prosekit-autocomplete-item>
12
+ <prosekit-autocomplete-empty>...</prosekit-autocomplete-empty>
13
+ </prosekit-autocomplete-popup>
14
+ </prosekit-autocomplete-positioner>
15
+ </prosekit-autocomplete-root>
16
+ ```
17
+ */
18
+
19
+ export {
20
+ AutocompleteEmptyElement,
21
+ AutocompleteEmptyPropsDeclaration,
22
+ registerAutocompleteEmptyElement,
23
+ setupAutocompleteEmpty,
24
+ type AutocompleteEmptyProps,
25
+ } from './autocomplete-empty.ts'
26
+
27
+ export {
28
+ AutocompleteItemElement,
29
+ AutocompleteItemPropsDeclaration,
30
+ registerAutocompleteItemElement,
31
+ SelectEvent,
32
+ setupAutocompleteItem,
33
+ type AutocompleteItemEvents,
34
+ type AutocompleteItemProps,
35
+ } from './autocomplete-item.ts'
36
+
37
+ export {
38
+ AutocompletePopupElement,
39
+ AutocompletePopupPropsDeclaration,
40
+ registerAutocompletePopupElement,
41
+ setupAutocompletePopup,
42
+ type AutocompletePopupEvents,
43
+ type AutocompletePopupProps,
44
+ } from './autocomplete-popup.ts'
45
+
46
+ export {
47
+ AutocompletePositionerElement,
48
+ AutocompletePositionerPropsDeclaration,
49
+ registerAutocompletePositionerElement,
50
+ setupAutocompletePositioner,
51
+ type AutocompletePositionerProps,
52
+ } from './autocomplete-positioner.ts'
53
+
54
+ export {
55
+ AutocompleteRootElement,
56
+ AutocompleteRootPropsDeclaration,
57
+ OpenChangeEvent,
58
+ QueryChangeEvent,
59
+ registerAutocompleteRootElement,
60
+ setupAutocompleteRoot,
61
+ type AutocompleteRootEvents,
62
+ type AutocompleteRootProps,
63
+ } from './autocomplete-root.ts'
64
+
65
+ export { ValueChangeEvent, ValuesChangeEvent } from '@aria-ui/elements/listbox'
@@ -0,0 +1,71 @@
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 { insertDefaultBlock, type Editor } from '@prosekit/core'
12
+
13
+ import { blockHandleStoreContext } from './context.ts'
14
+
15
+ export interface BlockHandleAddProps {
16
+ /**
17
+ * The ProseKit editor instance.
18
+ *
19
+ * @default null
20
+ * @hidden
21
+ */
22
+ editor: Editor | null
23
+ }
24
+
25
+ /** @internal */
26
+ export const BlockHandleAddPropsDeclaration: PropsDeclaration<BlockHandleAddProps> = /* @__PURE__ */ defineProps<BlockHandleAddProps>({
27
+ editor: { default: null, attribute: false, type: 'json' },
28
+ })
29
+
30
+ /**
31
+ * @internal
32
+ */
33
+ export function setupBlockHandleAdd(
34
+ host: HostElement,
35
+ props: State<BlockHandleAddProps>,
36
+ ): void {
37
+ const getStore = blockHandleStoreContext.consume(host)
38
+
39
+ useEventListener(host, 'pointerdown', (event) => {
40
+ event.preventDefault()
41
+
42
+ const store = getStore()
43
+ const editor = props.editor.get()
44
+ const hoverState = store?.hoverState.get()
45
+ if (!editor || !hoverState) {
46
+ return
47
+ }
48
+
49
+ const { node, pos } = hoverState
50
+ editor.exec(insertDefaultBlock({ pos: pos + node.nodeSize }))
51
+ editor.focus()
52
+
53
+ // Hide the drag handle
54
+ store?.hoverState.set(undefined)
55
+ })
56
+ }
57
+
58
+ const BlockHandleAddElementBase: HostElementConstructor<BlockHandleAddProps> = defineCustomElement(
59
+ setupBlockHandleAdd,
60
+ BlockHandleAddPropsDeclaration,
61
+ )
62
+
63
+ /**
64
+ * @public
65
+ */
66
+ export class BlockHandleAddElement extends BlockHandleAddElementBase {}
67
+
68
+ /** @internal */
69
+ export function registerBlockHandleAddElement(): void {
70
+ registerCustomElement('prosekit-block-handle-add', BlockHandleAddElement)
71
+ }
@@ -0,0 +1,158 @@
1
+ import {
2
+ defineCustomElement,
3
+ defineProps,
4
+ onMount,
5
+ registerCustomElement,
6
+ useEventListener,
7
+ type HostElement,
8
+ type HostElementConstructor,
9
+ type PropsDeclaration,
10
+ type State,
11
+ } from '@aria-ui/core'
12
+ import { useAttribute } from '@aria-ui/utils'
13
+ import { isHTMLElement } from '@ocavue/utils'
14
+ import type { Editor } from '@prosekit/core'
15
+ import type { ViewDragging } from '@prosekit/extensions/drop-indicator'
16
+ import { Fragment, Slice } from '@prosekit/pm/model'
17
+ import { NodeSelection } from '@prosekit/pm/state'
18
+ import type { EditorView } from '@prosekit/pm/view'
19
+
20
+ import { DRAGGING_CLASS_NAME } from '../../constants.ts'
21
+ import { getSafeEditorView } from '../../utils/get-safe-editor-view.ts'
22
+
23
+ import { blockHandleStoreContext } from './context.ts'
24
+ import type { HoverState } from './hover-state.ts'
25
+ import { setDragPreview } from './set-drag-preview.ts'
26
+
27
+ export interface BlockHandleDraggableProps {
28
+ /**
29
+ * The ProseKit editor instance.
30
+ *
31
+ * @default null
32
+ * @hidden
33
+ */
34
+ editor: Editor | null
35
+ }
36
+
37
+ /** @internal */
38
+ export const BlockHandleDraggablePropsDeclaration: PropsDeclaration<BlockHandleDraggableProps> = /* @__PURE__ */ defineProps<
39
+ BlockHandleDraggableProps
40
+ >({
41
+ editor: { default: null, attribute: false, type: 'json' },
42
+ })
43
+
44
+ /**
45
+ * @internal
46
+ */
47
+ export function setupBlockHandleDraggable(
48
+ host: HostElement,
49
+ props: State<BlockHandleDraggableProps>,
50
+ ): void {
51
+ const getStore = blockHandleStoreContext.consume(host)
52
+
53
+ onMount(host, () => {
54
+ host.draggable = true
55
+ })
56
+
57
+ usePointerDownHandler(host, () => getStore()?.hoverState.get() ?? null, props.editor.get)
58
+
59
+ useEventListener(host, 'dragstart', (event) => {
60
+ const store = getStore()
61
+ store?.dragging.set(true)
62
+
63
+ const view = getSafeEditorView(props.editor.get())
64
+ const hoverState = store?.hoverState.get()
65
+
66
+ if (view && hoverState) {
67
+ view.dom.classList.add(DRAGGING_CLASS_NAME)
68
+ createDraggingPreview(view, hoverState, event)
69
+ setViewDragging(view, hoverState)
70
+ }
71
+ })
72
+
73
+ useEventListener(host, 'dragend', () => {
74
+ const store = getStore()
75
+ store?.dragging.set(false)
76
+
77
+ const view = getSafeEditorView(props.editor.get())
78
+ if (view) {
79
+ view.dom.classList.remove(DRAGGING_CLASS_NAME)
80
+ }
81
+ })
82
+
83
+ useAttribute(host, 'data-dragging', () => (getStore()?.dragging.get() ? '' : undefined))
84
+ }
85
+
86
+ function usePointerDownHandler(
87
+ host: HostElement,
88
+ getHoverState: () => HoverState | null,
89
+ getEditor: () => Editor | null,
90
+ ) {
91
+ useEventListener(host, 'pointerdown', () => {
92
+ const hoverState = getHoverState()
93
+ const editor = getEditor()
94
+
95
+ if (hoverState?.pos == null || !editor?.view) {
96
+ return
97
+ }
98
+
99
+ const { view } = editor
100
+ view.dispatch(
101
+ view.state.tr.setSelection(NodeSelection.create(view.state.doc, hoverState.pos)),
102
+ )
103
+
104
+ // Clicking the handle will blur the editor, so we need to focus it again.
105
+ // We cannot call `event.preventDefault()` here to prevent the blur
106
+ // because it will prevent the drag event from firing.
107
+ requestAnimationFrame(() => {
108
+ view.focus()
109
+ })
110
+ })
111
+ }
112
+
113
+ function createDraggingPreview(view: EditorView, hoverState: HoverState, event: DragEvent): void {
114
+ if (!event.dataTransfer) {
115
+ return
116
+ }
117
+
118
+ const { pos } = hoverState
119
+
120
+ const element = view.nodeDOM(pos)
121
+ if (!element || !isHTMLElement(element)) {
122
+ return
123
+ }
124
+
125
+ event.dataTransfer.clearData()
126
+ event.dataTransfer.setData('text/html', element.outerHTML)
127
+ event.dataTransfer.effectAllowed = 'copyMove'
128
+ setDragPreview(event, element)
129
+
130
+ return
131
+ }
132
+
133
+ function setViewDragging(view: EditorView, hoverState: HoverState): void {
134
+ const { node, pos } = hoverState
135
+
136
+ const dragging: ViewDragging = {
137
+ slice: new Slice(Fragment.from(node), 0, 0),
138
+ move: true,
139
+ node: NodeSelection.create(view.state.doc, pos),
140
+ }
141
+
142
+ view.dragging = dragging
143
+ }
144
+
145
+ const BlockHandleDraggableElementBase: HostElementConstructor<BlockHandleDraggableProps> = defineCustomElement(
146
+ setupBlockHandleDraggable,
147
+ BlockHandleDraggablePropsDeclaration,
148
+ )
149
+
150
+ /**
151
+ * @public
152
+ */
153
+ export class BlockHandleDraggableElement extends BlockHandleDraggableElementBase {}
154
+
155
+ /** @internal */
156
+ export function registerBlockHandleDraggableElement(): void {
157
+ registerCustomElement('prosekit-block-handle-draggable', BlockHandleDraggableElement)
158
+ }
@@ -0,0 +1,43 @@
1
+ import {
2
+ defineCustomElement,
3
+ registerCustomElement,
4
+ type HostElement,
5
+ type HostElementConstructor,
6
+ type PropsDeclaration,
7
+ type State,
8
+ } from '@aria-ui/core'
9
+ import { OverlayPopupPropsDeclaration, setupOverlayPopup, type OverlayPopupProps } from '@aria-ui/elements/overlay'
10
+
11
+ import { blockHandleOverlayStoreContext } from './context.ts'
12
+
13
+ /**
14
+ * @public
15
+ */
16
+ export interface BlockHandlePopupProps extends OverlayPopupProps {}
17
+
18
+ /** @internal */
19
+ export const BlockHandlePopupPropsDeclaration: PropsDeclaration<BlockHandlePopupProps> = OverlayPopupPropsDeclaration
20
+
21
+ /** @internal */
22
+ export function setupBlockHandlePopup(
23
+ host: HostElement,
24
+ _props: State<BlockHandlePopupProps>,
25
+ ): void {
26
+ const getOverlayStore = blockHandleOverlayStoreContext.consume(host)
27
+ setupOverlayPopup(host, getOverlayStore)
28
+ }
29
+
30
+ const BlockHandlePopupElementBase: HostElementConstructor<BlockHandlePopupProps> = defineCustomElement(
31
+ setupBlockHandlePopup,
32
+ BlockHandlePopupPropsDeclaration,
33
+ )
34
+
35
+ /**
36
+ * @public
37
+ */
38
+ export class BlockHandlePopupElement extends BlockHandlePopupElementBase {}
39
+
40
+ /** @internal */
41
+ export function registerBlockHandlePopupElement(): void {
42
+ registerCustomElement('prosekit-block-handle-popup', BlockHandlePopupElement)
43
+ }