@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,68 @@
1
+ import { computed, createSignal, type Signal } from '@aria-ui/core'
2
+ import { describe, expect, it } from 'vitest'
3
+
4
+ import { createLazySignal } from './lazy-signal.ts'
5
+
6
+ describe('createLazySignal', () => {
7
+ it('returns fallback when remote is undefined', () => {
8
+ const lazy = createLazySignal<number>(() => undefined, 42)
9
+ expect(lazy.get()).toBe(42)
10
+ })
11
+
12
+ it('delegates get to remote when resolved', () => {
13
+ const real = createSignal(10)
14
+ const lazy = createLazySignal<number>(() => real, 0)
15
+ expect(lazy.get()).toBe(10)
16
+ })
17
+
18
+ it('delegates set to remote when resolved', () => {
19
+ const real = createSignal(10)
20
+ const lazy = createLazySignal<number>(() => real, 0)
21
+ lazy.set(20)
22
+ expect(real.get()).toBe(20)
23
+ })
24
+
25
+ it('set is a no-op when remote is undefined', () => {
26
+ const lazy = createLazySignal<number>(() => undefined, 42)
27
+ expect(() => lazy.set(99)).not.toThrow()
28
+ expect(lazy.get()).toBe(42)
29
+ })
30
+
31
+ it('propagates reactivity when remote is bound late', () => {
32
+ const source = createSignal<Signal<number> | undefined>(undefined)
33
+ const lazy = createLazySignal<number>(() => source.get(), 0)
34
+ const derived = computed(() => lazy.get())
35
+
36
+ expect(derived()).toBe(0)
37
+
38
+ const real = createSignal(42)
39
+ source.set(real)
40
+ expect(derived()).toBe(42)
41
+
42
+ real.set(100)
43
+ expect(derived()).toBe(100)
44
+
45
+ real.set(200)
46
+ expect(derived()).toBe(200)
47
+ })
48
+
49
+ it('releases old dependency when remote is reparented', () => {
50
+ const source = createSignal<Signal<number> | undefined>(undefined)
51
+ const lazy = createLazySignal<number>(() => source.get(), 0)
52
+ const derived = computed(() => lazy.get())
53
+
54
+ const a = createSignal(1)
55
+ source.set(a)
56
+ expect(derived()).toBe(1)
57
+
58
+ const b = createSignal(100)
59
+ source.set(b)
60
+ expect(derived()).toBe(100)
61
+
62
+ a.set(999)
63
+ expect(derived()).toBe(100)
64
+
65
+ b.set(200)
66
+ expect(derived()).toBe(200)
67
+ })
68
+ })
@@ -0,0 +1,17 @@
1
+ import type { Signal } from '@aria-ui/core'
2
+
3
+ export function createLazySignal<T>(
4
+ getRemote: () => Signal<T> | undefined,
5
+ fallback: T,
6
+ ): Signal<T> {
7
+ return {
8
+ get: (): T => {
9
+ const remote = getRemote()
10
+ return remote ? remote.get() : fallback
11
+ },
12
+ set: (value: T): void => {
13
+ const remote = getRemote()
14
+ if (remote) remote.set(value)
15
+ },
16
+ }
17
+ }
@@ -0,0 +1,6 @@
1
+ export function prefersReducedMotion(): boolean {
2
+ if (typeof window === 'undefined') {
3
+ return false
4
+ }
5
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches
6
+ }
@@ -0,0 +1,3 @@
1
+ export function preventDefault(event: Event): void {
2
+ event.preventDefault()
3
+ }
@@ -0,0 +1,17 @@
1
+ import { computed } from '@aria-ui/core'
2
+ import { isHTMLElement } from '@ocavue/utils'
3
+ import type { Editor } from '@prosekit/core'
4
+
5
+ export function useHTMLElementAt(
6
+ getEditor: () => Editor | null | undefined,
7
+ getPos: () => number | null | undefined,
8
+ ): () => HTMLElement | undefined {
9
+ return computed(() => {
10
+ const editor = getEditor()
11
+ const pos = getPos()
12
+ if (!editor || !pos) return
13
+ const view = editor.view
14
+ const element = view.nodeDOM(pos)
15
+ if (element && isHTMLElement(element)) return element
16
+ })
17
+ }
@@ -0,0 +1,7 @@
1
+ import { onMount, type HostElement } from '@aria-ui/core'
2
+
3
+ export function useNoFocus(host: HostElement): void {
4
+ onMount(host, () => {
5
+ host.tabIndex = -1
6
+ })
7
+ }
@@ -1,11 +0,0 @@
1
- import { createSignal } from "@aria-ui/core";
2
- //#region src/utils/get-default-state.ts
3
- function getStateWithDefaults(state, props) {
4
- const merged = { ...state };
5
- for (const key of Object.keys(props)) if (!merged[key]) merged[key] = createSignal(props[key].default);
6
- return merged;
7
- }
8
- //#endregion
9
- export { getStateWithDefaults as t };
10
-
11
- //# sourceMappingURL=get-default-state.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-default-state.js","names":[],"sources":["../src/utils/get-default-state.ts"],"sourcesContent":["import { createSignal, type PropDeclarations, type SignalState } from '@aria-ui/core'\n\nexport function getStateWithDefaults<\n Props extends Record<string, any> = Record<string, any>,\n>(\n state: Partial<SignalState<Props>>,\n props: PropDeclarations<Props>,\n): SignalState<Props> {\n const merged = { ...state } as SignalState<Props>\n\n for (const key of Object.keys(props) as (keyof Props)[]) {\n if (!merged[key]) {\n merged[key] = createSignal(props[key].default)\n }\n }\n\n return merged\n}\n"],"mappings":";;AAEA,SAAgB,qBAGd,OACA,OACoB;CACpB,MAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,MAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CAClC,KAAI,CAAC,OAAO,KACV,QAAO,OAAO,aAAa,MAAM,KAAK,QAAQ;AAIlD,QAAO"}
@@ -1,18 +0,0 @@
1
- import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
2
-
3
- import { useAutocompleteEmpty } from "./setup.ts"
4
- import { autocompleteEmptyEvents, autocompleteEmptyProps, type AutocompleteEmptyEvents, type AutocompleteEmptyProps } from "./types.ts"
5
-
6
- const AutocompleteEmptyElementBase: BaseElementConstructor<AutocompleteEmptyProps> = defineCustomElement<
7
- AutocompleteEmptyProps,
8
- AutocompleteEmptyEvents
9
- >({
10
- props: autocompleteEmptyProps,
11
- events: autocompleteEmptyEvents,
12
- setup: useAutocompleteEmpty,
13
- })
14
- class AutocompleteEmptyElement extends AutocompleteEmptyElementBase {}
15
-
16
- registerCustomElement('prosekit-autocomplete-empty', AutocompleteEmptyElement)
17
-
18
- export { AutocompleteEmptyElement }
@@ -1,6 +0,0 @@
1
- import { useListboxEmpty } from '@aria-ui/listbox/elements'
2
-
3
- /**
4
- * @internal
5
- */
6
- export const useAutocompleteEmpty: typeof useListboxEmpty = useListboxEmpty
@@ -1,13 +0,0 @@
1
- import type { EventDeclarations, PropDeclarations } from '@aria-ui/core'
2
-
3
- /** @internal */
4
- export interface AutocompleteEmptyProps {}
5
-
6
- /** @internal */
7
- export const autocompleteEmptyProps: PropDeclarations<AutocompleteEmptyProps> = {}
8
-
9
- /** @internal */
10
- export interface AutocompleteEmptyEvents {}
11
-
12
- /** @internal */
13
- export const autocompleteEmptyEvents: EventDeclarations<AutocompleteEmptyEvents> = {}
@@ -1,18 +0,0 @@
1
- import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
2
-
3
- import { useAutocompleteItem } from "./setup.ts"
4
- import { autocompleteItemEvents, autocompleteItemProps, type AutocompleteItemEvents, type AutocompleteItemProps } from "./types.ts"
5
-
6
- const AutocompleteItemElementBase: BaseElementConstructor<AutocompleteItemProps> = defineCustomElement<
7
- AutocompleteItemProps,
8
- AutocompleteItemEvents
9
- >({
10
- props: autocompleteItemProps,
11
- events: autocompleteItemEvents,
12
- setup: useAutocompleteItem,
13
- })
14
- class AutocompleteItemElement extends AutocompleteItemElementBase {}
15
-
16
- registerCustomElement('prosekit-autocomplete-item', AutocompleteItemElement)
17
-
18
- export { AutocompleteItemElement }
@@ -1,30 +0,0 @@
1
- import { useEffect, useEventListener, type ConnectableElement, type SetupOptions } from '@aria-ui/core'
2
- import { useListboxItem } from '@aria-ui/listbox/elements'
3
-
4
- import { openContext } from '../context.ts'
5
-
6
- import type { AutocompleteItemEvents, AutocompleteItemProps } from './types.ts'
7
-
8
- /**
9
- * @internal
10
- */
11
- export function useAutocompleteItem(
12
- element: ConnectableElement,
13
- { state, emit }: SetupOptions<AutocompleteItemProps, AutocompleteItemEvents>,
14
- ): void {
15
- useListboxItem(element, { state, emit })
16
-
17
- const open = openContext.consume(element)
18
-
19
- useEffect(element, () => {
20
- // Check the text content again when the open state changes
21
- if (!state.value.peek() && open.get()) {
22
- state.value.set(element.textContent ?? '')
23
- }
24
- })
25
-
26
- useEventListener(element, 'pointerdown', (event) => {
27
- // Prevent the editor from losing focus
28
- event.preventDefault()
29
- })
30
- }
@@ -1,25 +0,0 @@
1
- import type { EventDeclarations, PropDeclarations } from '@aria-ui/core'
2
- import { listboxItemEvents, type ListboxItemEvents } from '@aria-ui/listbox'
3
-
4
- export interface AutocompleteItemProps {
5
- /**
6
- * The value of the item, which will be matched against the query.
7
- *
8
- * If not provided, the value is the item's text content.
9
- *
10
- * @default ""
11
- */
12
- value: string
13
- }
14
-
15
- /** @internal */
16
- export const autocompleteItemProps: PropDeclarations<AutocompleteItemProps> = {
17
- value: {
18
- default: '',
19
- },
20
- }
21
-
22
- export interface AutocompleteItemEvents extends ListboxItemEvents {}
23
-
24
- /** @internal */
25
- export const autocompleteItemEvents: EventDeclarations<AutocompleteItemEvents> = listboxItemEvents
@@ -1,18 +0,0 @@
1
- import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
2
-
3
- import { useAutocompleteList } from "./setup.ts"
4
- import { autocompleteListEvents, autocompleteListProps, type AutocompleteListEvents, type AutocompleteListProps } from "./types.ts"
5
-
6
- const AutocompleteListElementBase: BaseElementConstructor<AutocompleteListProps> = defineCustomElement<
7
- AutocompleteListProps,
8
- AutocompleteListEvents
9
- >({
10
- props: autocompleteListProps,
11
- events: autocompleteListEvents,
12
- setup: useAutocompleteList,
13
- })
14
- class AutocompleteListElement extends AutocompleteListElementBase {}
15
-
16
- registerCustomElement('prosekit-autocomplete-list', AutocompleteListElement)
17
-
18
- export { AutocompleteListElement }
@@ -1,125 +0,0 @@
1
- import {
2
- createSignal,
3
- useEffect,
4
- type ConnectableElement,
5
- type ReadonlySignal,
6
- type SetupOptions,
7
- type TypedEventTarget,
8
- } from '@aria-ui/core'
9
- import { listboxProps, useListbox, type ListboxProps } from '@aria-ui/listbox/elements'
10
- import type { Priority } from '@prosekit/core'
11
- import { defineDOMEventHandler, withPriority, type Editor } from '@prosekit/core'
12
-
13
- import { getStateWithDefaults } from '../../../utils/get-default-state.ts'
14
- import { onSubmitContext, openContext, queryContext } from '../context.ts'
15
-
16
- import type { AutocompleteListEvents, AutocompleteListProps } from './types.ts'
17
-
18
- /**
19
- * @internal
20
- */
21
- export function useAutocompleteList(
22
- element: ConnectableElement,
23
- { state, emit }: SetupOptions<AutocompleteListProps, AutocompleteListEvents>,
24
- ): void {
25
- const open = openContext.consume(element)
26
- const query = queryContext.consume(element)
27
- const onSubmit = onSubmitContext.consume(element)
28
-
29
- const keydownTarget = useKeyDownTarget(element, open, state.editor)
30
-
31
- const listboxState = getStateWithDefaults<ListboxProps>(
32
- { filter: state.filter, eventTarget: createSignal(keydownTarget) },
33
- listboxProps,
34
- )
35
-
36
- useEffect(element, () => {
37
- element.addEventListener('valueChange', () => {
38
- if (onSubmit) {
39
- onSubmit.get()?.()
40
- }
41
- })
42
- })
43
-
44
- useListbox(element, { state: listboxState, emit })
45
-
46
- useEffect(element, () => {
47
- listboxState.query.set(query.get())
48
- })
49
-
50
- useEffect(element, () => {
51
- if (!open.get()) {
52
- listboxState.value.set('')
53
- query.set('')
54
- }
55
- })
56
-
57
- // Reset the focused item when the popover is open
58
- useEffect(element, () => {
59
- if (!open.get()) {
60
- listboxState.autoFocus.set(false)
61
- } else {
62
- let canceled = false
63
-
64
- requestAnimationFrame(() => {
65
- if (canceled) return
66
- listboxState.autoFocus.set(true)
67
- })
68
-
69
- return () => {
70
- canceled = true
71
- }
72
- }
73
- })
74
-
75
- // The autocomplete list should not be focusable because the editor will get
76
- // the focus during typing.
77
- useEffect(element, () => {
78
- element.tabIndex = -1
79
- })
80
- }
81
-
82
- function useKeyDownTarget(
83
- element: ConnectableElement,
84
- open: ReadonlySignal<boolean>,
85
- editor: ReadonlySignal<Editor | null>,
86
- ): TypedEventTarget<'keydown'> {
87
- const keydownHandlers: ((event: KeyboardEvent) => void)[] = []
88
-
89
- useEffect(element, () => {
90
- const editorValue = editor.get()
91
-
92
- if (!editorValue) {
93
- return
94
- }
95
-
96
- const extension = defineDOMEventHandler(
97
- 'keydown',
98
- (view, event): boolean => {
99
- if (view.composing || event.defaultPrevented || !open.get()) {
100
- return false
101
- }
102
- keydownHandlers.forEach((handler) => handler(event))
103
- return event.defaultPrevented
104
- },
105
- )
106
-
107
- return editorValue.use(withPriority(extension, 4 satisfies typeof Priority.highest))
108
- })
109
-
110
- return {
111
- addEventListener: (type, listener) => {
112
- if (type === 'keydown') {
113
- keydownHandlers.push(listener)
114
- }
115
- },
116
- removeEventListener: (type, listener) => {
117
- if (type === 'keydown') {
118
- const index = keydownHandlers.indexOf(listener)
119
- if (index !== -1) {
120
- keydownHandlers.splice(index, 1)
121
- }
122
- }
123
- },
124
- }
125
- }
@@ -1,22 +0,0 @@
1
- import type { EventDeclarations, PropDeclarations } from '@aria-ui/core'
2
- import { listboxEvents, listboxProps, type ListboxEvents, type ListboxProps } from '@aria-ui/listbox'
3
- import type { Editor } from '@prosekit/core'
4
-
5
- export interface AutocompleteListProps extends Pick<ListboxProps, 'filter'> {
6
- /**
7
- * The ProseKit editor instance.
8
- *
9
- * @default null
10
- * @hidden
11
- */
12
- editor: Editor | null
13
- }
14
-
15
- export const autocompleteListProps: PropDeclarations<AutocompleteListProps> = {
16
- filter: listboxProps.filter,
17
- editor: { default: null },
18
- }
19
-
20
- export interface AutocompleteListEvents extends ListboxEvents {}
21
-
22
- export const autocompleteListEvents: EventDeclarations<AutocompleteListEvents> = { ...listboxEvents }
@@ -1,18 +0,0 @@
1
- import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
2
-
3
- import { useAutocompletePopover } from "./setup.ts"
4
- import { autocompletePopoverEvents, autocompletePopoverProps, type AutocompletePopoverEvents, type AutocompletePopoverProps } from "./types.ts"
5
-
6
- const AutocompletePopoverElementBase: BaseElementConstructor<AutocompletePopoverProps> = defineCustomElement<
7
- AutocompletePopoverProps,
8
- AutocompletePopoverEvents
9
- >({
10
- props: autocompletePopoverProps,
11
- events: autocompletePopoverEvents,
12
- setup: useAutocompletePopover,
13
- })
14
- class AutocompletePopoverElement extends AutocompletePopoverElementBase {}
15
-
16
- registerCustomElement('prosekit-autocomplete-popover', AutocompletePopoverElement)
17
-
18
- export { AutocompletePopoverElement }
@@ -1,169 +0,0 @@
1
- import {
2
- createComputed,
3
- createSignal,
4
- useAnimationFrame,
5
- useAttribute,
6
- useEffect,
7
- type ConnectableElement,
8
- type ReadonlySignal,
9
- type SetupOptions,
10
- type Signal,
11
- } from '@aria-ui/core'
12
- import { useOverlayPositionerState } from '@aria-ui/overlay/elements'
13
- import { usePresence } from '@aria-ui/presence'
14
- import { defineKeymap, withPriority, type Editor, type Priority } from '@prosekit/core'
15
- import { AutocompleteRule, defineAutocomplete, type MatchHandler } from '@prosekit/extensions/autocomplete'
16
-
17
- import { useEditorExtension } from '../../../hooks/use-editor-extension.ts'
18
- import { useFirstRendering } from '../../../hooks/use-first-rendering.ts'
19
- import { getSafeEditorView } from '../../../utils/get-safe-editor-view.ts'
20
- import { onSubmitContext, openContext, queryContext } from '../context.ts'
21
-
22
- import { defaultQueryBuilder } from './helpers.ts'
23
- import type { AutocompletePopoverEvents, AutocompletePopoverProps } from './types.ts'
24
-
25
- /**
26
- * @internal
27
- */
28
- export function useAutocompletePopover(
29
- host: ConnectableElement,
30
- {
31
- state,
32
- emit,
33
- }: SetupOptions<AutocompletePopoverProps, AutocompletePopoverEvents>,
34
- ): void {
35
- const { editor, regex, ...overlayState } = state
36
-
37
- const reference = createSignal<Element | null>(null)
38
- const query = createSignal<string>('')
39
- const onDismiss = createSignal<VoidFunction | null>(null)
40
- const onSubmit = createSignal<VoidFunction | null>(null)
41
- const presence = createComputed(() => !!reference.get())
42
-
43
- queryContext.provide(host, query)
44
- onSubmitContext.provide(host, onSubmit)
45
- openContext.provide(host, presence)
46
-
47
- useEscapeKeydown(host, editor, createKeymapHandler(onDismiss, presence))
48
-
49
- useAutocompleteExtension(
50
- host,
51
- editor,
52
- regex,
53
- reference,
54
- query,
55
- onDismiss,
56
- onSubmit,
57
- )
58
-
59
- useOverlayPositionerState(host, overlayState, { reference })
60
-
61
- useAttribute(host, 'data-state', () => (presence.get() ? 'open' : 'closed'))
62
- usePresence(host, presence)
63
-
64
- const firstRendering = useFirstRendering(host)
65
-
66
- useEffect(host, () => {
67
- const queryValue = query.get()
68
-
69
- if (!firstRendering.peek()) {
70
- emit('queryChange', queryValue)
71
- }
72
- })
73
-
74
- useAnimationFrame(host, () => {
75
- const presenceValue = presence.get()
76
- return () => {
77
- emit('openChange', presenceValue)
78
- }
79
- })
80
- }
81
-
82
- function useAutocompleteExtension(
83
- host: ConnectableElement,
84
- editor: ReadonlySignal<Editor | null>,
85
- regex: ReadonlySignal<RegExp | null>,
86
- reference: Signal<Element | null>,
87
- query: Signal<string>,
88
- onDismiss: Signal<VoidFunction | null>,
89
- onSubmit: Signal<VoidFunction | null>,
90
- ) {
91
- useEffect(host, () => {
92
- const editorValue = editor.get()
93
- const regexValue = regex.get()
94
-
95
- if (!editorValue || !regexValue) {
96
- return
97
- }
98
-
99
- const rule = createAutocompleteRule(
100
- editorValue,
101
- regexValue,
102
- reference,
103
- query,
104
- onDismiss,
105
- onSubmit,
106
- )
107
- const extension = defineAutocomplete(rule)
108
- return editorValue.use(extension)
109
- })
110
- }
111
-
112
- function createAutocompleteRule(
113
- editor: Editor,
114
- regex: RegExp,
115
- reference: Signal<Element | null>,
116
- query: Signal<string>,
117
- onDismiss: Signal<VoidFunction | null>,
118
- onSubmit: Signal<VoidFunction | null>,
119
- ) {
120
- const handleEnter: MatchHandler = (options) => {
121
- const view = getSafeEditorView(editor)
122
- const span = view?.dom.querySelector('.prosekit-autocomplete-match')
123
-
124
- if (span) {
125
- reference.set(span)
126
- }
127
-
128
- query.set(defaultQueryBuilder(options.match))
129
- onDismiss.set(options.ignoreMatch)
130
- onSubmit.set(options.deleteMatch)
131
- }
132
-
133
- const handleLeave = () => {
134
- reference.set(null)
135
- query.set('')
136
- }
137
-
138
- return new AutocompleteRule({
139
- regex,
140
- onEnter: handleEnter,
141
- onLeave: handleLeave,
142
- })
143
- }
144
-
145
- function createKeymapHandler(
146
- handler: ReadonlySignal<VoidFunction | null>,
147
- enabled: ReadonlySignal<boolean>,
148
- ) {
149
- return (): boolean => {
150
- if (!enabled.get()) {
151
- return false
152
- }
153
-
154
- const fn = handler.peek()
155
- if (!fn) return false
156
- fn()
157
- return true
158
- }
159
- }
160
-
161
- function useEscapeKeydown(
162
- host: ConnectableElement,
163
- editor: ReadonlySignal<Editor | null>,
164
- handler: () => boolean,
165
- ): void {
166
- const keymap = { Escape: handler }
167
- const extension = withPriority(defineKeymap(keymap), 4 satisfies typeof Priority.highest)
168
- useEditorExtension(host, editor, extension)
169
- }