@prosekit/web 0.8.0-beta.6 → 0.8.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 (38) hide show
  1. package/dist/autocomplete.d.ts +19 -2
  2. package/dist/autocomplete.d.ts.map +1 -1
  3. package/dist/autocomplete.js +30 -17
  4. package/dist/autocomplete.js.map +1 -1
  5. package/dist/block-handle.d.ts.map +1 -1
  6. package/dist/block-handle.js +16 -10
  7. package/dist/block-handle.js.map +1 -1
  8. package/dist/drop-indicator.js.map +1 -1
  9. package/dist/get-safe-editor-view.js.map +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/inline-popover.js +4 -11
  12. package/dist/inline-popover.js.map +1 -1
  13. package/dist/menu.js.map +1 -1
  14. package/dist/popover.js.map +1 -1
  15. package/dist/resizable.js.map +1 -1
  16. package/dist/table-handle.js +11 -22
  17. package/dist/table-handle.js.map +1 -1
  18. package/dist/tooltip.js.map +1 -1
  19. package/dist/use-editor-extension.js.map +1 -1
  20. package/dist/use-editor-update-event.js +11 -0
  21. package/dist/use-editor-update-event.js.map +1 -0
  22. package/dist/use-scrolling.js.map +1 -1
  23. package/package.json +10 -10
  24. package/src/components/autocomplete/autocomplete-positioner.ts +14 -5
  25. package/src/components/autocomplete/autocomplete-root.ts +36 -13
  26. package/src/components/block-handle/block-handle-add.ts +1 -1
  27. package/src/components/block-handle/block-handle-draggable.ts +1 -1
  28. package/src/components/block-handle/block-handle-positioner.ts +1 -1
  29. package/src/components/block-handle/block-handle-root.ts +5 -2
  30. package/src/components/block-handle/use-has-text-selection.ts +13 -0
  31. package/src/components/inline-popover/inline-popover-positioner.ts +1 -1
  32. package/src/components/inline-popover/inline-popover-root.ts +1 -1
  33. package/src/components/table-handle/shared.ts +6 -6
  34. package/src/components/table-handle/table-handle-column-menu-trigger.ts +1 -1
  35. package/src/components/table-handle/table-handle-drag-preview.ts +1 -1
  36. package/src/components/table-handle/table-handle-drop-indicator.ts +1 -1
  37. package/src/components/table-handle/table-handle-root.ts +1 -1
  38. package/src/components/table-handle/table-handle-row-menu-trigger.ts +1 -1
@@ -13,6 +13,7 @@ import {
13
13
  import { defaultItemFilter, type ItemFilter, type ListboxRootEvents } from '@aria-ui/elements/listbox'
14
14
  import { createOverlayStore, OpenChangeEvent, type OverlayStore } from '@aria-ui/elements/overlay'
15
15
  import { useEventListener } from '@aria-ui/utils'
16
+ import type { ReferenceElement, VirtualElement } from '@floating-ui/dom'
16
17
  import { defineDOMEventHandler, defineKeymap, withPriority, type Editor, type Extension, type Priority } from '@prosekit/core'
17
18
  import { AutocompleteRule, defineAutocomplete, type MatchHandler } from '@prosekit/extensions/autocomplete'
18
19
 
@@ -48,15 +49,26 @@ export interface AutocompleteRootProps {
48
49
  * @default defaultItemFilter
49
50
  */
50
51
  filter: ItemFilter | null
52
+
53
+ /**
54
+ * The reference to position the popup against. This can be a DOM element, a
55
+ * Floating UI virtual element, or a function that returns either of them.
56
+ * By default, the popup will be positioned against the text content that
57
+ * triggers the autocomplete.
58
+ *
59
+ * @default null
60
+ */
61
+ anchor: Element | VirtualElement | (() => Element | VirtualElement | null) | null
51
62
  }
52
63
 
53
64
  /** @internal */
54
65
  export const AutocompleteRootPropsDeclaration: PropsDeclaration<AutocompleteRootProps> = /* @__PURE__ */ defineProps<
55
66
  AutocompleteRootProps
56
67
  >({
57
- editor: { default: null, attribute: false, type: 'json' },
58
- regex: { default: null, attribute: false, type: 'json' },
59
- filter: { default: defaultItemFilter, attribute: false, type: 'json' },
68
+ editor: { default: null, attribute: false },
69
+ regex: { default: null, attribute: false },
70
+ filter: { default: defaultItemFilter, attribute: false },
71
+ anchor: { default: null, attribute: false },
60
72
  })
61
73
 
62
74
  /**
@@ -95,7 +107,7 @@ interface RuleHandlers {
95
107
  }
96
108
 
97
109
  interface AutocompleteRuleDeps {
98
- reference: Signal<Element | undefined>
110
+ reference: Signal<ReferenceElement | undefined>
99
111
  handlers: RuleHandlers
100
112
  setQuery: (next: string) => void
101
113
  requestOpenChange: (open: boolean) => void
@@ -110,7 +122,7 @@ export function setupAutocompleteRoot(
110
122
  ): void {
111
123
  const getEditor = props.editor.get
112
124
 
113
- const reference = createSignal<Element | undefined>(undefined)
125
+ const reference = createSignal<ReferenceElement | undefined>(undefined)
114
126
  const open = createSignal(false)
115
127
  const query = createSignal('')
116
128
  const keyboardTarget = new KeyboardEventTarget()
@@ -159,7 +171,20 @@ export function setupAutocompleteRoot(
159
171
  host.dispatchEvent(new QueryChangeEvent(next))
160
172
  }
161
173
 
162
- useAutocompleteExtension(host, getEditor, props.regex.get, {
174
+ const getAnchor = (): ReferenceElement | null => {
175
+ const customAnchor = props.anchor.get()
176
+ if (customAnchor) {
177
+ if (typeof customAnchor === 'function') {
178
+ return customAnchor() || null
179
+ } else {
180
+ return customAnchor
181
+ }
182
+ }
183
+ const view = getSafeEditorView(getEditor())
184
+ return view?.dom.querySelector('.prosekit-autocomplete-match') || null
185
+ }
186
+
187
+ useAutocompleteExtension(host, getEditor, props.regex.get, getAnchor, {
163
188
  reference,
164
189
  handlers,
165
190
  setQuery,
@@ -202,6 +227,7 @@ function useAutocompleteExtension(
202
227
  host: HostElement,
203
228
  getEditor: () => Editor | null,
204
229
  getRegex: () => RegExp | null,
230
+ getAnchor: () => ReferenceElement | null,
205
231
  deps: AutocompleteRuleDeps,
206
232
  ) {
207
233
  useEffect(host, () => {
@@ -212,7 +238,7 @@ function useAutocompleteExtension(
212
238
  return
213
239
  }
214
240
 
215
- const rule = createAutocompleteRule(editor, regex, deps)
241
+ const rule = createAutocompleteRule(editor, regex, getAnchor, deps)
216
242
  const extension = defineAutocomplete(rule)
217
243
  return editor.use(extension)
218
244
  })
@@ -221,17 +247,14 @@ function useAutocompleteExtension(
221
247
  function createAutocompleteRule(
222
248
  editor: Editor,
223
249
  regex: RegExp,
250
+ getAnchor: () => ReferenceElement | null,
224
251
  deps: AutocompleteRuleDeps,
225
252
  ) {
226
253
  const { reference, handlers, setQuery, requestOpenChange } = deps
227
254
 
228
255
  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
- }
256
+ const anchor = getAnchor()
257
+ reference.set(anchor || undefined)
235
258
 
236
259
  handlers.submit = options.deleteMatch
237
260
  handlers.dismiss = options.ignoreMatch
@@ -24,7 +24,7 @@ export interface BlockHandleAddProps {
24
24
 
25
25
  /** @internal */
26
26
  export const BlockHandleAddPropsDeclaration: PropsDeclaration<BlockHandleAddProps> = /* @__PURE__ */ defineProps<BlockHandleAddProps>({
27
- editor: { default: null, attribute: false, type: 'json' },
27
+ editor: { default: null, attribute: false },
28
28
  })
29
29
 
30
30
  /**
@@ -37,7 +37,7 @@ export interface BlockHandleDraggableProps {
37
37
  export const BlockHandleDraggablePropsDeclaration: PropsDeclaration<BlockHandleDraggableProps> = /* @__PURE__ */ defineProps<
38
38
  BlockHandleDraggableProps
39
39
  >({
40
- editor: { default: null, attribute: false, type: 'json' },
40
+ editor: { default: null, attribute: false },
41
41
  })
42
42
 
43
43
  /**
@@ -59,7 +59,7 @@ export const BlockHandlePositionerPropsDeclaration: PropsDeclaration<BlockHandle
59
59
  // Enabling `hoist` will cause the popover to have a small delay when
60
60
  // scrolling the page.
61
61
  hoist: { default: false, attribute: 'hoist', type: 'boolean' },
62
- flip: { default: false, attribute: false, type: 'json' },
62
+ flip: { default: false, attribute: false },
63
63
  shift: { default: false, attribute: 'shift', type: 'boolean' },
64
64
  hide: { default: true, attribute: 'hide', type: 'boolean' },
65
65
  })
@@ -18,6 +18,7 @@ import type { ProseMirrorNode } from '@prosekit/pm/model'
18
18
  import { useScrolling } from '../../hooks/use-scrolling.ts'
19
19
 
20
20
  import { blockHandleOverlayStoreContext, BlockHandleStore, blockHandleStoreContext } from './context.ts'
21
+ import { useHasTextSelection } from './use-has-text-selection.ts'
21
22
  import { useHoverExtension } from './use-hover-extension.ts'
22
23
 
23
24
  export interface BlockHandleRootProps {
@@ -34,7 +35,7 @@ export interface BlockHandleRootProps {
34
35
  export const BlockHandleRootPropsDeclaration: PropsDeclaration<BlockHandleRootProps> = /* @__PURE__ */ defineProps<
35
36
  BlockHandleRootProps
36
37
  >({
37
- editor: { default: null, attribute: false, type: 'json' },
38
+ editor: { default: null, attribute: false },
38
39
  })
39
40
 
40
41
  /**
@@ -75,8 +76,10 @@ export function setupBlockHandleRoot(
75
76
 
76
77
  const reference = createSignal<VirtualElement | undefined>(undefined)
77
78
  const getScrolling = useScrolling(host)
79
+ // Hide the block handle when there is a text selection to avoid the block handle overlapping with inline menu
80
+ const getHasTextSelection = useHasTextSelection(host, getEditor)
78
81
 
79
- const getOpen = computed(() => !!store.hoverState.get() && !getScrolling())
82
+ const getOpen = computed(() => !!store.hoverState.get() && !getScrolling() && !getHasTextSelection())
80
83
 
81
84
  const overlayStore = createOverlayStore(
82
85
  getOpen,
@@ -0,0 +1,13 @@
1
+ import { createSignal, type HostElement } from '@aria-ui/core'
2
+ import { isTextSelection, type Editor } from '@prosekit/core'
3
+
4
+ import { useEditorUpdateEvent } from '../../hooks/use-editor-update-event.ts'
5
+
6
+ export function useHasTextSelection(host: HostElement, getEditor: () => Editor | null): () => boolean {
7
+ const state = createSignal(false)
8
+ useEditorUpdateEvent(host, getEditor, (view) => {
9
+ const { selection } = view.state
10
+ state.set(!selection.empty && isTextSelection(selection))
11
+ })
12
+ return state.get
13
+ }
@@ -86,7 +86,7 @@ export const InlinePopoverPositionerPropsDeclaration: PropsDeclaration<InlinePop
86
86
  >({
87
87
  ...OverlayPositionerPropsDeclaration,
88
88
  placement: { default: 'top', attribute: 'placement', type: 'string' },
89
- offset: { default: 12, attribute: false, type: 'json' },
89
+ offset: { default: 12, attribute: false },
90
90
  hide: { default: true, attribute: 'hide', type: 'boolean' },
91
91
  hoist: { default: false, attribute: 'hoist', type: 'boolean' },
92
92
  overlap: { default: true, attribute: 'overlap', type: 'boolean' },
@@ -53,7 +53,7 @@ export const InlinePopoverRootPropsDeclaration: PropsDeclaration<InlinePopoverRo
53
53
  InlinePopoverRootProps
54
54
  >({
55
55
  ...OverlayRootPropsDeclaration,
56
- editor: { default: null, attribute: false, type: 'json' },
56
+ editor: { default: null, attribute: false },
57
57
  defaultOpen: { default: true, attribute: 'default-open', type: 'boolean' },
58
58
  dismissOnEscape: { default: true, attribute: 'dismiss-on-escape', type: 'boolean' },
59
59
  })
@@ -52,10 +52,10 @@ export const SharedTableHandlePositionerPropsDeclaration: PropsDeclaration<Share
52
52
  SharedTableHandlePositionerProps
53
53
  >({
54
54
  ...OverlayPositionerPropsDeclaration,
55
- editor: { default: null, attribute: false, type: 'json' },
56
- hoist: { default: false, attribute: false, type: 'boolean' },
57
- flip: { default: false, attribute: false, type: 'json' },
58
- shift: { default: false, attribute: false, type: 'boolean' },
59
- hide: { default: true, attribute: false, type: 'boolean' },
60
- offset: { default: 0, attribute: false, type: 'json' },
55
+ editor: { default: null, attribute: false },
56
+ hoist: { default: false, attribute: false },
57
+ flip: { default: false, attribute: false },
58
+ shift: { default: false, attribute: false },
59
+ hide: { default: true, attribute: false },
60
+ offset: { default: 0, attribute: false },
61
61
  })
@@ -31,7 +31,7 @@ export interface TableHandleColumnMenuTriggerProps {
31
31
  export const TableHandleColumnMenuTriggerPropsDeclaration: PropsDeclaration<TableHandleColumnMenuTriggerProps> = defineProps<
32
32
  TableHandleColumnMenuTriggerProps
33
33
  >({
34
- editor: { default: null, attribute: false, type: 'json' },
34
+ editor: { default: null, attribute: false },
35
35
  })
36
36
 
37
37
  /** @internal */
@@ -30,7 +30,7 @@ export interface TableHandleDragPreviewProps {
30
30
  export const TableHandleDragPreviewPropsDeclaration: PropsDeclaration<TableHandleDragPreviewProps> = defineProps<
31
31
  TableHandleDragPreviewProps
32
32
  >({
33
- editor: { default: null, attribute: false, type: 'json' },
33
+ editor: { default: null, attribute: false },
34
34
  })
35
35
 
36
36
  /**
@@ -35,7 +35,7 @@ export interface TableHandleDropIndicatorProps {
35
35
  export const TableHandleDropIndicatorPropsDeclaration: PropsDeclaration<TableHandleDropIndicatorProps> = defineProps<
36
36
  TableHandleDropIndicatorProps
37
37
  >({
38
- editor: { default: null, attribute: false, type: 'json' },
38
+ editor: { default: null, attribute: false },
39
39
  })
40
40
 
41
41
  /**
@@ -33,7 +33,7 @@ export interface TableHandleRootProps {
33
33
 
34
34
  /** @internal */
35
35
  export const TableHandleRootPropsDeclaration: PropsDeclaration<TableHandleRootProps> = defineProps<TableHandleRootProps>({
36
- editor: { default: null, attribute: false, type: 'json' },
36
+ editor: { default: null, attribute: false },
37
37
  })
38
38
 
39
39
  /**
@@ -31,7 +31,7 @@ export interface TableHandleRowMenuTriggerProps {
31
31
  export const TableHandleRowMenuTriggerPropsDeclaration: PropsDeclaration<TableHandleRowMenuTriggerProps> = defineProps<
32
32
  TableHandleRowMenuTriggerProps
33
33
  >({
34
- editor: { default: null, attribute: false, type: 'json' },
34
+ editor: { default: null, attribute: false },
35
35
  })
36
36
 
37
37
  /** @internal */