@prosekit/web 0.7.3 → 0.7.5
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/{get-default-state-CIEy7xrl.js → get-default-state-BzBimBWi.js} +2 -1
- package/dist/get-default-state-BzBimBWi.js.map +1 -0
- package/dist/{get-safe-editor-view-DENm4avv.js → get-safe-editor-view-Dt9Amrcn.js} +2 -1
- package/dist/get-safe-editor-view-Dt9Amrcn.js.map +1 -0
- package/dist/{inject-style-D5jj7cme.js → inject-style-Dm6W58W3.js} +6 -9
- package/dist/inject-style-Dm6W58W3.js.map +1 -0
- package/dist/prosekit-web-autocomplete.d.ts +2 -1
- package/dist/prosekit-web-autocomplete.d.ts.map +1 -0
- package/dist/prosekit-web-autocomplete.js +9 -13
- package/dist/prosekit-web-autocomplete.js.map +1 -0
- package/dist/prosekit-web-block-handle.d.ts +2 -1
- package/dist/prosekit-web-block-handle.d.ts.map +1 -0
- package/dist/prosekit-web-block-handle.js +31 -31
- package/dist/prosekit-web-block-handle.js.map +1 -0
- package/dist/prosekit-web-drop-indicator.d.ts +2 -1
- package/dist/prosekit-web-drop-indicator.d.ts.map +1 -0
- package/dist/prosekit-web-drop-indicator.js +6 -6
- package/dist/prosekit-web-drop-indicator.js.map +1 -0
- package/dist/prosekit-web-inline-popover.d.ts +2 -1
- package/dist/prosekit-web-inline-popover.d.ts.map +1 -0
- package/dist/prosekit-web-inline-popover.js +8 -12
- package/dist/prosekit-web-inline-popover.js.map +1 -0
- package/dist/prosekit-web-popover.d.ts +2 -1
- package/dist/prosekit-web-popover.d.ts.map +1 -0
- package/dist/prosekit-web-popover.js +2 -1
- package/dist/prosekit-web-popover.js.map +1 -0
- package/dist/prosekit-web-resizable.d.ts +2 -1
- package/dist/prosekit-web-resizable.d.ts.map +1 -0
- package/dist/prosekit-web-resizable.js +5 -7
- package/dist/prosekit-web-resizable.js.map +1 -0
- package/dist/prosekit-web-table-handle.d.ts +2 -1
- package/dist/prosekit-web-table-handle.d.ts.map +1 -0
- package/dist/prosekit-web-table-handle.js +39 -72
- package/dist/prosekit-web-table-handle.js.map +1 -0
- package/dist/prosekit-web-tooltip.d.ts +2 -1
- package/dist/prosekit-web-tooltip.d.ts.map +1 -0
- package/dist/prosekit-web-tooltip.js +2 -1
- package/dist/prosekit-web-tooltip.js.map +1 -0
- package/dist/prosekit-web.js +1 -0
- package/dist/{use-editor-extension-Cc7ZG7uj.js → use-editor-extension-B2WuUfnd.js} +2 -1
- package/dist/use-editor-extension-B2WuUfnd.js.map +1 -0
- package/dist/{use-scrolling-BNfsQs3S.js → use-scrolling-BOvyjDvH.js} +2 -1
- package/dist/use-scrolling-BOvyjDvH.js.map +1 -0
- package/package.json +21 -21
- package/src/components/autocomplete/autocomplete-empty/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-empty/setup.ts +6 -0
- package/src/components/autocomplete/autocomplete-empty/types.ts +16 -0
- package/src/components/autocomplete/autocomplete-item/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-item/setup.ts +38 -0
- package/src/components/autocomplete/autocomplete-item/types.ts +31 -0
- package/src/components/autocomplete/autocomplete-list/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-list/setup.ts +140 -0
- package/src/components/autocomplete/autocomplete-list/types.ts +30 -0
- package/src/components/autocomplete/autocomplete-popover/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-popover/helpers.spec.ts +21 -0
- package/src/components/autocomplete/autocomplete-popover/helpers.ts +7 -0
- package/src/components/autocomplete/autocomplete-popover/setup.ts +185 -0
- package/src/components/autocomplete/autocomplete-popover/types.ts +103 -0
- package/src/components/autocomplete/context.ts +19 -0
- package/src/components/autocomplete/index.gen.ts +17 -0
- package/src/components/block-handle/block-handle-add/element.gen.ts +18 -0
- package/src/components/block-handle/block-handle-add/setup.ts +37 -0
- package/src/components/block-handle/block-handle-add/types.ts +26 -0
- package/src/components/block-handle/block-handle-draggable/element.gen.ts +18 -0
- package/src/components/block-handle/block-handle-draggable/set-drag-preview.ts +88 -0
- package/src/components/block-handle/block-handle-draggable/setup.ts +133 -0
- package/src/components/block-handle/block-handle-draggable/types.ts +26 -0
- package/src/components/block-handle/block-handle-popover/element.gen.ts +18 -0
- package/src/components/block-handle/block-handle-popover/pointer-move.ts +262 -0
- package/src/components/block-handle/block-handle-popover/setup.ts +88 -0
- package/src/components/block-handle/block-handle-popover/types.ts +84 -0
- package/src/components/block-handle/context.ts +34 -0
- package/src/components/block-handle/index.gen.ts +13 -0
- package/src/components/drop-indicator/drop-indicator/element.gen.ts +18 -0
- package/src/components/drop-indicator/drop-indicator/setup.ts +87 -0
- package/src/components/drop-indicator/drop-indicator/types.ts +34 -0
- package/src/components/drop-indicator/index.gen.ts +5 -0
- package/src/components/inline-popover/index.gen.ts +5 -0
- package/src/components/inline-popover/inline-popover/element.gen.ts +18 -0
- package/src/components/inline-popover/inline-popover/setup.ts +97 -0
- package/src/components/inline-popover/inline-popover/types.ts +115 -0
- package/src/components/inline-popover/inline-popover/virtual-selection-element.ts +75 -0
- package/src/components/popover/index.gen.ts +13 -0
- package/src/components/popover/popover-content/element.gen.ts +18 -0
- package/src/components/popover/popover-content/setup.ts +1 -0
- package/src/components/popover/popover-content/types.ts +12 -0
- package/src/components/popover/popover-root/element.gen.ts +18 -0
- package/src/components/popover/popover-root/setup.ts +1 -0
- package/src/components/popover/popover-root/types.ts +12 -0
- package/src/components/popover/popover-trigger/element.gen.ts +18 -0
- package/src/components/popover/popover-trigger/setup.ts +1 -0
- package/src/components/popover/popover-trigger/types.ts +12 -0
- package/src/components/resizable/context.ts +45 -0
- package/src/components/resizable/index.gen.ts +9 -0
- package/src/components/resizable/resizable-handle/calc-resize.spec.ts +280 -0
- package/src/components/resizable/resizable-handle/calc-resize.ts +121 -0
- package/src/components/resizable/resizable-handle/element.gen.ts +18 -0
- package/src/components/resizable/resizable-handle/setup.ts +112 -0
- package/src/components/resizable/resizable-handle/types.ts +32 -0
- package/src/components/resizable/resizable-root/element.gen.ts +18 -0
- package/src/components/resizable/resizable-root/setup.ts +93 -0
- package/src/components/resizable/resizable-root/types.ts +28 -0
- package/src/components/table-handle/context.ts +49 -0
- package/src/components/table-handle/dnd.ts +135 -0
- package/src/components/table-handle/hooks/use-drop.ts +94 -0
- package/src/components/table-handle/hooks/use-empty-image.ts +30 -0
- package/src/components/table-handle/index.gen.ts +37 -0
- package/src/components/table-handle/table-handle-column-root/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-column-root/setup.ts +71 -0
- package/src/components/table-handle/table-handle-column-root/types.ts +76 -0
- package/src/components/table-handle/table-handle-column-trigger/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-column-trigger/setup.ts +75 -0
- package/src/components/table-handle/table-handle-column-trigger/types.ts +23 -0
- package/src/components/table-handle/table-handle-drag-preview/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-drag-preview/render-preview.ts +80 -0
- package/src/components/table-handle/table-handle-drag-preview/setup.ts +67 -0
- package/src/components/table-handle/table-handle-drag-preview/types.ts +17 -0
- package/src/components/table-handle/table-handle-drag-preview/updater.ts +101 -0
- package/src/components/table-handle/table-handle-drop-indicator/calc-drag-over.ts +44 -0
- package/src/components/table-handle/table-handle-drop-indicator/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-drop-indicator/setup.ts +56 -0
- package/src/components/table-handle/table-handle-drop-indicator/types.ts +18 -0
- package/src/components/table-handle/table-handle-drop-indicator/updater.ts +110 -0
- package/src/components/table-handle/table-handle-popover-content/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-popover-content/setup.ts +90 -0
- package/src/components/table-handle/table-handle-popover-content/types.ts +40 -0
- package/src/components/table-handle/table-handle-popover-item/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-popover-item/setup.ts +23 -0
- package/src/components/table-handle/table-handle-popover-item/types.ts +24 -0
- package/src/components/table-handle/table-handle-root/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-root/setup.ts +93 -0
- package/src/components/table-handle/table-handle-root/types.ts +26 -0
- package/src/components/table-handle/table-handle-row-root/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-row-root/setup.ts +77 -0
- package/src/components/table-handle/table-handle-row-root/types.ts +75 -0
- package/src/components/table-handle/table-handle-row-trigger/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-row-trigger/setup.ts +74 -0
- package/src/components/table-handle/table-handle-row-trigger/types.ts +26 -0
- package/src/components/table-handle/utils.ts +107 -0
- package/src/components/tooltip/index.gen.ts +13 -0
- package/src/components/tooltip/tooltip-content/element.gen.ts +18 -0
- package/src/components/tooltip/tooltip-content/setup.ts +1 -0
- package/src/components/tooltip/tooltip-content/types.ts +12 -0
- package/src/components/tooltip/tooltip-root/element.gen.ts +18 -0
- package/src/components/tooltip/tooltip-root/setup.ts +1 -0
- package/src/components/tooltip/tooltip-root/types.ts +12 -0
- package/src/components/tooltip/tooltip-trigger/element.gen.ts +18 -0
- package/src/components/tooltip/tooltip-trigger/setup.ts +1 -0
- package/src/components/tooltip/tooltip-trigger/types.ts +12 -0
- package/src/hooks/use-editor-extension.ts +19 -0
- package/src/hooks/use-editor-focus-event.ts +23 -0
- package/src/hooks/use-editor-typing.ts +36 -0
- package/src/hooks/use-editor-update-event.ts +23 -0
- package/src/hooks/use-first-rendering.ts +20 -0
- package/src/hooks/use-keymap.ts +20 -0
- package/src/hooks/use-scrolling.ts +33 -0
- package/src/hooks/use-selecting.ts +63 -0
- package/src/index.ts +1 -0
- package/src/utils/assign-styles.ts +14 -0
- package/src/utils/clone-element.ts +110 -0
- package/src/utils/css-feature-detection.ts +9 -0
- package/src/utils/fade-color.ts +15 -0
- package/src/utils/get-box-element.ts +20 -0
- package/src/utils/get-client-rect.ts +35 -0
- package/src/utils/get-default-state.spec.ts +50 -0
- package/src/utils/get-default-state.ts +22 -0
- package/src/utils/get-effective-background-color.ts +21 -0
- package/src/utils/get-safe-editor-view.ts +10 -0
- package/src/utils/inject-style.ts +11 -0
- package/src/utils/is-finite-positive-number.ts +3 -0
- package/src/utils/max-z-index.ts +3 -0
- package/src/utils/throttle.ts +17 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EventDeclarations,
|
|
3
|
+
PropDeclarations,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
import {
|
|
6
|
+
listboxEvents,
|
|
7
|
+
listboxProps,
|
|
8
|
+
type ListboxEvents,
|
|
9
|
+
type ListboxProps,
|
|
10
|
+
} from '@aria-ui/listbox'
|
|
11
|
+
import type { Editor } from '@prosekit/core'
|
|
12
|
+
|
|
13
|
+
export interface AutocompleteListProps extends Pick<ListboxProps, 'filter'> {
|
|
14
|
+
/**
|
|
15
|
+
* The ProseKit editor instance.
|
|
16
|
+
*
|
|
17
|
+
* @default null
|
|
18
|
+
* @hidden
|
|
19
|
+
*/
|
|
20
|
+
editor: Editor | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const autocompleteListProps: PropDeclarations<AutocompleteListProps> = {
|
|
24
|
+
filter: listboxProps.filter,
|
|
25
|
+
editor: { default: null },
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AutocompleteListEvents extends ListboxEvents {}
|
|
29
|
+
|
|
30
|
+
export const autocompleteListEvents: EventDeclarations<AutocompleteListEvents> = { ...listboxEvents }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
|
|
2
|
+
|
|
3
|
+
import { useAutocompletePopover } from "./setup"
|
|
4
|
+
import { autocompletePopoverEvents, autocompletePopoverProps, type AutocompletePopoverEvents, type AutocompletePopoverProps } from "./types"
|
|
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 }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
} from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { defaultQueryBuilder } from './helpers'
|
|
8
|
+
|
|
9
|
+
describe('defaultQueryBuilder', () => {
|
|
10
|
+
it('can remove extra spaces', () => {
|
|
11
|
+
const str = ' a '
|
|
12
|
+
const match = /.*/.exec(str)!
|
|
13
|
+
expect(defaultQueryBuilder(match)).toMatchInlineSnapshot('"a"')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('can remove punctuations', () => {
|
|
17
|
+
const str = ' a ~!@#$%^&*()_+`-={}|[]\\:;"\'<>?,./ b '
|
|
18
|
+
const match = /.*/.exec(str)!
|
|
19
|
+
expect(defaultQueryBuilder(match)).toMatchInlineSnapshot('"a b"')
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,185 @@
|
|
|
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 {
|
|
15
|
+
defineKeymap,
|
|
16
|
+
Priority,
|
|
17
|
+
withPriority,
|
|
18
|
+
type Editor,
|
|
19
|
+
} from '@prosekit/core'
|
|
20
|
+
import {
|
|
21
|
+
AutocompleteRule,
|
|
22
|
+
defineAutocomplete,
|
|
23
|
+
type MatchHandler,
|
|
24
|
+
} from '@prosekit/extensions/autocomplete'
|
|
25
|
+
|
|
26
|
+
import { useEditorExtension } from '../../../hooks/use-editor-extension'
|
|
27
|
+
import { useFirstRendering } from '../../../hooks/use-first-rendering'
|
|
28
|
+
import { getSafeEditorView } from '../../../utils/get-safe-editor-view'
|
|
29
|
+
import {
|
|
30
|
+
onSubmitContext,
|
|
31
|
+
openContext,
|
|
32
|
+
queryContext,
|
|
33
|
+
} from '../context'
|
|
34
|
+
|
|
35
|
+
import { defaultQueryBuilder } from './helpers'
|
|
36
|
+
import type {
|
|
37
|
+
AutocompletePopoverEvents,
|
|
38
|
+
AutocompletePopoverProps,
|
|
39
|
+
} from './types'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export function useAutocompletePopover(
|
|
45
|
+
host: ConnectableElement,
|
|
46
|
+
{
|
|
47
|
+
state,
|
|
48
|
+
emit,
|
|
49
|
+
}: SetupOptions<AutocompletePopoverProps, AutocompletePopoverEvents>,
|
|
50
|
+
): void {
|
|
51
|
+
const { editor, regex, ...overlayState } = state
|
|
52
|
+
|
|
53
|
+
const reference = createSignal<Element | null>(null)
|
|
54
|
+
const query = createSignal<string>('')
|
|
55
|
+
const onDismiss = createSignal<VoidFunction | null>(null)
|
|
56
|
+
const onSubmit = createSignal<VoidFunction | null>(null)
|
|
57
|
+
const presence = createComputed(() => !!reference.get())
|
|
58
|
+
|
|
59
|
+
queryContext.provide(host, query)
|
|
60
|
+
onSubmitContext.provide(host, onSubmit)
|
|
61
|
+
openContext.provide(host, presence)
|
|
62
|
+
|
|
63
|
+
useEscapeKeydown(host, editor, createKeymapHandler(onDismiss, presence))
|
|
64
|
+
|
|
65
|
+
useAutocompleteExtension(
|
|
66
|
+
host,
|
|
67
|
+
editor,
|
|
68
|
+
regex,
|
|
69
|
+
reference,
|
|
70
|
+
query,
|
|
71
|
+
onDismiss,
|
|
72
|
+
onSubmit,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
useOverlayPositionerState(host, overlayState, { reference })
|
|
76
|
+
|
|
77
|
+
useAttribute(host, 'data-state', () => (presence.get() ? 'open' : 'closed'))
|
|
78
|
+
usePresence(host, presence)
|
|
79
|
+
|
|
80
|
+
const firstRendering = useFirstRendering(host)
|
|
81
|
+
|
|
82
|
+
useEffect(host, () => {
|
|
83
|
+
const queryValue = query.get()
|
|
84
|
+
|
|
85
|
+
if (!firstRendering.peek()) {
|
|
86
|
+
emit('queryChange', queryValue)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
useAnimationFrame(host, () => {
|
|
91
|
+
const presenceValue = presence.get()
|
|
92
|
+
return () => {
|
|
93
|
+
emit('openChange', presenceValue)
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function useAutocompleteExtension(
|
|
99
|
+
host: ConnectableElement,
|
|
100
|
+
editor: ReadonlySignal<Editor | null>,
|
|
101
|
+
regex: ReadonlySignal<RegExp | null>,
|
|
102
|
+
reference: Signal<Element | null>,
|
|
103
|
+
query: Signal<string>,
|
|
104
|
+
onDismiss: Signal<VoidFunction | null>,
|
|
105
|
+
onSubmit: Signal<VoidFunction | null>,
|
|
106
|
+
) {
|
|
107
|
+
useEffect(host, () => {
|
|
108
|
+
const editorValue = editor.get()
|
|
109
|
+
const regexValue = regex.get()
|
|
110
|
+
|
|
111
|
+
if (!editorValue || !regexValue) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const rule = createAutocompleteRule(
|
|
116
|
+
editorValue,
|
|
117
|
+
regexValue,
|
|
118
|
+
reference,
|
|
119
|
+
query,
|
|
120
|
+
onDismiss,
|
|
121
|
+
onSubmit,
|
|
122
|
+
)
|
|
123
|
+
const extension = defineAutocomplete(rule)
|
|
124
|
+
return editorValue.use(extension)
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createAutocompleteRule(
|
|
129
|
+
editor: Editor,
|
|
130
|
+
regex: RegExp,
|
|
131
|
+
reference: Signal<Element | null>,
|
|
132
|
+
query: Signal<string>,
|
|
133
|
+
onDismiss: Signal<VoidFunction | null>,
|
|
134
|
+
onSubmit: Signal<VoidFunction | null>,
|
|
135
|
+
) {
|
|
136
|
+
const handleEnter: MatchHandler = (options) => {
|
|
137
|
+
const view = getSafeEditorView(editor)
|
|
138
|
+
const span = view?.dom.querySelector('.prosemirror-prediction-match')
|
|
139
|
+
|
|
140
|
+
if (span) {
|
|
141
|
+
reference.set(span)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
query.set(defaultQueryBuilder(options.match))
|
|
145
|
+
onDismiss.set(options.ignoreMatch)
|
|
146
|
+
onSubmit.set(options.deleteMatch)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const handleLeave = () => {
|
|
150
|
+
reference.set(null)
|
|
151
|
+
query.set('')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return new AutocompleteRule({
|
|
155
|
+
regex,
|
|
156
|
+
onEnter: handleEnter,
|
|
157
|
+
onLeave: handleLeave,
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function createKeymapHandler(
|
|
162
|
+
handler: ReadonlySignal<VoidFunction | null>,
|
|
163
|
+
enabled: ReadonlySignal<boolean>,
|
|
164
|
+
) {
|
|
165
|
+
return (): boolean => {
|
|
166
|
+
if (!enabled.get()) {
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const fn = handler.peek()
|
|
171
|
+
if (!fn) return false
|
|
172
|
+
fn()
|
|
173
|
+
return true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function useEscapeKeydown(
|
|
178
|
+
host: ConnectableElement,
|
|
179
|
+
editor: ReadonlySignal<Editor | null>,
|
|
180
|
+
handler: () => boolean,
|
|
181
|
+
): void {
|
|
182
|
+
const keymap = { Escape: handler }
|
|
183
|
+
const extension = withPriority(defineKeymap(keymap), Priority.highest)
|
|
184
|
+
useEditorExtension(host, editor, extension)
|
|
185
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EventDeclarations,
|
|
3
|
+
PropDeclarations,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
import {
|
|
6
|
+
overlayPositionerEvents,
|
|
7
|
+
overlayPositionerProps,
|
|
8
|
+
type OverlayPositionerEvents,
|
|
9
|
+
type OverlayPositionerProps,
|
|
10
|
+
} from '@aria-ui/overlay/elements'
|
|
11
|
+
import type { Editor } from '@prosekit/core'
|
|
12
|
+
|
|
13
|
+
export interface AutocompletePopoverProps extends OverlayPositionerProps {
|
|
14
|
+
/**
|
|
15
|
+
* The ProseKit editor instance.
|
|
16
|
+
*
|
|
17
|
+
* @default null
|
|
18
|
+
* @hidden
|
|
19
|
+
*/
|
|
20
|
+
editor: Editor | null
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The regular expression to match the query text to autocomplete.
|
|
24
|
+
*
|
|
25
|
+
* @default null
|
|
26
|
+
*/
|
|
27
|
+
regex: RegExp | null
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The placement of the popover, relative to the text cursor.
|
|
31
|
+
*
|
|
32
|
+
* @default "bottom-start"
|
|
33
|
+
*/
|
|
34
|
+
placement: OverlayPositionerProps['placement']
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The distance between the popover and the hovered block.
|
|
38
|
+
*
|
|
39
|
+
* @default 4
|
|
40
|
+
*/
|
|
41
|
+
offset: OverlayPositionerProps['offset']
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
inline: OverlayPositionerProps['inline']
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @default true
|
|
50
|
+
*/
|
|
51
|
+
hoist: OverlayPositionerProps['hoist']
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
fitViewport: OverlayPositionerProps['fitViewport']
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @default "The body element"
|
|
60
|
+
*/
|
|
61
|
+
boundary: OverlayPositionerProps['boundary']
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @default 8
|
|
65
|
+
*/
|
|
66
|
+
overflowPadding: OverlayPositionerProps['overflowPadding']
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const body = typeof document !== 'undefined' && document.querySelector('body')
|
|
70
|
+
const defaultBoundary = body || 'clippingAncestors'
|
|
71
|
+
|
|
72
|
+
/** @internal */
|
|
73
|
+
export const autocompletePopoverProps: PropDeclarations<AutocompletePopoverProps> = {
|
|
74
|
+
...overlayPositionerProps,
|
|
75
|
+
editor: { default: null },
|
|
76
|
+
regex: { default: null },
|
|
77
|
+
placement: { default: 'bottom-start' },
|
|
78
|
+
offset: { default: 4 },
|
|
79
|
+
inline: { default: true },
|
|
80
|
+
hoist: { default: true },
|
|
81
|
+
fitViewport: { default: true },
|
|
82
|
+
boundary: { default: defaultBoundary },
|
|
83
|
+
overflowPadding: { default: 8 },
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface AutocompletePopoverEvents extends OverlayPositionerEvents {
|
|
87
|
+
/**
|
|
88
|
+
* Fired when the open state changes.
|
|
89
|
+
*/
|
|
90
|
+
openChange: CustomEvent<boolean>
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Fired when the query changes.
|
|
94
|
+
*/
|
|
95
|
+
queryChange: CustomEvent<string>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** @internal */
|
|
99
|
+
export const autocompletePopoverEvents: EventDeclarations<AutocompletePopoverEvents> = {
|
|
100
|
+
...overlayPositionerEvents,
|
|
101
|
+
openChange: {},
|
|
102
|
+
queryChange: {},
|
|
103
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
type Context,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
|
|
6
|
+
export const queryContext: Context<string> = createContext(
|
|
7
|
+
'prosekit/autocomplete-popover/query',
|
|
8
|
+
'',
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
export const onSubmitContext: Context<VoidFunction | null> = createContext(
|
|
12
|
+
'prosekit/autocomplete-popover/onSubmit',
|
|
13
|
+
null,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
export const openContext: Context<boolean> = createContext(
|
|
17
|
+
'prosekit/autocomplete-popover/open',
|
|
18
|
+
false,
|
|
19
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// This file is generated by packages/dev/src/gen-components.ts
|
|
2
|
+
|
|
3
|
+
export { AutocompleteEmptyElement } from './autocomplete-empty/element.gen'
|
|
4
|
+
export { autocompleteEmptyEvents, autocompleteEmptyProps, type AutocompleteEmptyEvents, type AutocompleteEmptyProps } from './autocomplete-empty/types'
|
|
5
|
+
export { useAutocompleteEmpty } from './autocomplete-empty/setup'
|
|
6
|
+
|
|
7
|
+
export { AutocompleteItemElement } from './autocomplete-item/element.gen'
|
|
8
|
+
export { autocompleteItemEvents, autocompleteItemProps, type AutocompleteItemEvents, type AutocompleteItemProps } from './autocomplete-item/types'
|
|
9
|
+
export { useAutocompleteItem } from './autocomplete-item/setup'
|
|
10
|
+
|
|
11
|
+
export { AutocompleteListElement } from './autocomplete-list/element.gen'
|
|
12
|
+
export { autocompleteListEvents, autocompleteListProps, type AutocompleteListEvents, type AutocompleteListProps } from './autocomplete-list/types'
|
|
13
|
+
export { useAutocompleteList } from './autocomplete-list/setup'
|
|
14
|
+
|
|
15
|
+
export { AutocompletePopoverElement } from './autocomplete-popover/element.gen'
|
|
16
|
+
export { autocompletePopoverEvents, autocompletePopoverProps, type AutocompletePopoverEvents, type AutocompletePopoverProps } from './autocomplete-popover/types'
|
|
17
|
+
export { useAutocompletePopover } from './autocomplete-popover/setup'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
|
|
2
|
+
|
|
3
|
+
import { useBlockHandleAdd } from "./setup"
|
|
4
|
+
import { blockHandleAddEvents, blockHandleAddProps, type BlockHandleAddEvents, type BlockHandleAddProps } from "./types"
|
|
5
|
+
|
|
6
|
+
const BlockHandleAddElementBase: BaseElementConstructor<BlockHandleAddProps> = defineCustomElement<
|
|
7
|
+
BlockHandleAddProps,
|
|
8
|
+
BlockHandleAddEvents
|
|
9
|
+
>({
|
|
10
|
+
props: blockHandleAddProps,
|
|
11
|
+
events: blockHandleAddEvents,
|
|
12
|
+
setup: useBlockHandleAdd,
|
|
13
|
+
})
|
|
14
|
+
class BlockHandleAddElement extends BlockHandleAddElementBase {}
|
|
15
|
+
|
|
16
|
+
registerCustomElement('prosekit-block-handle-add', BlockHandleAddElement)
|
|
17
|
+
|
|
18
|
+
export { BlockHandleAddElement }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useEventListener,
|
|
3
|
+
type ConnectableElement,
|
|
4
|
+
type SignalState,
|
|
5
|
+
} from '@aria-ui/core'
|
|
6
|
+
import { insertDefaultBlock } from '@prosekit/core'
|
|
7
|
+
|
|
8
|
+
import { blockPopoverContext } from '../context'
|
|
9
|
+
|
|
10
|
+
import type { BlockHandleAddProps } from './types'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export function useBlockHandleAdd(
|
|
16
|
+
host: ConnectableElement,
|
|
17
|
+
{ state }: { state: SignalState<BlockHandleAddProps> },
|
|
18
|
+
): void {
|
|
19
|
+
const context = blockPopoverContext.consume(host)
|
|
20
|
+
|
|
21
|
+
useEventListener(host, 'pointerdown', (event) => {
|
|
22
|
+
event.preventDefault()
|
|
23
|
+
|
|
24
|
+
const editor = state.editor.get()
|
|
25
|
+
const hoverState = context.get()
|
|
26
|
+
if (!editor || !hoverState) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { node, pos } = hoverState
|
|
31
|
+
editor.exec(insertDefaultBlock({ pos: pos + node.nodeSize }))
|
|
32
|
+
editor.focus()
|
|
33
|
+
|
|
34
|
+
// Hide the drag handle
|
|
35
|
+
context.set(null)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EventDeclarations,
|
|
3
|
+
PropDeclarations,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
import type { Editor } from '@prosekit/core'
|
|
6
|
+
|
|
7
|
+
export interface BlockHandleAddProps {
|
|
8
|
+
/**
|
|
9
|
+
* The ProseKit editor instance.
|
|
10
|
+
*
|
|
11
|
+
* @default null
|
|
12
|
+
* @hidden
|
|
13
|
+
*/
|
|
14
|
+
editor: Editor | null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
export const blockHandleAddProps: PropDeclarations<BlockHandleAddProps> = {
|
|
19
|
+
editor: { default: null },
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** @internal */
|
|
23
|
+
export interface BlockHandleAddEvents {}
|
|
24
|
+
|
|
25
|
+
/** @internal */
|
|
26
|
+
export const blockHandleAddEvents: EventDeclarations<BlockHandleAddEvents> = {}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
|
|
2
|
+
|
|
3
|
+
import { useBlockHandleDraggable } from "./setup"
|
|
4
|
+
import { blockHandleDraggableEvents, blockHandleDraggableProps, type BlockHandleDraggableEvents, type BlockHandleDraggableProps } from "./types"
|
|
5
|
+
|
|
6
|
+
const BlockHandleDraggableElementBase: BaseElementConstructor<BlockHandleDraggableProps> = defineCustomElement<
|
|
7
|
+
BlockHandleDraggableProps,
|
|
8
|
+
BlockHandleDraggableEvents
|
|
9
|
+
>({
|
|
10
|
+
props: blockHandleDraggableProps,
|
|
11
|
+
events: blockHandleDraggableEvents,
|
|
12
|
+
setup: useBlockHandleDraggable,
|
|
13
|
+
})
|
|
14
|
+
class BlockHandleDraggableElement extends BlockHandleDraggableElementBase {}
|
|
15
|
+
|
|
16
|
+
registerCustomElement('prosekit-block-handle-draggable', BlockHandleDraggableElement)
|
|
17
|
+
|
|
18
|
+
export { BlockHandleDraggableElement }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { assignStyles } from '../../../utils/assign-styles'
|
|
2
|
+
import { deepCloneElement } from '../../../utils/clone-element'
|
|
3
|
+
import { getClientRect } from '../../../utils/get-client-rect'
|
|
4
|
+
import { injectStyle } from '../../../utils/inject-style'
|
|
5
|
+
import { maxZIndex } from '../../../utils/max-z-index'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sets a drag preview image for the given element and ensures the preview position
|
|
9
|
+
* relative to the pointer is correct.
|
|
10
|
+
*
|
|
11
|
+
* This function does the following:
|
|
12
|
+
*
|
|
13
|
+
* - Creates a temporary container element.
|
|
14
|
+
* - Puts the container at the end of the document body.
|
|
15
|
+
* - Sets event's drag image.
|
|
16
|
+
* - Removes the container from the document body after the next frame.
|
|
17
|
+
*/
|
|
18
|
+
export function setDragPreview(event: DragEvent, element: HTMLElement): void {
|
|
19
|
+
const { top, bottom, left, right } = getClientRect(element)
|
|
20
|
+
const width = right - left
|
|
21
|
+
const height = bottom - top
|
|
22
|
+
const elementX = left
|
|
23
|
+
const elementY = top
|
|
24
|
+
|
|
25
|
+
const { clientX, clientY } = event
|
|
26
|
+
|
|
27
|
+
const document = element.ownerDocument
|
|
28
|
+
|
|
29
|
+
const container = document.createElement('div')
|
|
30
|
+
|
|
31
|
+
// If outsideX is positive, the point is at the left side of the element.
|
|
32
|
+
const outsideX = Math.round(elementX - clientX)
|
|
33
|
+
// If outsideY is positive, the point is above the element.
|
|
34
|
+
const outsideY = Math.round(elementY - clientY)
|
|
35
|
+
|
|
36
|
+
const borderX = Math.max(outsideX, 0)
|
|
37
|
+
const borderY = Math.max(outsideY, 0)
|
|
38
|
+
assignStyles(container, {
|
|
39
|
+
// Ensuring we don't cause reflow when adding the element to the page using
|
|
40
|
+
// `position:fixed` rather than `position:absolute` so we are positioned on
|
|
41
|
+
// the current viewport. `position:fixed` also creates a new stacking
|
|
42
|
+
// context, so we don't need to do that here.
|
|
43
|
+
// https://github.com/atlassian/pragmatic-drag-and-drop/blob/56276552/packages/core/src/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.ts#L60
|
|
44
|
+
position: 'fixed',
|
|
45
|
+
|
|
46
|
+
// The element is positioned off-screen to avoid capturing the content of
|
|
47
|
+
// the page on Safari when the dragging element has a transparent background
|
|
48
|
+
// on Safari. See https://github.com/prosekit/prosekit/issues/1153 for more
|
|
49
|
+
// details.
|
|
50
|
+
top: '-1000vh',
|
|
51
|
+
left: '-1000vw',
|
|
52
|
+
|
|
53
|
+
// The element should not be interactive.
|
|
54
|
+
pointerEvents: 'none',
|
|
55
|
+
|
|
56
|
+
zIndex: maxZIndex,
|
|
57
|
+
|
|
58
|
+
// Only reliable cross browser technique found to push a drag preview away
|
|
59
|
+
// from the cursor is to use transparent borders on the container.
|
|
60
|
+
// https://github.com/atlassian/pragmatic-drag-and-drop/blob/56276552/packages/core/src/public-utils/element/custom-native-drag-preview/pointer-outside-of-preview.ts#L13-L18
|
|
61
|
+
borderLeft: `${borderX}px solid transparent`,
|
|
62
|
+
borderTop: `${borderY}px solid transparent`,
|
|
63
|
+
|
|
64
|
+
boxSizing: 'border-box',
|
|
65
|
+
width: `${width + borderX}px`,
|
|
66
|
+
height: `${height + borderY}px`,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const [clonedElement, styleText] = deepCloneElement(element, true)
|
|
70
|
+
|
|
71
|
+
// A hardcoded opacity.
|
|
72
|
+
clonedElement.style.setProperty('opacity', '0.5', 'important')
|
|
73
|
+
// The bounding client rect doesn't include the margin, so we need to remove
|
|
74
|
+
// the margin too from the cloned element so that it can fit the container.
|
|
75
|
+
clonedElement.style.setProperty('margin', '0', 'important')
|
|
76
|
+
// Hide the outline of the cloned element.
|
|
77
|
+
clonedElement.style.setProperty('outline-color', 'transparent', 'important')
|
|
78
|
+
|
|
79
|
+
document.body.appendChild(container)
|
|
80
|
+
container.appendChild(clonedElement)
|
|
81
|
+
injectStyle(container, styleText)
|
|
82
|
+
|
|
83
|
+
event.dataTransfer?.setDragImage(container, Math.max(-outsideX, 0), Math.max(-outsideY, 0))
|
|
84
|
+
|
|
85
|
+
requestAnimationFrame(() => {
|
|
86
|
+
container.remove()
|
|
87
|
+
})
|
|
88
|
+
}
|