@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.
- 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 +30 -25
- 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
|
@@ -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
|
-
|
|
4
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
+
}
|