@domternal/extension-block-menu 0.7.0 → 0.7.2
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/README.md +1 -1
- package/dist/index.cjs +13 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +13 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/FloatingMenu.ts","../src/helpers/findTopLevelBlock.ts","../src/helpers/expandToEmptyWrappers.ts","../src/helpers/convertListItemForParent.ts","../src/helpers/moveBlock.ts","../src/helpers/moveBlockAsNestedChild.ts","../src/helpers/dragGhost.ts","../src/helpers/clampCoords.ts","../src/helpers/gutterBias.ts","../src/helpers/defaultMatchers.ts","../src/helpers/resolveDragTarget.ts","../src/BlockHandle.ts","../src/KeyboardReorder.ts","../src/helpers/blockOperations.ts","../src/helpers/turnIntoWrapper.ts","../src/BlockContextMenu.ts","../src/createSlashSuggestionRenderer.ts","../src/SlashCommand.ts","../src/SmartPaste.ts"],"names":["node","content","Fragment","LIST_ITEM_TYPES","PluginKey","midY","Plugin","Extension","TextSelection","defaultIcons","positionFloatingOnce","DecorationSet","Decoration"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Block-insert menu shown when the cursor sits at the start of an empty\n * paragraph. Items collected via `addFloatingMenuItems()`. This file owns\n * visibility, positioning, dismiss, and keyboard entry; framework wrappers\n * render the UI.\n */\nimport { Extension, positionFloatingOnce } from '@domternal/core';\nimport type { Editor, FloatingMenuItemsOverride } from '@domternal/core';\nimport { Plugin, PluginKey } from '@domternal/pm/state';\nimport type { EditorView } from '@domternal/pm/view';\nimport type { EditorState } from '@domternal/pm/state';\n\nexport const floatingMenuPluginKey = new PluginKey('floatingMenu');\n\n/**\n * Default visibility predicate. Shows the menu when the cursor is at the\n * very start of an empty `paragraph` in an editable editor.\n */\nfunction defaultShouldShow({\n editor,\n state,\n}: {\n editor: Editor;\n view: EditorView;\n state: EditorState;\n}): boolean {\n if (!editor.isEditable) return false;\n const { selection } = state;\n const { $from, empty } = selection;\n if (!empty) return false;\n if ($from.parent.type.name !== 'paragraph') return false;\n if ($from.parent.content.size !== 0) return false;\n if ($from.parentOffset !== 0) return false;\n return true;\n}\n\n/**\n * Keyboard shortcuts that move focus from the editor into the menu.\n * Defaults combine the WAI-ARIA recommendation (`Alt-F10`) with a\n * modern slash-command-friendly shortcut (`Mod-/`). Set to an empty\n * array to disable keyboard entry entirely.\n */\nexport interface FloatingMenuKeymap {\n /** Shortcuts that focus the first menu item when the menu is visible. */\n enterMenu?: string[];\n}\n\nconst DEFAULT_ENTER_MENU_SHORTCUTS: string[] = ['Alt-F10', 'Mod-/'];\n\nexport interface FloatingMenuOptions {\n /**\n * The HTML element that contains the menu. Required when used directly;\n * framework wrappers create this element and pass it in.\n */\n element: HTMLElement | null;\n\n /**\n * Visibility predicate. Defaults to `defaultShouldShow` (empty paragraph\n * at cursor start).\n */\n shouldShow: (props: {\n editor: Editor;\n view: EditorView;\n state: EditorState;\n }) => boolean;\n\n /**\n * Pixel offset from the anchor. @default 0\n */\n offset: number;\n\n /**\n * Items override. Array replaces defaults entirely; function receives\n * the collected defaults and returns a new list (filter/reorder/extend).\n * Consumed by the controller; the plugin itself only reads it when the\n * wrapper does not construct its own controller.\n */\n items?: FloatingMenuItemsOverride;\n\n /** Keyboard shortcuts for entering the menu via keyboard. */\n keymap?: FloatingMenuKeymap;\n\n /**\n * When `true`, the menu only appears when EXPLICITLY triggered via\n * `showFloatingMenu(view)` (typically from BlockHandle's `+` button).\n * Pressing `Enter` to create a new empty paragraph no longer auto-shows\n * the menu. Mirrors Notion's behaviour: empty rows display a placeholder\n * hint, the slash command (`/`) is the keyboard trigger, and the menu\n * opens via the gutter `+` button only.\n *\n * @default false (auto-shows on every empty paragraph - backward compat)\n */\n requireExplicitTrigger?: boolean;\n}\n\nexport interface CreateFloatingMenuPluginOptions {\n pluginKey: PluginKey;\n editor: Editor;\n element: HTMLElement;\n shouldShow?: FloatingMenuOptions['shouldShow'];\n offset?: number;\n keymap?: FloatingMenuKeymap | undefined;\n requireExplicitTrigger?: boolean;\n}\n\n/** Internal plugin state - tracks whether `+` button explicitly triggered the menu. */\ninterface FloatingMenuPluginState {\n triggered: boolean;\n}\n\n/**\n * String meta key used by `showFloatingMenu` / `hideFloatingMenu`. We\n * use a STRING (not a PluginKey) so callers don't need a reference to\n * the specific plugin instance - framework wrappers (angular, react,\n * vue) create their own per-instance PluginKey via random suffix to\n * disambiguate menus across editors, but they all read this shared\n * string meta. The plugin's `state.apply` listens for it.\n */\nexport const FLOATING_MENU_META = 'dm:floatingMenuTrigger';\n\n/**\n * Programmatically show the FloatingMenu - used by BlockHandle's `+`\n * button after it inserts a fresh empty paragraph. When the plugin is\n * configured with `requireExplicitTrigger: true`, this is the ONLY way\n * the menu opens (besides the existing `Mod-/` keyboard shortcut, which\n * is unaffected and continues to focus an already-visible menu).\n */\nexport function showFloatingMenu(view: EditorView): void {\n view.dispatch(view.state.tr.setMeta(FLOATING_MENU_META, 'show'));\n}\n\n/** Programmatically hide the FloatingMenu (clears the explicit-trigger flag). */\nexport function hideFloatingMenu(view: EditorView): void {\n view.dispatch(view.state.tr.setMeta(FLOATING_MENU_META, 'hide'));\n}\n\n// Cache platform check at module load rather than per-keystroke.\nconst IS_MAC = typeof navigator !== 'undefined'\n && /Mac|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n/**\n * Parses a shortcut string (e.g. `Alt-F10`, `Mod-/`, `Shift-Ctrl-Enter`)\n * against a KeyboardEvent. Matches prosemirror-keymap's grammar:\n *\n * - Modifiers can appear in any order and separated by `-`.\n * - `Mod` maps to Cmd on macOS, Ctrl elsewhere.\n * - Aliases: `Cmd` / `m` / `Meta`, `Ctrl` / `c` / `Control`, `Alt` / `a`,\n * `Shift` / `s`.\n * - Named keys use `KeyEvent.key` values directly (e.g. `F10`, `Enter`,\n * `ArrowUp`). Letters are case-insensitive; `Shift-` prefix is implied\n * for shifted-character keys.\n *\n * @returns true if the event matches the shortcut exactly (all and only\n * the listed modifiers, same key).\n */\nfunction matchShortcut(event: KeyboardEvent, shortcut: string): boolean {\n const parts = shortcut.split('-');\n let keyPart = parts.pop();\n if (!keyPart) return false;\n // prosemirror-keymap convention: `Space` is an alias for ' ' since the\n // literal character is awkward to type in a shortcut string.\n if (keyPart === 'Space') keyPart = ' ';\n\n let needCtrl = false;\n let needMeta = false;\n let needAlt = false;\n let needShift = false;\n\n for (const mod of parts) {\n switch (mod) {\n case 'Mod':\n case 'mod':\n if (IS_MAC) needMeta = true;\n else needCtrl = true;\n break;\n case 'Cmd':\n case 'cmd':\n case 'Meta':\n case 'meta':\n case 'm':\n needMeta = true;\n break;\n case 'Ctrl':\n case 'ctrl':\n case 'Control':\n case 'control':\n case 'c':\n needCtrl = true;\n break;\n case 'Alt':\n case 'alt':\n case 'a':\n needAlt = true;\n break;\n case 'Shift':\n case 'shift':\n case 's':\n needShift = true;\n break;\n default:\n return false;\n }\n }\n\n if (event.altKey !== needAlt) return false;\n if (event.ctrlKey !== needCtrl) return false;\n if (event.metaKey !== needMeta) return false;\n // For single-character keys, ignore Shift (since Shift is part of the\n // character itself, e.g. Shift+/ produces `?`). For named keys (F10,\n // ArrowUp, Enter, etc.), require Shift match exactly.\n if (keyPart.length > 1 && event.shiftKey !== needShift) return false;\n\n return event.key === keyPart || event.key.toLowerCase() === keyPart.toLowerCase();\n}\n\n/**\n * Creates a standalone FloatingMenu ProseMirror plugin. Framework wrappers\n * call this directly so they can own element creation and rendering.\n */\nexport function createFloatingMenuPlugin(options: CreateFloatingMenuPluginOptions): Plugin {\n const {\n pluginKey,\n editor,\n element,\n shouldShow = defaultShouldShow,\n offset = 0,\n keymap,\n requireExplicitTrigger = false,\n } = options;\n\n const enterShortcuts = keymap?.enterMenu ?? DEFAULT_ENTER_MENU_SHORTCUTS;\n\n // Semantic defaults: `menu` is the right WAI-ARIA role for a transient\n // list of single-action choices (unlike `toolbar` which implies a\n // persistent set of controls).\n if (!element.getAttribute('role')) {\n element.setAttribute('role', 'menu');\n element.setAttribute('aria-label', 'Insert block');\n }\n\n let cleanupFloating: (() => void) | null = null;\n let editorEl: Element | null = null;\n let clickOutsideHandler: ((e: Event) => void) | null = null;\n let dismissOverlayHandler: (() => void) | null = null;\n\n const isVisible = (): boolean => element.hasAttribute('data-show');\n\n const updatePosition = (view: EditorView): void => {\n const { selection } = view.state;\n const { $from } = selection;\n const depth = $from.depth;\n const startPos = $from.start(depth);\n const domNode = view.nodeDOM(startPos - 1);\n if (domNode instanceof HTMLElement) {\n cleanupFloating?.();\n cleanupFloating = positionFloatingOnce(domNode, element, {\n placement: 'bottom-start',\n offsetValue: offset,\n });\n element.setAttribute('data-show', '');\n }\n };\n\n const hideMenu = (): void => {\n cleanupFloating?.();\n cleanupFloating = null;\n element.removeAttribute('data-show');\n };\n\n // Focus first menuitem. Wrappers mark each item with\n // `data-floating-menu-item`; falls back to any focusable descendant.\n const focusFirstItem = (): boolean => {\n const first =\n element.querySelector<HTMLElement>('[data-floating-menu-item]:not([aria-disabled=\"true\"])')\n ?? element.querySelector<HTMLElement>('button, [tabindex]:not([tabindex=\"-1\"])');\n if (!first) return false;\n first.focus();\n return true;\n };\n\n // Hide initially (wrappers may render the element before the plugin runs).\n hideMenu();\n\n // Compute final visibility: when `requireExplicitTrigger` is on, both\n // the explicit-trigger flag AND the user-supplied shouldShow predicate\n // must be true. Otherwise (default), only shouldShow gates visibility.\n const isVisibleNow = (view: EditorView): boolean => {\n const wantsShow = shouldShow({ editor, view, state: view.state });\n if (!requireExplicitTrigger) return wantsShow;\n const triggered = (pluginKey.getState(view.state) as FloatingMenuPluginState | undefined)?.triggered ?? false;\n return triggered && wantsShow;\n };\n\n return new Plugin<FloatingMenuPluginState>({\n key: pluginKey,\n\n state: {\n init: (): FloatingMenuPluginState => ({ triggered: false }),\n apply: (tr, prev): FloatingMenuPluginState => {\n const meta = tr.getMeta(FLOATING_MENU_META) as unknown;\n if (meta === 'show') return { triggered: true };\n if (meta === 'hide') return { triggered: false };\n return prev;\n },\n },\n\n props: {\n // Keyboard entry from the editor. ProseMirror's handleKeyDown fires\n // before browser defaults, so we can intercept without risking\n // interference with typing. We only act while the menu is visible.\n handleKeyDown(_view, event): boolean {\n if (!isVisible()) return false;\n for (const shortcut of enterShortcuts) {\n if (matchShortcut(event, shortcut)) {\n if (focusFirstItem()) {\n event.preventDefault();\n return true;\n }\n return false;\n }\n }\n return false;\n },\n },\n\n view: (editorView) => {\n // Move the menu into `.dm-editor` so `position:absolute` resolves\n // against the scrollable editor container - zero jitter on scroll.\n editorEl = editorView.dom.closest('.dm-editor');\n if (editorEl && element.parentElement !== editorEl) {\n editorEl.appendChild(element);\n }\n\n // Hide the menu AND clear the explicit-trigger flag so a stale\n // `triggered=true` doesn't survive across an unrelated dismissal.\n const dismiss = (): void => {\n hideMenu();\n if (requireExplicitTrigger) {\n const triggered = (pluginKey.getState(editor.view.state) as FloatingMenuPluginState | undefined)?.triggered ?? false;\n if (triggered) {\n editor.view.dispatch(editor.view.state.tr.setMeta(FLOATING_MENU_META, 'hide'));\n }\n }\n };\n\n const onFocus = (): void => {\n if (isVisibleNow(editor.view)) updatePosition(editor.view);\n else dismiss();\n };\n\n const onBlur = ({ event }: { event: FocusEvent }): void => {\n // Keep the menu visible if focus moved into it - users can\n // interact with menu items without the menu vanishing.\n // `relatedTarget` is `EventTarget | null`, not `Node` - guard with\n // an `instanceof Node` check so `.contains()` receives a valid arg\n // even for exotic focus targets (e.g. AbortSignal-based targets\n // never raise a focus event in practice, but the cast is unsound).\n const related = event.relatedTarget;\n if (related instanceof Node && element.contains(related)) return;\n dismiss();\n };\n\n // Click-outside dismissal. Capture phase ensures we fire before\n // other UI (dropdowns, popovers) handles the same click.\n clickOutsideHandler = (e: Event): void => {\n if (!isVisible()) return;\n const target = e.target;\n if (!(target instanceof Node)) return;\n if (element.contains(target)) return;\n if (editor.view.dom.contains(target)) return;\n dismiss();\n };\n document.addEventListener('mousedown', clickOutsideHandler, true);\n\n // Cooperative dismissal: other overlays (toolbar dropdowns,\n // popovers) broadcast this event to close any open chrome.\n if (editorEl) {\n dismissOverlayHandler = (): void => { dismiss(); };\n editorEl.addEventListener('dm:dismiss-overlays', dismissOverlayHandler);\n }\n\n editor.on('focus', onFocus);\n editor.on('blur', onBlur);\n\n return {\n update: (view) => {\n if (isVisibleNow(view)) updatePosition(view);\n else {\n hideMenu();\n // Auto-clear stale `triggered` state when the user navigates\n // away from the empty paragraph (e.g. types a character or\n // moves the cursor) - otherwise the next empty paragraph\n // they enter would silently re-show the menu.\n if (requireExplicitTrigger) {\n const triggered = (pluginKey.getState(view.state) as FloatingMenuPluginState | undefined)?.triggered ?? false;\n if (triggered) {\n view.dispatch(view.state.tr.setMeta(FLOATING_MENU_META, 'hide'));\n }\n }\n }\n },\n\n destroy: () => {\n hideMenu();\n editor.off('focus', onFocus);\n editor.off('blur', onBlur);\n if (clickOutsideHandler) {\n document.removeEventListener('mousedown', clickOutsideHandler, true);\n clickOutsideHandler = null;\n }\n if (dismissOverlayHandler && editorEl) {\n editorEl.removeEventListener('dm:dismiss-overlays', dismissOverlayHandler);\n dismissOverlayHandler = null;\n }\n editorEl = null;\n },\n };\n },\n });\n}\n\nexport const FloatingMenu = Extension.create<FloatingMenuOptions>({\n name: 'floatingMenu',\n\n addOptions() {\n return {\n element: null,\n shouldShow: defaultShouldShow,\n offset: 0,\n requireExplicitTrigger: false,\n };\n },\n\n addProseMirrorPlugins() {\n const { element, shouldShow, offset, keymap, requireExplicitTrigger } = this.options;\n if (!element) return [];\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n\n return [\n createFloatingMenuPlugin({\n pluginKey: floatingMenuPluginKey,\n editor,\n element,\n shouldShow,\n offset,\n keymap,\n ...(requireExplicitTrigger !== undefined && { requireExplicitTrigger }),\n }),\n ];\n },\n});\n","import type { Node } from '@domternal/pm/model';\nimport type { EditorView } from '@domternal/pm/view';\n\nimport type { BlockCandidate, BlockMatcher } from './blockMatcher.js';\n\n/**\n * Information about a top-level block in the document.\n */\nexport interface TopLevelBlock {\n /** The block node. */\n node: Node;\n /** Absolute position of the block (its start). */\n pos: number;\n /** Absolute position one past the block end (= pos + node.nodeSize). */\n end: number;\n /** Zero-based index among doc children. */\n index: number;\n}\n\n/**\n * Resolves the top-level block (direct child of the document) that contains\n * a given absolute position. Returns `null` when `pos` resolves to the\n * document itself (depth 0) or is out of bounds.\n */\nexport function findTopLevelBlock(doc: Node, pos: number): TopLevelBlock | null {\n if (pos < 0 || pos > doc.content.size) return null;\n const $pos = doc.resolve(pos);\n\n // Position exactly at a top-level boundary (between blocks, or at doc\n // start). `doc.nodeAt(pos)` returns the node that starts at this position.\n if ($pos.depth === 0) {\n const node = doc.nodeAt(pos);\n if (!node) return null;\n return {\n node,\n pos,\n end: pos + node.nodeSize,\n index: $pos.index(0),\n };\n }\n\n const node = $pos.node(1);\n const blockPos = $pos.before(1);\n const index = $pos.index(0);\n return {\n node,\n pos: blockPos,\n end: blockPos + node.nodeSize,\n index,\n };\n}\n\n/**\n * Resolves the deepest ancestor whose node type name appears in\n * `draggableTypes`. Falls back to `findTopLevelBlock` (depth-1 walk) if no\n * ancestor in the list matches.\n *\n * Used by `BlockHandle` when the `nested` option is active: the plugin\n * hovers over list items / task items individually instead of always\n * anchoring on the whole list.\n *\n * Walking is deepest-first so nested lists resolve to the innermost\n * matching item (the one the cursor is actually inside).\n */\nexport function findDraggableBlock(\n doc: Node,\n pos: number,\n draggableTypes: string[],\n): TopLevelBlock | null {\n if (pos < 0 || pos > doc.content.size) return null;\n if (draggableTypes.length === 0) return findTopLevelBlock(doc, pos);\n const $pos = doc.resolve(pos);\n\n // Walk ancestors from deepest to shallowest (skip depth 0 = doc itself).\n for (let depth = $pos.depth; depth >= 1; depth--) {\n const node = $pos.node(depth);\n if (draggableTypes.includes(node.type.name)) {\n const blockPos = $pos.before(depth);\n // The \"index\" for a nested draggable is its index within its direct\n // parent - consistent with what the block's drag logic expects when\n // reordering siblings.\n const index = $pos.index(depth - 1);\n return {\n node,\n pos: blockPos,\n end: blockPos + node.nodeSize,\n index,\n };\n }\n }\n\n // No allowed-node ancestor found - fall back to the top-level block so\n // hover/drag still works for plain paragraphs outside any container.\n return findTopLevelBlock(doc, pos);\n}\n\n/**\n * Spatial result returned by {@link findDeepestBlockAtY}.\n */\nexport interface DeepestBlockMatch {\n node: Node;\n pos: number;\n dom: HTMLElement;\n rect: DOMRect;\n}\n\n/**\n * Finds the **deepest (innermost)** block at a given client Y coordinate\n * by walking the doc tree and comparing each node's DOM rect against\n * `clientY`. Among all blocks whose vertical rect contains `clientY`\n * AND whose type appears in `allowedTypes`, the one with the **smallest\n * height** wins (innermost in a vertical block layout).\n *\n * X is intentionally ignored - the gutter where the BlockHandle visually\n * lives sits to the left of `.ProseMirror`, so any X-based resolution\n * (`posAtCoords`, point-in-rect tests) would resolve to whatever happens\n * to be at the editor's left edge, which is the OUTER block when nested\n * lists are indented further right. This is the deepest-match behaviour:\n * the handle anchors on the row the cursor is actually in, regardless of\n * how far left the cursor strayed.\n *\n * The opposite policy - gutter bias (penalise depth near the left edge so\n * shallower ancestors win) - is exposed here as Mode C (`promoteOnEdge`)\n * and uses {@link ./resolveDragTarget resolveDragTarget} instead.\n *\n * `matchers` (default `[]`) shares the same `BlockMatcher[]` contract Mode C\n * applies; here only the `'reject'` verdict matters (a rejected candidate is\n * skipped, the walker continues). This keeps exclusion behaviour (e.g.\n * `firstChildOfListItem`) consistent between modes B and C: when a host\n * extends `allowedTypes` to include `paragraph`, the label paragraph of a\n * list item is automatically excluded so the handle still resolves to the\n * list item itself.\n *\n * Returns `null` when no allowed block contains `clientY` (e.g. cursor is\n * above the first block, below the last, or hovering a top-level node not\n * in `allowedTypes`). Callers should treat `null` as \"fall through to\n * top-level resolution\".\n */\nexport function findDeepestBlockAtY(\n view: EditorView,\n clientY: number,\n allowedTypes: string[],\n matchers: readonly BlockMatcher[] = [],\n): DeepestBlockMatch | null {\n if (allowedTypes.length === 0) return null;\n let best: DeepestBlockMatch | null = null;\n view.state.doc.descendants((node, pos, parent, index) => {\n const dom = view.nodeDOM(pos);\n if (!(dom instanceof HTMLElement)) return true;\n const rect = dom.getBoundingClientRect();\n // Skip the entire subtree when the cursor isn't vertically inside this\n // node - children of a non-containing parent can't contain the cursor\n // either, so pruning here is what keeps the walk O(depth) instead of\n // O(doc).\n if (clientY < rect.top || clientY > rect.bottom) return false;\n if (allowedTypes.includes(node.type.name)) {\n if (matchers.length > 0 && isRejectedByMatchers(view, node, pos, parent, index, matchers)) {\n return true;\n }\n if (best === null || rect.height < best.rect.height) {\n best = { node, pos, dom, rect };\n }\n }\n return true;\n });\n return best;\n}\n\nfunction isRejectedByMatchers(\n view: EditorView,\n node: Node,\n pos: number,\n parent: Node | null,\n index: number,\n matchers: readonly BlockMatcher[],\n): boolean {\n const $pos = view.state.doc.resolve(pos);\n const candidate: BlockCandidate = {\n block: node,\n documentPos: pos,\n // `pos` sits right BEFORE `node`, so $pos.depth is the parent's depth\n // and `node` itself lives one level deeper.\n treeDepth: $pos.depth + 1,\n container: parent,\n positionInContainer: index,\n isFirstChild: index === 0,\n isLastChild: parent !== null ? index === parent.childCount - 1 : true,\n resolvedPos: $pos,\n editorView: view,\n };\n for (const matcher of matchers) {\n if (matcher.test(candidate) === 'reject') return true;\n }\n return false;\n}\n","import type { Node } from '@domternal/pm/model';\n\n/**\n * Walks up from `[from, to]` widening the range as long as removing the\n * source from each ancestor would leave that ancestor effectively empty.\n * Stops at the first ancestor with meaningful sibling content (or at the\n * doc root).\n *\n * Shared by `moveBlock` and `deleteBlock`. Without it:\n *\n * - Move: dragging the only `<li>` out of a nested `<ul>` would force\n * PM's content fitter to retain an empty `<li>` placeholder to satisfy\n * `bulletList → listItem+`.\n * - Delete: deleting the only listItem inside a UL would either leave\n * that empty placeholder OR (worse, depending on schema fitter\n * behaviour) silently delete the whole list because PM tries to\n * replace the LI with the next-best fit and may unwrap the wrapper.\n *\n * Two collapse cases are handled:\n *\n * 1. **Single-child wrapper** (`block+` schema, classic case): the\n * parent contains only the source. Walking up removes the empty\n * wrapper outright.\n * 2. **Single-meaningful-child wrapper** (Notion-strict `paragraph\n * block*` schema for list items): the parent contains the source\n * plus one auto-injected empty filler paragraph (PM's content\n * fitter prepends an empty paragraph so the list item is schema\n * valid). Treating that filler as discardable keeps the wrapper\n * chain collapsing all the way up, preserving the same behaviour\n * we have under `block+`.\n */\nexport function expandToEmptyWrappers(\n doc: Node,\n from: number,\n to: number,\n): { from: number; to: number } {\n let curFrom = from;\n let curTo = to;\n let $pos = doc.resolve(curFrom);\n while ($pos.depth > 0 && isCollapsibleParent($pos.node($pos.depth), $pos.index($pos.depth))) {\n curFrom = $pos.before($pos.depth);\n curTo = $pos.after($pos.depth);\n $pos = doc.resolve(curFrom);\n }\n return { from: curFrom, to: curTo };\n}\n\n/**\n * Parent collapses if removing the source leaves no meaningful content.\n * `sourceIndex` is the position the source occupies among the parent's\n * children (so we can identify the OTHER children when checking for\n * filler paragraphs).\n */\nfunction isCollapsibleParent(parent: Node, sourceIndex: number): boolean {\n if (parent.childCount === 1) return true;\n if (parent.childCount !== 2) return false;\n const otherIndex = sourceIndex === 0 ? 1 : 0;\n const other = parent.child(otherIndex);\n return other.type.name === 'paragraph' && other.content.size === 0;\n}\n","import { Fragment } from '@domternal/pm/model';\nimport type { Node, NodeType, Schema } from '@domternal/pm/model';\n\nconst TASK_LIST_TYPE = 'taskList';\nconst BULLET_LIST_TYPES = new Set(['bulletList', 'orderedList']);\n\nconst TASK_ITEM_TYPE = 'taskItem';\nconst LIST_ITEM_TYPE = 'listItem';\n\n/**\n * Adapts the IMMEDIATE children of a slice so they satisfy the target\n * parent's content rule when dropping into a list-wrapper container\n * (`bulletList` / `orderedList` / `taskList`).\n *\n * Three behaviours:\n *\n * 1. **Item already matches the target list.** No-op (e.g. dragging a\n * `listItem` into another `bulletList` keeps it a `listItem`).\n *\n * 2. **Cross-list-type conversion.** Source is a list item of the OTHER\n * type (e.g. `taskItem` → bulletList parent). Wrapper type swaps\n * while preserving inner content. For listItem→taskItem we set\n * `checked: false`; for taskItem→listItem the `checked` attr is\n * dropped (PM ignores attrs not declared by the target schema).\n *\n * 3. **Arbitrary-block wrap.** Source is something else (heading,\n * paragraph, codeBlock, blockquote, hr, image, etc.). We wrap the\n * dragged block in a fresh `listItem` (or `taskItem`) so the drop\n * lands INSIDE the list, mirroring Notion's behaviour.\n *\n * Notion-strict listItem content (`paragraph block*`) requires the\n * first child to be a paragraph (the \"label\" line aligned with the\n * bullet/checkbox). For non-paragraph blocks we prepend an empty\n * label paragraph so the block attaches as a nested child below\n * it; for paragraphs we use them directly as the label.\n *\n * Without this wrap, PM's content fitter would silently promote\n * the dragged block to the next valid position (a sibling AFTER\n * the list), which contradicts the visual drop indicator and\n * surprises the user.\n *\n * Scope: only IMMEDIATE children of the slice are adapted. Nested\n * lists inside the dragged content keep their original type - drag a\n * bullet item that contains a nested task list, and the outer wrapper\n * adapts to the new parent while the nested task list is preserved.\n *\n * Returns the original Fragment unchanged when target parent isn't a\n * list wrapper, or when every child already matches the target item\n * type.\n */\nexport function convertListItemForParent(\n schema: Schema,\n content: Fragment,\n parentType: NodeType,\n): Fragment {\n const expectsTaskItem = parentType.name === TASK_LIST_TYPE;\n const expectsListItem = BULLET_LIST_TYPES.has(parentType.name);\n if (!expectsTaskItem && !expectsListItem) return content;\n\n const targetTypeName = expectsTaskItem ? TASK_ITEM_TYPE : LIST_ITEM_TYPE;\n const oppositeTypeName = expectsTaskItem ? LIST_ITEM_TYPE : TASK_ITEM_TYPE;\n const targetItemType = schema.nodes[targetTypeName];\n if (!targetItemType) return content;\n\n // Snapshot children so we can short-circuit when nothing needs\n // adapting - every direct child is already the matching item type.\n const children: Node[] = [];\n content.forEach((child) => { children.push(child); });\n const allMatch = children.every((c) => c.type.name === targetTypeName);\n if (allMatch) return content;\n\n const replaced = children.map((child) => {\n // (1) Already the right type - keep as-is.\n if (child.type.name === targetTypeName) return child;\n\n // (2) Opposite list-item type - convert by reusing inner content.\n if (child.type.name === oppositeTypeName) {\n const newAttrs = expectsTaskItem\n ? { ...child.attrs, checked: false }\n : { ...child.attrs };\n return targetItemType.create(newAttrs, child.content, child.marks);\n }\n\n // (3) Arbitrary block (heading, paragraph, codeBlock, …) - wrap it\n // in a fresh item. Notion-strict listItem requires `paragraph\n // block*` content, so for non-paragraph children we prepend an\n // empty label paragraph (the bullet/checkbox-aligned line) and\n // attach the dragged block below it as a nested child.\n const wrapperAttrs: Record<string, unknown> = expectsTaskItem\n ? { checked: false }\n : {};\n if (child.type.name === 'paragraph') {\n return targetItemType.create(wrapperAttrs, [child]);\n }\n const paragraphType = schema.nodes['paragraph'];\n const labelParagraph = paragraphType?.createAndFill();\n const content = labelParagraph ? [labelParagraph, child] : [child];\n return targetItemType.create(wrapperAttrs, content);\n });\n\n return Fragment.from(replaced);\n}\n","import type { Transaction } from '@domternal/pm/state';\nimport { expandToEmptyWrappers } from './expandToEmptyWrappers.js';\nimport { convertListItemForParent } from './convertListItemForParent.js';\n\n/**\n * Move a top-level block from `sourcePos` to `targetPos` in-place. Single\n * source of truth for block reorder position math, used by BlockHandle\n * drag-drop and KeyboardReorder.\n *\n * Notable steps: deletion range expands outward to swallow single-child\n * wrapper ancestors (else PM's fitter leaves an empty `<li>` placeholder);\n * the slice is adapted to the target parent's content rule (listItem ↔\n * taskItem auto-conversion when dropping across list types). Self-drops\n * (target inside the expanded deletion range) return the transaction\n * unchanged.\n */\nexport function moveBlock(\n tr: Transaction,\n sourcePos: number,\n targetPos: number,\n): Transaction {\n if (sourcePos < 0 || sourcePos >= tr.doc.content.size) return tr;\n const sourceNode = tr.doc.nodeAt(sourcePos);\n if (!sourceNode) return tr;\n const sourceEnd = sourcePos + sourceNode.nodeSize;\n\n const { from, to } = expandToEmptyWrappers(tr.doc, sourcePos, sourceEnd);\n if (targetPos >= from && targetPos <= to) return tr;\n\n // Slice ONLY the source node (not the wrappers we're about to remove -\n // they exist purely as redundant single-child containers and should not\n // travel with the source to its new location).\n const slice = tr.doc.slice(sourcePos, sourceEnd);\n tr.delete(from, to);\n const adjustedTarget = targetPos > from\n ? targetPos - (to - from)\n : targetPos;\n\n // Auto-convert listItem ↔ taskItem when crossing list types, matching\n // Notion's \"drop adapts to context\" UX. When the target's parent isn't\n // a list wrapper (top-level drops, paragraph parents, etc.) the helper\n // returns the slice content unchanged.\n const targetParent = tr.doc.resolve(adjustedTarget).parent;\n const adaptedContent = convertListItemForParent(\n tr.doc.type.schema,\n slice.content,\n targetParent.type,\n );\n\n tr.insert(adjustedTarget, adaptedContent);\n return tr;\n}\n\n","import { Fragment } from '@domternal/pm/model';\nimport type { Node as PMNode } from '@domternal/pm/model';\nimport type { Transaction } from '@domternal/pm/state';\nimport { insertAsListItemChild } from '@domternal/core';\nimport { expandToEmptyWrappers } from './expandToEmptyWrappers.js';\nimport { convertListItemForParent } from './convertListItemForParent.js';\n\nconst LIST_ITEM_TYPES = new Set(['listItem', 'taskItem']);\n\n/**\n * Moves a block from `sourcePos` and inserts it as the LAST child of\n * the list item at `targetItemPos` inside the wrapper at `wrapperPos`.\n * Shared drop-indent path used by `BlockHandle.performBlockDrop` when\n * `computeDropPlacement` returns `mode: 'nested'`.\n *\n * Behaviour matrix:\n *\n * - **Non-list source** (paragraph, heading, codeBlock, blockquote,\n * horizontalRule, image, etc.) - inserted directly as last child of\n * the target item. Schema (`paragraph block*`) accepts any block in\n * the trailing slot.\n * - **List item source** (listItem / taskItem) - wrapped in a fresh\n * list wrapper of the SAME TYPE as the target's wrapper, with the\n * source's item type adapted (via `convertListItemForParent`) so a\n * bulletList listItem dropped into a taskList nested zone becomes a\n * fresh taskList with a taskItem inside. Result: the dragged item\n * appears as a nested sublist below the target item's label.\n *\n * Position math is delegated to `insertAsListItemChild` which handles\n * source-before-vs-after-target ordering automatically. Source range\n * is widened via `expandToEmptyWrappers` so single-child containers\n * don't leave empty placeholders behind (matches `moveBlock` semantics).\n *\n * Returns `false` (no mutation) when:\n * - source position is invalid / no node\n * - target position falls inside the source range (self-drop)\n * - schema rejects the resulting structure (caller falls through to\n * a sibling-style fallback or no-op)\n */\nexport function moveBlockAsNestedChild(\n tr: Transaction,\n sourcePos: number,\n wrapperPos: number,\n targetItemPos: number,\n): boolean {\n if (sourcePos < 0 || sourcePos >= tr.doc.content.size) return false;\n const sourceNode = tr.doc.nodeAt(sourcePos);\n if (!sourceNode) return false;\n const sourceEnd = sourcePos + sourceNode.nodeSize;\n\n // Self-drop guard: target item or its wrapper sits inside the source\n // range. Prevents \"move A into A's own subtree\" - an invalid op that\n // would otherwise corrupt the document.\n if (targetItemPos >= sourcePos && targetItemPos < sourceEnd) return false;\n if (wrapperPos >= sourcePos && wrapperPos < sourceEnd) return false;\n\n // Widen the deletion range so a single-child wrapper around the\n // source (e.g., a nested ul whose only li is the source) collapses\n // along with the source, instead of being left as an empty placeholder.\n const { from: expandedFrom, to: expandedTo } = expandToEmptyWrappers(tr.doc, sourcePos, sourceEnd);\n\n // Pick the block to insert. For a list-item source we wrap it in a\n // fresh list wrapper so the trailing block-slot of the target item\n // (which expects a block, not a bare listItem) accepts the insertion\n // and the result reads as a nested sublist below the target's label.\n let blockNode: PMNode;\n if (LIST_ITEM_TYPES.has(sourceNode.type.name)) {\n const wrapperNode = tr.doc.nodeAt(wrapperPos);\n if (!wrapperNode) return false;\n const adaptedFragment = convertListItemForParent(\n tr.doc.type.schema,\n Fragment.from(sourceNode),\n wrapperNode.type,\n );\n if (adaptedFragment.childCount === 0) return false;\n blockNode = wrapperNode.type.create(null, adaptedFragment);\n } else {\n blockNode = sourceNode;\n }\n\n const result = insertAsListItemChild({\n tr,\n wrapperPos,\n targetItemPos,\n blockNode,\n sourceRange: { from: expandedFrom, to: expandedTo },\n });\n return result.ok;\n}\n","/**\n * Build an off-screen \"ghost\" of a block suitable for HTML5\n * `dataTransfer.setDragImage`.\n *\n * The browser snapshots whatever element you pass to `setDragImage` at\n * call time, with ambient transforms, scroll offsets, and ancestor\n * clipping applied. Pseudo-class styles and effects inherited from\n * ancestors that don't survive in a detached clone are also lost.\n *\n * The workaround: deep-clone the node, then walk both trees in parallel\n * and copy the resolved `cssText` from `getComputedStyle` onto each\n * cloned element's inline `style`. The result paints identically to the\n * original even when detached. The clone goes into an absolutely\n * positioned wrapper far above the viewport so it is invisible during\n * the snapshot, and the wrapper is removed on dragend/drop.\n */\n\nexport interface DragGhost {\n /** Wrapper element to pass to `setDragImage`. */\n wrapper: HTMLElement;\n}\n\n/**\n * Create a styled ghost of `source` and append the wrapper to\n * `document.body`. Caller must remove the wrapper when the drag ends.\n */\nexport function createDragGhost(source: HTMLElement): DragGhost {\n const wrapper = makeWrapper(source);\n const clone = deepCloneWithStyles(source);\n wrapper.appendChild(clone);\n document.body.appendChild(wrapper);\n return { wrapper };\n}\n\nfunction makeWrapper(source: HTMLElement): HTMLElement {\n const w = document.createElement('div');\n w.setAttribute('aria-hidden', 'true');\n Object.assign(w.style, {\n position: 'absolute',\n top: '-10000px',\n left: '-10000px',\n pointerEvents: 'none',\n width: `${String(source.getBoundingClientRect().width)}px`,\n });\n return w;\n}\n\nfunction deepCloneWithStyles(source: HTMLElement): HTMLElement {\n const clone = source.cloneNode(true) as HTMLElement;\n freezeStylesIntoClone(source, clone);\n return clone;\n}\n\nfunction freezeStylesIntoClone(src: Element, dst: Element): void {\n if (src instanceof HTMLElement && dst instanceof HTMLElement) {\n dst.style.cssText = getComputedStyle(src).cssText;\n }\n const srcKids = src.children;\n const dstKids = dst.children;\n const n = Math.min(srcKids.length, dstKids.length);\n for (let i = 0; i < n; i++) {\n const s = srcKids.item(i);\n const d = dstKids.item(i);\n if (s !== null && d !== null) freezeStylesIntoClone(s, d);\n }\n}\n","/**\n * Clamp a (clientX, clientY) pair into the editor's content rectangle\n * so position resolution still works when the cursor is in the side\n * gutter (where the block handle visually lives) or above/below the\n * first/last block.\n *\n * The clamp targets `view.dom.firstElementChild`'s left/right edges\n * (the actual content rect) rather than `view.dom`'s padded box, so\n * a wide editor with `padding-left: 4rem` still anchors X clamps to\n * where text actually lives.\n *\n * Y is only clamped when the cursor is OUTSIDE the editor's vertical\n * span (above the first block or below the last block). When the cursor\n * is INSIDE the editor's span, Y passes through unchanged - clipping the\n * edges (e.g. 5px off the bottom) would otherwise hide thin nested blocks\n * like a 2px-tall horizontal rule that sits at the very bottom of the\n * last top-level container. The `inset` only applies when the cursor is\n * out-of-bounds, snapping it just-inside the content edge.\n *\n * Returns `null` for an empty document - caller should bail out and\n * keep the handle hidden.\n */\nimport type { EditorView } from '@domternal/pm/view';\n\nconst DEFAULT_INSET_PX = 5;\n\nexport function clampToContent(\n view: EditorView,\n clientX: number,\n clientY: number,\n inset: number = DEFAULT_INSET_PX,\n): { x: number; y: number } | null {\n const first = view.dom.firstElementChild;\n const last = view.dom.lastElementChild;\n if (!first || !last) return null;\n\n const topRect = first.getBoundingClientRect();\n const bottomRect = last.getBoundingClientRect();\n\n // Out-of-bounds clamp ONLY: cursor inside the editor's vertical span\n // keeps its exact Y so nested elements at the very edge are reachable.\n let clampedY = clientY;\n if (clientY < topRect.top) clampedY = topRect.top + inset;\n else if (clientY > bottomRect.bottom) clampedY = bottomRect.bottom - inset;\n\n // Use the first block's horizontal extent as the \"content row\" to clamp\n // X into. Multi-column layouts where blocks have wildly different widths\n // are not supported here; for our schema (linear blocks of uniform width)\n // this is sufficient.\n const minX = topRect.left + inset;\n const maxX = topRect.right - inset;\n const clampedX = Math.max(minX, Math.min(clientX, maxX));\n\n return { x: clampedX, y: clampedY };\n}\n","/**\n * Gutter-bias resolution for nested drag-target selection.\n *\n * When the cursor sits near a configured edge of a candidate's rect, the\n * candidate is treated as \"in the gutter\" and its rank weight is reduced\n * proportionally to its tree depth. Shallower (outer) ancestors therefore\n * win against deeply-nested descendants in the gutter zone.\n *\n * The \"deepest-match\" mode skips this bias entirely and always returns the\n * innermost allowed block under the cursor.\n */\n\n/** Cardinal edge of a candidate's bounding rect. */\nexport type GutterEdge = 'left' | 'right' | 'top' | 'bottom';\n\n/**\n * Named presets for the bias config:\n * - `'left'` → ['left', 'top'] (left gutter, default)\n * - `'right'` → ['right', 'top'] (right gutter, RTL-friendly)\n * - `'both'` → ['left', 'right', 'top']\n * - `'none'` → no gutter bias (deepest match wins)\n */\nexport type GutterBiasPreset = 'left' | 'right' | 'both' | 'none';\n\nexport interface GutterBiasConfig {\n /** Edges that constitute the \"gutter\" zone. */\n edges: GutterEdge[];\n /** Pixel distance from the edge at which the bias activates. */\n threshold: number;\n /** Bias factor applied per depth level when in the gutter. */\n strength: number;\n}\n\nconst PRESET_DEFAULT: GutterBiasConfig = {\n edges: ['left', 'top'],\n threshold: 12,\n strength: 500,\n};\n\nconst PRESET_RIGHT: GutterBiasConfig = { ...PRESET_DEFAULT, edges: ['right', 'top'] };\nconst PRESET_BOTH: GutterBiasConfig = { ...PRESET_DEFAULT, edges: ['left', 'right', 'top'] };\n\n/**\n * Resolve the user-facing `promoteOnEdge` input into a concrete bias\n * configuration, or `null` when bias is disabled.\n *\n * Returns `null` for `undefined`, `false`, or `'none'` (deepest-match wins).\n */\nexport function resolveGutterBias(\n input: boolean | GutterBiasPreset | Partial<GutterBiasConfig> | undefined,\n): GutterBiasConfig | null {\n switch (input) {\n case undefined:\n case false:\n case 'none':\n return null;\n case true:\n case 'left':\n return { ...PRESET_DEFAULT };\n case 'right':\n return { ...PRESET_RIGHT };\n case 'both':\n return { ...PRESET_BOTH };\n default:\n return {\n edges: input.edges ?? PRESET_DEFAULT.edges,\n threshold: input.threshold ?? PRESET_DEFAULT.threshold,\n strength: input.strength ?? PRESET_DEFAULT.strength,\n };\n }\n}\n\n/**\n * True when `(x, y)` falls inside the gutter zone defined by `config`.\n * The zone is the union of strips `threshold` px wide along each\n * configured edge of `rect`.\n */\nexport function isInGutter(\n x: number,\n y: number,\n rect: DOMRect,\n config: GutterBiasConfig,\n): boolean {\n const t = config.threshold;\n for (const edge of config.edges) {\n if (edge === 'left' && x - rect.left <= t) return true;\n if (edge === 'right' && rect.right - x <= t) return true;\n if (edge === 'top' && y - rect.top <= t) return true;\n if (edge === 'bottom' && rect.bottom - y <= t) return true;\n }\n return false;\n}\n\n/**\n * Compute the rank-weight penalty for a candidate at `depth` whose rect\n * is in the gutter zone. Returns 0 when the candidate is outside the\n * gutter (no penalty applied).\n */\nexport function gutterBiasWeight(\n x: number,\n y: number,\n rect: DOMRect,\n depth: number,\n config: GutterBiasConfig,\n): number {\n return isInGutter(x, y, rect, config) ? config.strength * depth : 0;\n}\n","/**\n * Built-in eligibility matchers. Together they constrain the drag\n * resolver to \"user-visible block units\" (paragraphs, headings, list\n * items, task items, images, etc.) and exclude structural plumbing\n * (table cells, inline text, list containers whose items are draggable\n * individually).\n *\n * Hosts can disable the bundled set with `defaultMatchers: false` and\n * supply their own matcher list via `matchers`.\n */\nimport type { BlockMatcher } from './blockMatcher.js';\n\nconst LIST_ITEM_NODE_TYPES = new Set(['listItem', 'taskItem']);\nconst TABLE_PLUMBING_TYPES = new Set(['tableRow', 'tableCell', 'tableHeader']);\n\n/**\n * Reject a paragraph that is the first child of a list/task item.\n * Dragging that paragraph alone would split the item; promoting the\n * matcher to \"reject\" sends the resolver up to the list item itself.\n */\nconst firstChildOfListItem: BlockMatcher = {\n name: 'firstChildOfListItem',\n test(candidate) {\n if (!candidate.isFirstChild) return 'allow';\n const parent = candidate.container;\n if (parent === null) return 'allow';\n return LIST_ITEM_NODE_TYPES.has(parent.type.name) ? 'reject' : 'allow';\n },\n};\n\n/**\n * Reject a list/task container when its direct children are list items.\n * Without this the resolver would lock onto the wrapping list near the\n * top edge of the first item.\n */\nconst listContainerSkip: BlockMatcher = {\n name: 'listContainerSkip',\n test(candidate) {\n const firstChild = candidate.block.firstChild;\n if (firstChild === null) return 'allow';\n return LIST_ITEM_NODE_TYPES.has(firstChild.type.name) ? 'reject' : 'allow';\n },\n};\n\n/**\n * Reject table-internal nodes. Table rows, cells, and headers are\n * managed by the Table extension's own UI - the block handle is for\n * top-level blocks only.\n */\nconst tableInternals: BlockMatcher = {\n name: 'tableInternals',\n test(candidate) {\n if (TABLE_PLUMBING_TYPES.has(candidate.block.type.name)) return 'reject';\n if (candidate.container?.type.name === 'tableHeader') return 'reject';\n return 'allow';\n },\n};\n\n/**\n * Reject inline-level nodes (text, marks-bearing inline). The handle\n * targets block-level content only.\n */\nconst inlineNodes: BlockMatcher = {\n name: 'inlineNodes',\n test(candidate) {\n const { block } = candidate;\n return block.isText || block.isInline ? 'reject' : 'allow';\n },\n};\n\nexport const DEFAULT_BLOCK_MATCHERS: readonly BlockMatcher[] = Object.freeze([\n firstChildOfListItem,\n listContainerSkip,\n tableInternals,\n inlineNodes,\n]);\n","/**\n * Two-stage drag target resolver: filter eligible candidates by matcher\n * verdicts, then rank survivors by depth (and optional gutter bias).\n *\n * Algorithm:\n * 1. Resolve cursor to a doc position via `posAtCoords`.\n * 2. Walk ancestors from the deepest (innermost) outward.\n * 3. Each ancestor is checked against type/container constraints, then\n * against every matcher's `test()`. Any 'reject' verdict drops it.\n * 4. Atom leaves (image, horizontal rule, etc.) are not ancestors of\n * the resolved position - they live at `$pos.nodeAfter`. A separate\n * pass adds them as candidates at depth + 1.\n * 5. The survivor list is ranked: when no gutter bias is configured,\n * depth alone decides (deepest wins). When bias is configured, each\n * candidate's effective rank is `treeDepth - gutterPenalty`, where\n * `gutterPenalty = strength * depth` for in-gutter rects and 0\n * otherwise.\n * 6. Highest effective rank wins; ties break by deeper depth.\n */\nimport type { Node, ResolvedPos } from '@domternal/pm/model';\nimport type { EditorView } from '@domternal/pm/view';\n\nimport type { BlockCandidate, BlockMatcher, MatchVerdict } from './blockMatcher.js';\nimport { gutterBiasWeight } from './gutterBias.js';\nimport type { GutterBiasConfig } from './gutterBias.js';\n\nexport interface ResolveDragTargetOptions {\n /** Matchers applied to every candidate. Empty array = no filtering. */\n matchers: readonly BlockMatcher[];\n /** Active gutter-bias config, or `null` to disable. */\n gutterBias: GutterBiasConfig | null;\n /**\n * Allow-list of PM node type names. When non-empty, only nodes whose\n * type name appears here can become the drag target.\n */\n allowedTypes?: readonly string[];\n /**\n * Required ancestor types. When non-empty, the candidate's chain must\n * contain at least one ancestor whose type name appears here.\n */\n requiredAncestorTypes?: readonly string[];\n}\n\nexport interface DragTarget {\n pos: number;\n rect: DOMRect;\n dom: HTMLElement;\n /** Tree depth at which the target sits. */\n depth: number;\n /** Effective rank used to pick this candidate. Exposed for tests. */\n rank: number;\n /** The PM node at `pos`. */\n node: Node;\n}\n\ninterface RankedCandidate extends DragTarget {}\n\n/**\n * Find the best drag target for cursor `(x, y)`, or `null` when no\n * candidate survives the matcher pass.\n */\nexport function resolveDragTarget(\n view: EditorView,\n x: number,\n y: number,\n options: ResolveDragTargetOptions,\n): DragTarget | null {\n const coord = view.posAtCoords({ left: x, top: y });\n if (coord === null) return null;\n\n const $pos = view.state.doc.resolve(coord.pos);\n const survivors: RankedCandidate[] = [];\n\n collectAncestors($pos, view, options, survivors);\n collectAtomLeaf($pos, view, options, survivors);\n\n if (survivors.length === 0) return null;\n applyGutterBias(survivors, x, y, options.gutterBias);\n return chooseWinner(survivors);\n}\n\nfunction collectAncestors(\n $pos: ResolvedPos,\n view: EditorView,\n options: ResolveDragTargetOptions,\n out: RankedCandidate[],\n): void {\n for (let depth = $pos.depth; depth >= 1; depth--) {\n const block = $pos.node(depth);\n const documentPos = $pos.before(depth);\n const container = depth > 0 ? $pos.node(depth - 1) : null;\n const positionInContainer = depth > 0 ? $pos.index(depth - 1) : 0;\n const containerSize = container?.childCount ?? 1;\n\n if (!passesScopeFilters(block, $pos, depth, options)) continue;\n\n const candidate: BlockCandidate = {\n block,\n documentPos,\n treeDepth: depth,\n container,\n positionInContainer,\n isFirstChild: positionInContainer === 0,\n isLastChild: positionInContainer === containerSize - 1,\n resolvedPos: $pos,\n editorView: view,\n };\n\n if (rejectedByMatchers(candidate, options.matchers)) continue;\n\n const dom = view.nodeDOM(documentPos);\n if (!(dom instanceof HTMLElement)) continue;\n\n out.push({\n pos: documentPos,\n rect: dom.getBoundingClientRect(),\n dom,\n depth,\n rank: depth,\n node: block,\n });\n }\n}\n\nfunction collectAtomLeaf(\n $pos: ResolvedPos,\n view: EditorView,\n options: ResolveDragTargetOptions,\n out: RankedCandidate[],\n): void {\n const leaf = $pos.nodeAfter;\n if (leaf === null) return;\n if (!leaf.isAtom || leaf.isInline) return;\n\n const synthDepth = $pos.depth + 1;\n if (!passesScopeFilters(leaf, $pos, synthDepth, options)) return;\n\n const parent = $pos.parent;\n const positionInContainer = $pos.index();\n const containerSize = parent.childCount;\n\n const candidate: BlockCandidate = {\n block: leaf,\n documentPos: $pos.pos,\n treeDepth: synthDepth,\n container: parent,\n positionInContainer,\n isFirstChild: positionInContainer === 0,\n isLastChild: positionInContainer === containerSize - 1,\n resolvedPos: $pos,\n editorView: view,\n };\n\n if (rejectedByMatchers(candidate, options.matchers)) return;\n\n const dom = view.nodeDOM($pos.pos);\n if (!(dom instanceof HTMLElement)) return;\n\n out.push({\n pos: $pos.pos,\n rect: dom.getBoundingClientRect(),\n dom,\n depth: synthDepth,\n rank: synthDepth,\n node: leaf,\n });\n}\n\nfunction passesScopeFilters(\n block: Node,\n $pos: ResolvedPos,\n depth: number,\n options: ResolveDragTargetOptions,\n): boolean {\n const { allowedTypes, requiredAncestorTypes } = options;\n\n if (allowedTypes !== undefined && allowedTypes.length > 0) {\n if (!allowedTypes.includes(block.type.name)) return false;\n }\n\n if (requiredAncestorTypes !== undefined && requiredAncestorTypes.length > 0) {\n if (!hasMatchingAncestor($pos, depth, requiredAncestorTypes)) return false;\n }\n\n return true;\n}\n\nfunction hasMatchingAncestor(\n $pos: ResolvedPos,\n depth: number,\n acceptableTypes: readonly string[],\n): boolean {\n for (let d = depth - 1; d >= 1; d--) {\n const ancestor = $pos.node(d);\n if (acceptableTypes.includes(ancestor.type.name)) return true;\n }\n return false;\n}\n\nfunction rejectedByMatchers(\n candidate: BlockCandidate,\n matchers: readonly BlockMatcher[],\n): boolean {\n for (const matcher of matchers) {\n const verdict: MatchVerdict = matcher.test(candidate);\n if (verdict === 'reject') return true;\n }\n return false;\n}\n\nfunction applyGutterBias(\n candidates: RankedCandidate[],\n x: number,\n y: number,\n config: GutterBiasConfig | null,\n): void {\n if (config === null) return;\n for (const c of candidates) {\n const penalty = gutterBiasWeight(x, y, c.rect, c.depth, config);\n c.rank = c.depth - penalty;\n }\n}\n\nfunction chooseWinner(candidates: readonly RankedCandidate[]): DragTarget {\n // Caller guarantees `candidates.length > 0`; the `reduce` keeps the\n // type narrowing happy without non-null assertions on indexed access.\n return candidates.reduce((best, c) => {\n if (c.rank > best.rank) return c;\n if (c.rank === best.rank && c.depth > best.depth) return c;\n return best;\n });\n}\n","/**\n * BlockHandle Extension\n *\n * Renders a Notion-style gutter handle on the left side of each top-level\n * block when the user hovers over the editor. The handle exposes two\n * buttons:\n *\n * 1. `⋮⋮` drag handle (click → opens BlockContextMenu, drag → reorder)\n * 2. `+` insert button (inserts an empty paragraph below the block; the\n * FloatingMenu extension picks up the empty-line state and auto-shows\n * its insert menu)\n *\n * Visibility + drag + context-menu trigger are fully owned by this plugin;\n * the context menu UI itself lives in `BlockContextMenu.ts` and listens for\n * the `dm:block-context-menu-open` custom event that this plugin dispatches.\n *\n * Styles ship via `@domternal/theme` (`_block-handle.scss`). The plugin\n * adds a `dm-editor--has-block-handle` class to the `.dm-editor` container\n * so the theme stylesheet can widen `.ProseMirror` padding-left to create\n * gutter space inside the `overflow:hidden` editor wrapper.\n */\nimport { Extension, defaultIcons } from '@domternal/core';\nimport type { Editor } from '@domternal/core';\nimport { NodeSelection, Plugin, PluginKey, TextSelection } from '@domternal/pm/state';\nimport type { EditorView } from '@domternal/pm/view';\nimport type { Slice } from '@domternal/pm/model';\nimport { findDeepestBlockAtY } from './helpers/findTopLevelBlock.js';\nimport { moveBlock } from './helpers/moveBlock.js';\nimport { moveBlockAsNestedChild } from './helpers/moveBlockAsNestedChild.js';\nimport { createDragGhost } from './helpers/dragGhost.js';\nimport { clampToContent } from './helpers/clampCoords.js';\nimport { resolveGutterBias } from './helpers/gutterBias.js';\nimport type { GutterBiasConfig, GutterBiasPreset } from './helpers/gutterBias.js';\nimport { DEFAULT_BLOCK_MATCHERS } from './helpers/defaultMatchers.js';\nimport { resolveDragTarget } from './helpers/resolveDragTarget.js';\nimport type { BlockMatcher } from './helpers/blockMatcher.js';\nimport { showFloatingMenu } from './FloatingMenu.js';\n\n/** Default list of nodes treated as drag-targetable when `nested: true`. */\nexport const DEFAULT_NESTED_NODES: string[] = ['listItem', 'taskItem'];\n\n/**\n * Node types that accept a nested-child drop in MVP. When the resolver\n * lands on one of these AND `clientX` exceeds `nestThreshold` from the\n * left edge, `computeDropPlacement` returns `mode: 'nested'`. Other\n * containers (blockquote, codeBlock, details) have their own content\n * rules and remain sibling-only until explicit support lands.\n */\nconst LIST_ITEM_TYPES = new Set(['listItem', 'taskItem']);\n\n/**\n * Default pixel threshold from the left edge of a list item beyond\n * which drop commits to nested-child mode. Roughly the width of a\n * bullet/checkbox marker (~24px) + a small buffer so the boundary\n * sits just past where the marker visually ends.\n */\nexport const DEFAULT_NEST_THRESHOLD = 28;\n\n/**\n * Pixel inset of the nested-mode drop indicator from the resolved\n * block's left edge. Mirrors `--dm-block-children-indent` (1.5rem ≈\n * 24px) so the dashed line lands exactly where a nested child block\n * would render inside the list item.\n */\nconst NESTED_INDICATOR_INDENT_PX = 24;\n\n/**\n * Drop-zone tolerance in CSS pixels. The handle's drop zone extends\n * `DROP_ZONE_TOL_LEFT` past the editor's left edge (so the gutter where\n * the handle visually lives counts as a valid drop area) and `DROP_ZONE_TOL`\n * on every other edge (subpixel jitter + small margins outside `.dm-editor`).\n * Hardcoded so the gate stays predictable regardless of how callers style\n * the wrapper. Override behaviour by setting `dropIndicator: false` and\n * rendering your own visual.\n */\nconst DROP_ZONE_TOL_LEFT = 80;\nconst DROP_ZONE_TOL = 16;\n\nexport const blockHandlePluginKey = new PluginKey<BlockHandlePluginState>('blockHandle');\n\nexport interface BlockHandleOptions {\n /**\n * Milliseconds to wait before hiding the handle after the mouse leaves\n * the editor. Gives users time to move into the handle without it\n * disappearing.\n * @default 200\n */\n hideDelay?: number;\n /**\n * Disable drag-to-reorder while still showing the plus/drag buttons\n * (drag becomes a no-op, click opens context menu only).\n * @default false\n */\n disableDrag?: boolean;\n /**\n * Auto-scroll the nearest scrollable ancestor when the user drags near\n * the top/bottom edge of the viewport. Disable if the host app manages\n * its own drag scroll behaviour.\n * @default true\n */\n autoScroll?: boolean;\n /**\n * Distance in CSS pixels from the top/bottom edge that triggers\n * auto-scroll. Larger values start scrolling sooner.\n * @default 48\n */\n autoScrollThreshold?: number;\n /**\n * Peak scroll speed in CSS pixels per animation frame. Speed ramps\n * linearly from 0 at the threshold to this value at the edge.\n * @default 18\n */\n autoScrollMaxSpeed?: number;\n /**\n * Whether the handle should resolve to nested block containers (list\n * items, task items, and optionally others) instead of always the\n * top-level block.\n *\n * - `false` - only top-level blocks are hoverable / draggable (default).\n * - `true` - list items and task items resolve individually (Notion behaviour).\n * - object - fine-grained config; see `NestedConfig`.\n *\n * @default false\n */\n nested?: boolean | NestedConfig;\n /**\n * Pixel threshold from the LEFT edge of a list item beyond which a\n * drop commits to nested-child mode (the dragged block becomes the\n * last child of that item) instead of sibling mode (a new list item\n * created next to it). Mirrors Notion's \"drop indented = nested,\n * drop on the marker = sibling\" UX.\n *\n * Set to `0` to disable nested-drop entirely (every drop is sibling).\n *\n * The X-detection only fires when nested mode is on AND the resolved\n * target is a `listItem` / `taskItem`. Other containers stay sibling-\n * only until explicit support lands.\n *\n * @default 28\n */\n nestThreshold?: number;\n /**\n * Show a custom drop indicator line during drag-from-handle that\n * mirrors EXACTLY where the drop will land. Replaces the need for\n * `prosemirror-dropcursor` for our drag flow - `dropcursor` uses\n * PM's default `posAtCoords` which can disagree with our resolver\n * (especially in side-gutter / inter-block-gap drops).\n *\n * Set to `false` if you want the standard `prosemirror-dropcursor`\n * behaviour or are providing your own indicator.\n * @default true\n */\n dropIndicator?: boolean;\n}\n\n/**\n * Configuration for nested resolution. Backwards-compatible with the\n * earlier `{ allowedNodes }` literal - every field is optional.\n */\nexport interface NestedConfig {\n /**\n * Node type names treated as drag targets when nested mode is on.\n * @default ['listItem', 'taskItem']\n */\n allowedNodes?: string[];\n /**\n * Restrict resolution to nodes that have at least one ancestor of one\n * of these type names. Use to scope nested mode to specific structures\n * (e.g. only inside `table`). Empty / omitted → no restriction.\n */\n allowedContainers?: string[];\n /**\n * \"Promote to parent at the gutter\" behaviour. When the cursor is\n * within `threshold` px of a configured edge, the candidate's score\n * is reduced by `strength * depth` - deeper nodes are penalised\n * more, so a shallower ancestor (e.g. the wrapping list) wins near\n * the boundary.\n *\n * - `false` / `undefined` / `'none'` → deepest match wins.\n * - `true` / `'left'` → defaults: edges `['left','top']`, threshold 12, strength 500.\n * - `'right'` / `'both'` → preset variants.\n * - object → custom config (any field optional, merged over defaults).\n *\n * @default false\n */\n promoteOnEdge?: boolean | GutterBiasPreset | Partial<GutterBiasConfig>;\n /**\n * Append custom block matchers. Default matchers still apply unless\n * `defaultMatchers: false` is also set.\n */\n matchers?: BlockMatcher[];\n /**\n * Set to `false` to disable the four built-in matchers\n * (firstChildOfListItem, listContainerSkip, tableInternals,\n * inlineNodes). Almost always wanted; opt-out only for testing or\n * specialised host editors.\n * @default true\n */\n defaultMatchers?: boolean;\n}\n\nexport interface BlockHandlePluginState {\n /** Absolute position of the top-level block currently under the cursor, or null. */\n hoveredPos: number | null;\n /**\n * Source position of the block currently being dragged (set on\n * dragstart, cleared on dragend). Used by `handleDrop` to determine\n * whether the drop originated from our handle.\n */\n draggedFrom: number | null;\n}\n\n/**\n * Minimal shape for ProseMirror's internal `view.dragging` property.\n * Assigning to it tells PM that a drag is in progress and which slice is\n * being moved; PM's default drop handler reads this to finalise the move.\n *\n * `node` is an undocumented but critical field - when present, PM's drop\n * handler treats it as the authoritative source selection to delete from\n * the old location, rather than relying on `view.state.selection`. The\n * browser may shift the selection mid-drag (e.g. when the user clicks\n * somewhere else during the drag), which without `node` causes the\n * original block to survive the drop. Setting it explicitly from the\n * `NodeSelection` we created on dragstart prevents this family of bugs.\n */\ninterface PMViewWithDragging {\n dragging: { slice: Slice; move: boolean; node?: NodeSelection } | null;\n}\n\n/** Casts `EditorView` to expose PM's internal `dragging` field. */\nfunction asDragView(view: EditorView): PMViewWithDragging {\n return view as unknown as PMViewWithDragging;\n}\n\n/**\n * Internal, fully-resolved view of `NestedConfig`. Plain string arrays\n * + an optional edge config so the resolver doesn't have to interpret\n * presets at hover time.\n */\nexport interface NestedResolution {\n /** Allowed drag targets. Empty array → top-level-only mode. */\n allowedNodes: string[];\n /** Optional ancestor whitelist; empty array → no restriction. */\n allowedContainers: string[];\n /** Gutter bias config; `null` → deepest match wins. */\n gutterBias: GutterBiasConfig | null;\n /** Effective matcher list (defaults + user, or just user when defaults off). */\n matchers: BlockMatcher[];\n}\n\nexport interface CreateBlockHandlePluginOptions {\n pluginKey: PluginKey<BlockHandlePluginState>;\n editor: Editor;\n hideDelay: number;\n disableDrag: boolean;\n autoScroll: boolean;\n autoScrollThreshold: number;\n autoScrollMaxSpeed: number;\n nested: NestedResolution;\n dropIndicator: boolean;\n /**\n * Pixel threshold for nested-drop X-detection (see `BlockHandleOptions.nestThreshold`).\n * `0` disables nested-drop.\n */\n nestThreshold: number;\n}\n\n/**\n * Walks up from `el` to the nearest ancestor that actually scrolls\n * vertically. Returns `null` when no bounded scrollable ancestor exists -\n * the caller should then skip its custom scroll loop and let the browser's\n * native drag-edge autoscroll handle page-level scrolling. Running both\n * our RAF scrollBy AND the browser's native scroll at the same time\n * double-scrolls and feels janky.\n */\nfunction findScrollableAncestor(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el;\n while (cur) {\n const style = getComputedStyle(cur);\n const overflowY = style.overflowY;\n if ((overflowY === 'auto' || overflowY === 'scroll') && cur.scrollHeight > cur.clientHeight) {\n return cur;\n }\n cur = cur.parentElement;\n }\n return null;\n}\n\n/**\n * Finds the block under the given client coordinates.\n *\n * When `nestedNodes` is non-empty, the plugin is in \"nested mode\":\n * resolves the deepest allowed block (list item, task item, etc.) at\n * the cursor row so users drag individual list items instead of always\n * the whole list.\n *\n * - Mode B (deepest-match, default): spatial Y-walk via `findDeepestBlockAtY`.\n * `posAtCoords` would resolve to whatever sits at the cursor's X,\n * which in the gutter is OUTER content (the inner items are indented\n * further right). The spatial walk anchors the handle on the row the\n * cursor is in, regardless of X.\n * - Mode C (gutter-bias ranking): uses `resolveDragTarget` with\n * gutter bias. By design, gutter-X promotes to OUTER (different\n * UX choice). Opt in via `promoteOnEdge`.\n *\n * When `nestedNodes` is empty, classic behavior: walk doc children and\n * compare Y against each top-level block's DOM rect, with a `posAtCoords`\n * fallback for positions in between blocks.\n */\nfunction resolveBlockAtCoords(\n view: EditorView,\n clientX: number,\n clientY: number,\n nested: NestedResolution,\n): { pos: number; rect: DOMRect; dom: HTMLElement } | null {\n // Mode A - top-level only (classic). Walk doc children by Y range; X\n // is intentionally ignored so the handle still surfaces when the\n // cursor is in the side gutter.\n if (nested.allowedNodes.length === 0) {\n return resolveTopLevelByY(view, clientY);\n }\n\n // Common to nested modes: clamp coords into the editor's content\n // rectangle so resolution survives cursor-in-gutter and above/below\n // edge cases (where `posAtCoords` would otherwise return null).\n const clamped = clampToContent(view, clientX, clientY);\n if (!clamped) return null;\n\n // Mode C - gutter-bias ranking.\n if (nested.gutterBias) {\n const target = resolveDragTarget(view, clamped.x, clamped.y, {\n matchers: nested.matchers,\n gutterBias: nested.gutterBias,\n allowedTypes: nested.allowedNodes,\n requiredAncestorTypes: nested.allowedContainers,\n });\n if (target) {\n return { pos: target.pos, rect: target.rect, dom: target.dom };\n }\n // Ranking picked nothing - fall through to top-level so the handle\n // still surfaces on the doc's outer block.\n return resolveTopLevelByY(view, clamped.y);\n }\n\n // Mode B - deepest allowed block at the cursor row.\n // X is intentionally ignored; see `findDeepestBlockAtY` rationale.\n // `nested.matchers` is forwarded so rejection logic (e.g.\n // firstChildOfListItem) applies consistently with Mode C - hosts\n // extending allowedNodes to include `paragraph` get label-paragraph\n // rejection for free.\n const found = findDeepestBlockAtY(view, clamped.y, nested.allowedNodes, nested.matchers);\n if (found) {\n return { pos: found.pos, rect: found.rect, dom: found.dom };\n }\n return resolveTopLevelByY(view, clamped.y);\n}\n\n/**\n * Top-level fallback used by every mode: walk the doc's direct children\n * and return the one whose vertical range contains `clientY`. X is\n * ignored so the handle resolves correctly even when the cursor sits\n * outside the editor's horizontal bounds.\n *\n * When no top-level block strictly contains `clientY` (cursor sits in\n * the inter-block gap, above the first block, or below the last), this\n * falls back to the **closest** top-level block by vertical distance.\n * The previous fallback used `posAtCoords({ left: 0, top: clientY })`\n * which returned `null` when X=0 was outside the editor's content area -\n * leading to silent drop-in-gap failures (the user sees a hover that\n * anchors but the drop does nothing). Closest-by-Y is robust regardless\n * of horizontal layout and matches Notion's \"drop sticks to the nearest\n * block\" UX.\n */\nfunction resolveTopLevelByY(\n view: EditorView,\n clientY: number,\n): { pos: number; rect: DOMRect; dom: HTMLElement } | null {\n const doc = view.state.doc;\n let offset = 0;\n let closest: { pos: number; rect: DOMRect; dom: HTMLElement; dist: number } | null = null;\n for (let i = 0; i < doc.childCount; i++) {\n const child = doc.child(i);\n const dom = view.nodeDOM(offset);\n if (dom instanceof HTMLElement) {\n const rect = dom.getBoundingClientRect();\n if (clientY >= rect.top && clientY <= rect.bottom) {\n return { pos: offset, rect, dom };\n }\n const dist = clientY < rect.top ? rect.top - clientY : clientY - rect.bottom;\n if (closest === null || dist < closest.dist) {\n closest = { pos: offset, rect, dom, dist };\n }\n }\n offset += child.nodeSize;\n }\n if (closest) return { pos: closest.pos, rect: closest.rect, dom: closest.dom };\n return null;\n}\n\nconst LIST_WRAPPER_TYPE_NAMES = new Set(['bulletList', 'orderedList', 'taskList']);\n\n/**\n * Notion-style \"drop sticks to the list\" semantics. When the resolved\n * drop target is a list-wrapper container (bulletList / orderedList /\n * taskList) and the cursor sits ABOVE its top edge or BELOW its bottom\n * edge, descend into the wrapper and pick the FIRST or LAST listItem\n * (respectively) so the drop lands inside the list rather than creating\n * a sibling list of one item.\n *\n * Without this, a drop in the small gap between a list bottom and the\n * next block would be processed against the wrapper UL - and PM's\n * subsequent insert at the wrapper's end position would auto-wrap the\n * dragged listItem in a brand-new bulletList sibling, which is rarely\n * what users intend (most lists were the user's grouping; they want the\n * drag to keep things in the same list).\n *\n * Returns `resolved` unchanged when:\n * - The resolved node isn't a list wrapper.\n * - The wrapper has no children (e.g. mid-edit transient state).\n * - The cursor is INSIDE the wrapper's vertical extent (the resolver\n * would have already returned a child via `findDeepestBlockAtY` in\n * that case; if we got the wrapper despite being inside, the caller's\n * default targeting is already correct).\n */\nfunction adjustDropTargetForListWrapper(\n view: EditorView,\n resolved: { pos: number; rect: DOMRect; dom: HTMLElement },\n clientY: number,\n): { pos: number; rect: DOMRect; dom: HTMLElement } {\n const node = view.state.doc.nodeAt(resolved.pos);\n if (!node) return resolved;\n if (!LIST_WRAPPER_TYPE_NAMES.has(node.type.name)) return resolved;\n if (node.childCount === 0) return resolved;\n\n const isAbove = clientY < resolved.rect.top;\n const isBelow = clientY > resolved.rect.bottom;\n if (!isAbove && !isBelow) return resolved;\n\n // Find absolute pos of the first or last child relative to the wrapper.\n // Wrapper opens at `resolved.pos`, so its first child starts at\n // `resolved.pos + 1` (one past the open token).\n const targetIndex = isBelow ? node.childCount - 1 : 0;\n let childPos = resolved.pos + 1;\n for (let i = 0; i < targetIndex; i++) {\n childPos += node.child(i).nodeSize;\n }\n const childDom = view.nodeDOM(childPos);\n if (!(childDom instanceof HTMLElement)) return resolved;\n return { pos: childPos, rect: childDom.getBoundingClientRect(), dom: childDom };\n}\n\n/**\n * Resolved drop target shared by `handleDrop` and `updateDropIndicator`\n * so the indicator draws exactly where the drop lands (no\n * \"indicator says X, item drops Y\" mismatch).\n *\n * `mode` distinguishes the two ways a block can be dropped over a list\n * item: `'sibling'` (the existing behaviour, drop position becomes a\n * new sibling of the target via the standard `moveBlock` flow) and\n * `'nested'` (drop becomes a nested child of `targetItemPos` inside\n * `wrapperPos`, applied via `insertAsListItemChild`). Today every\n * placement is `'sibling'`; the `'nested'` branch activates in a\n * follow-up that adds X-threshold detection.\n */\nexport interface DropPlacement {\n /** Position right BEFORE the resolved block (same convention as `nodeAt`). */\n pos: number;\n /** Bounding rect of the resolved block, used to draw the indicator line. */\n rect: DOMRect;\n /**\n * `true` -> drop lands AFTER the resolved block; `false` -> BEFORE.\n * Computed from cursor Y vs the resolved block's mid-line. Read by the\n * sibling-style drop pipeline; ignored when `mode === 'nested'` (the\n * nested branch dispatches via `insertAsListItemChild`).\n */\n insertAfter: boolean;\n /** Sibling drop (current behaviour) vs nested-child drop (drop-indent). */\n mode: 'sibling' | 'nested';\n /** Position of the target list item when `mode === 'nested'`. */\n targetItemPos?: number;\n /** Position of the containing list wrapper when `mode === 'nested'`. */\n wrapperPos?: number;\n}\n\n/**\n * Computes the FINAL drop placement using the same logic `handleDrop`\n * uses. Returned by both the actual drop handler AND the visual drop\n * indicator so the line draws exactly where the drop will land - no\n * \"indicator says one place, item drops elsewhere\" mismatch (the classic\n * dropcursor pain point with custom drop handlers).\n *\n * - `rect` is the resolved target block's rect (for drawing the line)\n * - `insertAfter` decides whether the line sits above or below the rect\n * AND whether the drop pos becomes `pos + nodeSize` or `pos`\n *\n * Returns `null` when the resolver finds no candidate (e.g. empty doc).\n *\n * **Inter-block gap normalization.** When the cursor sits in the gap\n * between two siblings, `resolveBlockAtCoords` flips between them based\n * on Y proximity. Without normalization the indicator would draw at two\n * different rect edges (upper.bottom vs lower.top) - visually two lines\n * for what is the SAME logical drop slot (PM treats `endOf(upper)` and\n * `startOf(lower)` as one position in the parent's content array). To\n * unify the visual we canonicalise `insertAfter=false` to \"after the\n * previous sibling\" whenever a previous sibling exists at the same depth.\n * Net effect: one gap → one line, anchored at the bottom edge of the\n * upper block, with the upper block's width (which equals the lower's\n * for prose at the same depth, so the line spans the content column).\n */\nexport function computeDropPlacement(\n view: EditorView,\n clientX: number,\n clientY: number,\n nested: NestedResolution,\n nestThreshold: number = DEFAULT_NEST_THRESHOLD,\n): DropPlacement | null {\n const initial = resolveBlockAtCoords(view, clientX, clientY, nested);\n if (!initial) return null;\n const resolved = adjustDropTargetForListWrapper(view, initial, clientY);\n\n // X-threshold detection: when the resolved target is a list item and\n // the cursor sits >= nestThreshold px from its left edge (inside the\n // rect's vertical span), commit to nested mode (drop becomes the\n // target item's LAST child). `nestThreshold === 0` disables the branch.\n if (nestThreshold > 0) {\n const targetNode = view.state.doc.nodeAt(resolved.pos);\n if (targetNode && LIST_ITEM_TYPES.has(targetNode.type.name)) {\n const targetRect = resolved.rect;\n const xInTarget = clientX - targetRect.left;\n const isInsideX = xInTarget >= 0 && xInTarget <= targetRect.width;\n const isInNestZone = xInTarget >= nestThreshold;\n const isInsideY = clientY >= targetRect.top && clientY <= targetRect.bottom;\n if (isInsideX && isInNestZone && isInsideY) {\n // Walk up to the wrapping list. `$resolved.before()` is the\n // position right before the parent at $resolved.depth, which for\n // a position between siblings is the wrapper itself.\n const $resolved = view.state.doc.resolve(resolved.pos);\n const wrapperPos = $resolved.before();\n // `insertAfter` mirrors the sibling-mode Y-mid calculation so the\n // field stays semantically meaningful when consumers (the nested\n // branch ignores it).\n const midY = targetRect.top + targetRect.height / 2;\n return {\n pos: resolved.pos,\n rect: targetRect,\n insertAfter: clientY > midY,\n mode: 'nested',\n targetItemPos: resolved.pos,\n wrapperPos,\n };\n }\n }\n }\n\n const rect = resolved.rect;\n const midY = rect.top + rect.height / 2;\n const insertAfter = clientY > midY;\n\n if (!insertAfter) {\n const prev = findPreviousSiblingAtSameDepth(view, resolved.pos);\n if (prev) {\n return { pos: prev.pos, rect: prev.rect, insertAfter: true, mode: 'sibling' };\n }\n }\n return { pos: resolved.pos, rect, insertAfter, mode: 'sibling' };\n}\n\n/**\n * Returns the previous sibling at the same parent depth as `pos` (which\n * must be the position immediately BEFORE a node - same convention as\n * `nodeAt`). Returns `null` when the node has no previous sibling (it's\n * the first child of its parent) or when the previous sibling has no DOM\n * representation.\n *\n * Works for any depth: top-level blocks resolve against `doc`; nested\n * blocks (list items, table cells) resolve against their immediate\n * container - so the canonical \"between\" position is always the upper\n * sibling within the SAME container, never crossing container boundaries.\n */\nfunction findPreviousSiblingAtSameDepth(\n view: EditorView,\n pos: number,\n): { pos: number; rect: DOMRect } | null {\n const doc = view.state.doc;\n if (pos <= 0) return null;\n const $pos = doc.resolve(pos);\n if ($pos.index() === 0) return null;\n const prevNode = $pos.parent.child($pos.index() - 1);\n const prevPos = pos - prevNode.nodeSize;\n const prevDom = view.nodeDOM(prevPos);\n if (!(prevDom instanceof HTMLElement)) return null;\n return { pos: prevPos, rect: prevDom.getBoundingClientRect() };\n}\n\n/**\n * Creates a standalone BlockHandle ProseMirror plugin. Exported so\n * framework wrappers can build on top without going through the Extension\n * factory.\n */\nexport function createBlockHandlePlugin(\n options: CreateBlockHandlePluginOptions,\n): Plugin<BlockHandlePluginState> {\n const { pluginKey, editor, hideDelay, disableDrag, autoScroll, autoScrollThreshold, autoScrollMaxSpeed, nested, dropIndicator, nestThreshold } = options;\n\n // --- Build DOM once. Buttons rendered with the shared Phosphor icons.\n const root = document.createElement('div');\n root.className = 'dm-block-handle';\n root.setAttribute('data-dm-editor-ui', '');\n\n const dragBtn = document.createElement('button');\n dragBtn.type = 'button';\n dragBtn.className = 'dm-block-handle-btn dm-block-handle-drag';\n dragBtn.setAttribute('aria-label', 'Drag to reorder, click for options');\n dragBtn.setAttribute('draggable', 'true');\n dragBtn.innerHTML = defaultIcons['dotsSixVertical'] ?? '';\n\n const plusBtn = document.createElement('button');\n plusBtn.type = 'button';\n plusBtn.className = 'dm-block-handle-btn dm-block-handle-plus';\n plusBtn.setAttribute('aria-label', 'Add block below');\n plusBtn.innerHTML = defaultIcons['plus'] ?? '';\n\n root.appendChild(dragBtn);\n root.appendChild(plusBtn);\n\n // --- Drop indicator: a thin horizontal line drawn at the resolved\n // drop target during an active drag. Built once, hidden by default,\n // appended into `.dm-editor` alongside the handle.\n const indicator = document.createElement('div');\n indicator.className = 'dm-block-drop-indicator';\n indicator.setAttribute('data-dm-editor-ui', '');\n\n let editorEl: HTMLElement | null = null;\n // Element that captures hover events. Usually `editorEl.parentElement`\n // so the listener catches mouse moves in the side gutter (where the\n // BlockHandle sits visually when the editor is centered narrower than\n // the page). Falls back to `editorEl` if no parent exists.\n let hoverEl: HTMLElement | null = null;\n let hideTimer: number | null = null;\n\n // Hover-tick state - rAF-coalesced to keep the handle glide-smooth even\n // when mousemove fires ~240Hz on high-refresh pointers. Only one rAF is\n // registered at a time; latest coords win. `currentHoveredPos` is the\n // identity gate: we only repaint when the ProseMirror position under\n // the cursor *changes*, not on every micro-move within the same block.\n let hoverRaf: number | null = null;\n let pendingHoverCoords: { x: number; y: number } | null = null;\n let currentHoveredPos: number | null = null;\n // Set on `mousedown` on the drag button, cleared on `mouseup` / `dragend`.\n // While truthy, hover updates are paused so the handle does NOT jump to\n // a neighbouring block during the browser's drag-initiation window\n // (the ~3-5px mousedown+move that decides click-vs-drag). Without this\n // lock, the handle slides out from under the user's cursor before the\n // browser has decided the interaction is a drag, and `dragstart` never\n // fires - feels like \"click and hold does nothing\".\n let dragPressActive = false;\n\n // Active drag preview wrapper - built on dragstart via `createDragGhost`,\n // removed on drop/dragend.\n let dragPreview: HTMLElement | null = null;\n\n // SYNC source position captured in `onDragStart`. Required because PM's\n // internal drop handler clears `view.dragging` BEFORE the `handleDrop`\n // plugin hook fires, AND the plugin-state `draggedFrom` is committed via\n // a deferred `setTimeout(0)` (see comment on the dispatch in `onDragStart`)\n // that may not have run by drop time on very fast drags. Closure scope is\n // independent of both, so reading from here is reliable. Cleared on\n // dragend, so it never lingers across drags.\n let pendingDraggedFrom: number | null = null;\n\n // Auto-scroll state machine (populated during an active drag, reset by\n // `resetAutoScroll`). Grouped into one object so every reset clears every\n // field - prevents the \"I forgot to reset X\" class of bug.\n //\n // `lastDragoverAt` is a `performance.now()` timestamp used by the RAF\n // loop as a dead-man switch: if no dragover arrived for `DRAGOVER_SILENCE_MS`,\n // we assume the drag was cancelled (browser ate dragend, OS-level abort)\n // and stop the loop to avoid leaking frames. 1.5s is generous enough to\n // tolerate users holding cursor still mid-drag, tight enough to recover\n // quickly when the browser drops events.\n const DRAGOVER_SILENCE_MS = 1500;\n const autoScrollState: {\n raf: number | null;\n target: HTMLElement | null;\n lastClientY: number | null;\n lastAt: number;\n } = { raf: null, target: null, lastClientY: null, lastAt: 0 };\n\n const resetAutoScroll = (): void => {\n if (autoScrollState.raf !== null) {\n cancelAnimationFrame(autoScrollState.raf);\n }\n autoScrollState.raf = null;\n autoScrollState.target = null;\n autoScrollState.lastClientY = null;\n autoScrollState.lastAt = 0;\n };\n\n const clearHideTimer = (): void => {\n if (hideTimer !== null) {\n window.clearTimeout(hideTimer);\n hideTimer = null;\n }\n };\n\n const hide = (): void => {\n root.removeAttribute('data-show');\n currentHoveredPos = null;\n };\n\n const scheduleHide = (): void => {\n // Context-menu pin: same gate as `onMouseMove`.\n if (editorEl?.hasAttribute('data-block-context-menu-open')) return;\n clearHideTimer();\n hideTimer = window.setTimeout(() => {\n hide();\n hideTimer = null;\n }, hideDelay);\n };\n\n const show = (blockEl: HTMLElement, blockRect: DOMRect, editorRect: DOMRect): void => {\n // Vertically center the handle on the FIRST LINE of the block, not on\n // the block's top edge. For tall blocks (e.g., H1 with line-height\n // 2.8rem) the top edge sits well above the visible text, leaving the\n // handle floating above the title. Aligning to the first line's\n // center matches Notion's positioning regardless of font size.\n const cs = getComputedStyle(blockEl);\n let lineHeight = parseFloat(cs.lineHeight);\n if (!Number.isFinite(lineHeight)) {\n // `line-height: normal` returns a non-numeric string - fall back to\n // ~1.2× the font size (browser default for `normal`).\n const fontSize = parseFloat(cs.fontSize) || 16;\n lineHeight = fontSize * 1.2;\n }\n const handleHeight = root.offsetHeight || 24;\n const offsetIntoBlock = Math.max(0, (lineHeight - handleHeight) / 2);\n const top = blockRect.top - editorRect.top + offsetIntoBlock;\n root.style.top = `${String(top)}px`;\n root.setAttribute('data-show', '');\n };\n\n const updateHoverState = (view: EditorView, pos: number | null): void => {\n const current = pluginKey.getState(view.state)?.hoveredPos ?? null;\n if (current === pos) return;\n view.dispatch(view.state.tr.setMeta(pluginKey, { hoveredPos: pos }));\n };\n\n const setDraggedFrom = (view: EditorView, pos: number | null): void => {\n view.dispatch(view.state.tr.setMeta(pluginKey, { draggedFrom: pos }));\n };\n\n // mousemove is the single hottest event on the editor - high-refresh\n // pointers fire it at 240+Hz. Running `posAtCoords` + `getBoundingClientRect`\n // + `style.top` writes on every tick causes visible wobble because each\n // layout read forces sync layout and each write flips the visibility of\n // the handle one frame at a time. Coalescing to one rAF per frame and\n // gating reposition on ProseMirror-position identity eliminates both.\n const onMouseMove = (event: MouseEvent): void => {\n if (!editorEl) return;\n // Freeze the handle in place while the user is pressing the drag\n // button. Moving it here would slide the button out from under the\n // cursor before the browser decides the interaction is a drag.\n if (dragPressActive) return;\n // Pin the handle to the source block while the BlockContextMenu\n // is open - it serves as the menu's visual anchor.\n if (editorEl.hasAttribute('data-block-context-menu-open')) return;\n pendingHoverCoords = { x: event.clientX, y: event.clientY };\n if (hoverRaf !== null) return;\n hoverRaf = requestAnimationFrame(() => {\n hoverRaf = null;\n const coords = pendingHoverCoords;\n pendingHoverCoords = null;\n if (!coords || !editorEl) return;\n // Re-check the pin gate: a mousemove queued pre-open can fire\n // after `open()` and otherwise reposition the handle.\n if (editorEl.hasAttribute('data-block-context-menu-open')) return;\n const resolved = resolveBlockAtCoords(editor.view, coords.x, coords.y, nested);\n if (!resolved) {\n scheduleHide();\n return;\n }\n clearHideTimer();\n // `updateHoverState` is a no-op when PM plugin state already matches\n // - keep it unconditional so that if a prior docChanged transaction\n // cleared `state.hoveredPos` (forward-assoc mapping can still miss\n // the edge cases around setNodeMarkup), the next hover tick\n // re-asserts it. Skipping this led to \"click on drag handle does\n // nothing\" after a color-swatch change, since the subsequent click\n // would bail with `hoveredPos === null`.\n updateHoverState(editor.view, resolved.pos);\n // Identity gate for the visual reposition only: don't rewrite\n // style.top + data-show if the cursor is still over the same block.\n // That's where the measurable smoothness win lives.\n if (resolved.pos === currentHoveredPos && root.hasAttribute('data-show')) {\n return;\n }\n currentHoveredPos = resolved.pos;\n const editorRect = editorEl.getBoundingClientRect();\n show(resolved.dom, resolved.rect, editorRect);\n });\n };\n\n const onMouseLeave = (): void => {\n scheduleHide();\n };\n\n const onMouseEnter = (): void => {\n clearHideTimer();\n };\n\n const onDismissOverlays = (): void => {\n // BlockContextMenu fires this event while opening to close other\n // overlays; keep the handle visible because it anchors the menu.\n // The attribute is set by `BlockContextMenu.open()` before the\n // dispatch, so its presence means \"context menu opening, not\n // dismissing me\".\n if (editorEl?.hasAttribute('data-block-context-menu-open')) return;\n hide();\n updateHoverState(editor.view, null);\n };\n\n // --- Plus button: dismiss other overlays, insert empty paragraph\n // after the hovered block, focus, then EXPLICITLY trigger the\n // FloatingMenu. Order matters:\n //\n // 1. Dispatch `dm:dismiss-overlays` FIRST - closes BubbleMenu /\n // ContextMenu / SlashCommand and any opt-in FloatingMenu that's\n // already open elsewhere. We do this before flipping our own\n // explicit-trigger flag so the dismissal can't accidentally\n // clear it.\n // 2. Insert the paragraph + move the caret + focus.\n // 3. Call `showFloatingMenu(view)` - required for FloatingMenu\n // instances configured with `requireExplicitTrigger: true`\n // (Notion-style; no auto-show on plain Enter). Default instances\n // ignore the meta and auto-show on the empty paragraph anyway.\n const onPlusClick = (event: MouseEvent): void => {\n event.preventDefault();\n event.stopPropagation();\n if (!editor.isEditable) return;\n const state = pluginKey.getState(editor.view.state);\n const pos = state?.hoveredPos ?? null;\n if (pos === null) return;\n const node = editor.view.state.doc.nodeAt(pos);\n if (!node) return;\n\n const paragraphType = editor.view.state.schema.nodes['paragraph'];\n if (!paragraphType) return;\n\n // (1) Close anything else that might be open.\n editorEl?.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n\n // (2) Insert the new paragraph + park the caret inside it.\n const blockEnd = pos + node.nodeSize;\n const tr = editor.view.state.tr;\n tr.insert(blockEnd, paragraphType.create());\n const sel = TextSelection.near(tr.doc.resolve(blockEnd + 1));\n tr.setSelection(sel);\n editor.view.dispatch(tr.scrollIntoView());\n editor.view.focus();\n\n // (3) Mark this insert as an explicit \"user wants the menu\" gesture.\n showFloatingMenu(editor.view);\n };\n\n // Plus button: keep editor focus during click so the FloatingMenu that\n // auto-appears after insert can read the correct state. `preventDefault`\n // on mousedown stops the button from grabbing focus.\n //\n // Drag button: must NOT call `preventDefault` on mousedown - for a\n // `draggable=\"true\"` element, the browser requires the default mousedown\n // action to initiate a drag. Cancelling it silently kills drag-to-reorder\n // in Chrome/Safari. Focus is restored explicitly after context-menu\n // actions via `editor.view.focus()`.\n const onPlusBtnMouseDown = (event: MouseEvent): void => {\n event.preventDefault();\n };\n\n // Lock the handle in place from mousedown through dragend (or mouseup\n // without drag). Prevents the rAF hover loop from repositioning the\n // handle out from under the cursor during the click-vs-drag window.\n //\n // Mouseup is attached lazily as a one-shot ONLY for the click-without-\n // drag path: the user pressed the drag button but never crossed the\n // browser's drag-init threshold. The dragend path calls `releaseDragPress`\n // directly. Keeping the listener attached for the editor's lifetime\n // (the previous design) leaked a global handler that fired on every\n // click anywhere in the document.\n const onDragBtnMouseDown = (): void => {\n dragPressActive = true;\n document.addEventListener('mouseup', releaseDragPress, { once: true });\n };\n const releaseDragPress = (): void => {\n dragPressActive = false;\n // Defensive: dragend may fire BEFORE mouseup (the common drag-success\n // path). Remove the once-listener so the next stray mouseup anywhere\n // in the page doesn't fire into an already-released lock.\n document.removeEventListener('mouseup', releaseDragPress);\n };\n\n // --- Drag handle: click opens context menu, drag reorders the block.\n //\n // Browser semantics we rely on: when `draggable=\"true\"` and the user\n // presses and releases without moving more than ~3px (browser threshold),\n // a `click` event fires and no `dragstart` is dispatched. Conversely, if\n // the user moves past that threshold, `dragstart` fires and `click` does\n // NOT. This gives us a free, reliable click-vs-drag split - no custom\n // threshold tracking needed.\n\n const onDragBtnClick = (event: MouseEvent): void => {\n event.preventDefault();\n event.stopPropagation();\n if (!editor.isEditable) return;\n const state = pluginKey.getState(editor.view.state);\n const pos = state?.hoveredPos ?? null;\n if (pos === null) return;\n // Dispatch custom event for BlockContextMenu plugin to pick up. Using\n // a CustomEvent with detail preserves both the source block and the\n // anchor element for positioning.\n editorEl?.dispatchEvent(new CustomEvent('dm:block-context-menu-open', {\n bubbles: false,\n detail: { blockPos: pos, anchorElement: dragBtn },\n }));\n };\n\n // --- Auto-scroll during drag.\n //\n // A single RAF loop runs for the whole drag. Each frame reads the last\n // known dragover Y and, if it's within `autoScrollThreshold` of the top\n // or bottom edge of the scrollable target, nudges scroll by a ramped\n // speed (linear from 0 at the threshold to `autoScrollMaxSpeed` at the\n // edge). The loop self-terminates if dragover has been silent for longer\n // than `DRAGOVER_SILENCE_MS` - a cheap failsafe against the browser\n // skipping the `dragend` event (it happens on some OS/browser combos).\n\n const onDocumentDragover = (event: DragEvent): void => {\n autoScrollState.lastClientY = event.clientY;\n autoScrollState.lastAt = performance.now();\n const inZone = isCursorOverDropZone(event.clientX, event.clientY);\n // CRITICAL: when the cursor is in our drop zone (incl. the gutter\n // outside `.ProseMirror`'s padding box), we MUST call preventDefault\n // on dragover. Without it, the browser refuses to fire the subsequent\n // `drop` event on non-PM targets (notion-page, body, etc.) - the\n // user's release becomes a silent no-op. With it, drop fires on\n // whatever element is under the cursor; bubbles up to our document\n // drop listener, which performs the move.\n if (inZone) event.preventDefault();\n if (dropIndicator) {\n if (!inZone) {\n indicator.removeAttribute('data-show');\n return;\n }\n updateDropIndicator(event.clientX, event.clientY);\n }\n };\n\n /**\n * Document-level drop listener. Catches drops that happened OUTSIDE\n * `.ProseMirror` (handle gutter, notion-page padding) but INSIDE our\n * indicator zone - places where the user just saw a \"drop will land\n * here\" line and reasonably expects the release to take effect.\n *\n * Bubbles after PM's own handler (registered on `view.dom`); when PM\n * handled the drop already we see `event.defaultPrevented === true`\n * and bail to avoid double-processing. When PM didn't see the drop\n * (cursor was in the gutter, target is `.notion-page` or similar)\n * `defaultPrevented` is false and we run the same drop logic ourselves.\n */\n const onDocumentDrop = (event: DragEvent): void => {\n if (event.defaultPrevented) return;\n const view = editor.view;\n const dragging = asDragView(view).dragging;\n if (!dragging) return;\n if (!isCursorOverDropZone(event.clientX, event.clientY)) return;\n if (performBlockDrop(event.clientX, event.clientY)) {\n event.preventDefault();\n }\n };\n\n /**\n * Shared drop logic - runs from both PM's `handleDrop` (when cursor\n * is over `.ProseMirror`) and our document-level drop listener (when\n * cursor is in the gutter/margin area but still inside the indicator\n * zone). Returns `true` when a move was dispatched, so callers can\n * decide whether to `preventDefault()` on the source event.\n */\n const performBlockDrop = (clientX: number, clientY: number): boolean => {\n const view = editor.view;\n const state = pluginKey.getState(view.state);\n // Read the source position with a tiered fallback:\n // 1. Plugin state `draggedFrom` - the canonical source. Set via the\n // deferred dispatch in `onDragStart` (Chrome microtask-window\n // workaround) so it MAY still be null on very fast drags where\n // drop fires before the timer has run.\n // 2. Closure-scoped `pendingDraggedFrom` - set SYNCHRONOUSLY in\n // `onDragStart`. Independent of both the deferred dispatch AND of\n // PM's `view.dragging`, which PM's internal drop handler clears\n // BEFORE invoking the plugin `handleDrop` hook (so reading\n // `view.dragging.node.from` here would already see null).\n // 3. `view.dragging.node.from` - last-ditch resort for callers that\n // might fire `drop` directly without ever invoking our\n // `onDragStart` (synthetic e2e events bypass the handle).\n const draggedFrom = state?.draggedFrom\n ?? pendingDraggedFrom\n ?? asDragView(view).dragging?.node?.from\n ?? null;\n if (draggedFrom === null) return false;\n const sourceNode = view.state.doc.nodeAt(draggedFrom);\n if (!sourceNode) return false;\n const placement = computeDropPlacement(view, clientX, clientY, nested, nestThreshold);\n if (!placement) return false;\n const tr = view.state.tr;\n\n if (\n placement.mode === 'nested'\n && placement.targetItemPos !== undefined\n && placement.wrapperPos !== undefined\n ) {\n // Drop-indent path: append source as the last child of the target\n // list item via `insertAsListItemChild`. On schema reject the\n // helper leaves `tr` untouched and returns false; we fall back to\n // the sibling-style move so the user's drag still produces a\n // sensible result.\n const ok = moveBlockAsNestedChild(tr, draggedFrom, placement.wrapperPos, placement.targetItemPos);\n if (ok) {\n view.dispatch(tr.scrollIntoView());\n return true;\n }\n }\n\n const targetNode = view.state.doc.nodeAt(placement.pos);\n const targetEnd = targetNode ? placement.pos + targetNode.nodeSize : placement.pos;\n const targetPos = placement.insertAfter ? targetEnd : placement.pos;\n moveBlock(tr, draggedFrom, targetPos);\n view.dispatch(tr.scrollIntoView());\n return true;\n };\n\n /**\n * Defines the rectangle in which a drop on the editor will succeed.\n * Equals `.dm-editor`'s bounding box extended by `DROP_ZONE_TOL_LEFT`\n * on the left (gutter where the BlockHandle visually sits) and\n * `DROP_ZONE_TOL` on every other edge. See the constant declarations\n * at the top of the file for rationale.\n */\n const isCursorOverDropZone = (clientX: number, clientY: number): boolean => {\n if (!editorEl) return false;\n const rect = editorEl.getBoundingClientRect();\n return clientX >= rect.left - DROP_ZONE_TOL_LEFT\n && clientX <= rect.right + DROP_ZONE_TOL\n && clientY >= rect.top - DROP_ZONE_TOL\n && clientY <= rect.bottom + DROP_ZONE_TOL;\n };\n\n /**\n * Reposition the drop-indicator line at the same target `handleDrop`\n * would land at for these coordinates. Called from the document-level\n * `dragover` listener while a drag is in progress.\n *\n * Hides the indicator when the resolver finds nothing (e.g. cursor\n * outside the editor's content range during a no-op drag-out).\n *\n * Two visual modes:\n *\n * - **Sibling** - solid line at the rect's top OR bottom edge\n * (decided by `insertAfter`), spanning the full block width. The\n * line lives in the gap BETWEEN sibling blocks.\n * - **Nested** - dashed line at the rect's BOTTOM edge, indented to\n * where children render (matching `--dm-block-children-indent`,\n * nominally 24px). Communicates \"this drop becomes a nested child\n * appended at the end\" via `insertAsListItemChild`.\n *\n * The `data-mode` attribute carries the placement mode so theme CSS\n * can swap solid for dashed via `&[data-mode='nested']`.\n */\n const updateDropIndicator = (clientX: number, clientY: number): void => {\n if (!editorEl) return;\n const placement = computeDropPlacement(editor.view, clientX, clientY, nested, nestThreshold);\n if (!placement) {\n indicator.removeAttribute('data-show');\n return;\n }\n const editorRect = editorEl.getBoundingClientRect();\n\n let lineY: number;\n let left: number;\n let width: number;\n if (placement.mode === 'nested') {\n // Indicator sits AT the bottom of the target list item, indented\n // to the children-zone start. `NESTED_INDICATOR_INDENT_PX` mirrors\n // the default `--dm-block-children-indent` CSS variable (1.5rem ≈\n // 24px); custom themes that override the variable can override\n // the indicator indent through the same CSS hook (see theme).\n const indent = NESTED_INDICATOR_INDENT_PX;\n lineY = placement.rect.bottom - editorRect.top;\n left = placement.rect.left - editorRect.left + indent;\n width = Math.max(0, placement.rect.width - indent);\n } else {\n // Sibling line: ABOVE rect when inserting before, BELOW when\n // inserting after. Spans the full resolved block width.\n lineY = (placement.insertAfter ? placement.rect.bottom : placement.rect.top) - editorRect.top;\n left = placement.rect.left - editorRect.left;\n width = placement.rect.width;\n }\n indicator.style.top = `${String(lineY)}px`;\n indicator.style.left = `${String(left)}px`;\n indicator.style.width = `${String(width)}px`;\n indicator.setAttribute('data-show', '');\n indicator.setAttribute('data-mode', placement.mode);\n };\n\n const stopAutoScroll = (): void => {\n resetAutoScroll();\n };\n\n const hideDropIndicator = (): void => {\n indicator.removeAttribute('data-show');\n };\n\n let dragoverAttached = false;\n /** Register document-level dragover + drop listeners for the active\n * drag. Shared by auto-scroll AND drop-indicator AND the\n * gutter-area drop handling so they stay in lockstep without\n * double-listening. */\n const startDragListeners = (): void => {\n if (dragoverAttached) return;\n document.addEventListener('dragover', onDocumentDragover);\n document.addEventListener('drop', onDocumentDrop);\n dragoverAttached = true;\n };\n const stopDragListeners = (): void => {\n if (!dragoverAttached) return;\n document.removeEventListener('dragover', onDocumentDragover);\n document.removeEventListener('drop', onDocumentDrop);\n dragoverAttached = false;\n };\n\n const autoScrollTick = (): void => {\n const target = autoScrollState.target;\n if (target === null) {\n autoScrollState.raf = null;\n return;\n }\n // Dead-man switch: if the browser stopped sending dragover events, the\n // drag is effectively over (some OS/browser combos eat `dragend`).\n // Tear down the same things `onDragEnd` would so we don't leak the\n // document-level listeners or leave a stale drop indicator visible.\n if (autoScrollState.lastAt > 0 && performance.now() - autoScrollState.lastAt > DRAGOVER_SILENCE_MS) {\n stopAutoScroll();\n stopDragListeners();\n hideDropIndicator();\n return;\n }\n if (autoScrollState.lastClientY !== null) {\n // `findScrollableAncestor` only returns bounded elements now, so we\n // measure against the scrollable rect directly. Page-level scroll\n // is handled by the browser's own drag-edge autoscroll (running\n // both would double-scroll and visibly jank).\n const rect = target.getBoundingClientRect();\n const distFromTop = autoScrollState.lastClientY - rect.top;\n const distFromBottom = rect.bottom - autoScrollState.lastClientY;\n let delta = 0;\n if (distFromTop < autoScrollThreshold && distFromTop >= 0) {\n // Ramp: at the edge (dist=0) speed is maxSpeed; at threshold speed is 0.\n delta = -Math.round(autoScrollMaxSpeed * (1 - distFromTop / autoScrollThreshold));\n } else if (distFromBottom < autoScrollThreshold && distFromBottom >= 0) {\n delta = Math.round(autoScrollMaxSpeed * (1 - distFromBottom / autoScrollThreshold));\n }\n if (delta !== 0) {\n target.scrollBy(0, delta);\n }\n }\n autoScrollState.raf = requestAnimationFrame(autoScrollTick);\n };\n\n const startAutoScroll = (): void => {\n if (!autoScroll) return;\n if (!editorEl) return;\n const target = findScrollableAncestor(editorEl);\n if (!target) return;\n autoScrollState.target = target;\n autoScrollState.lastClientY = null;\n autoScrollState.lastAt = performance.now();\n autoScrollState.raf = requestAnimationFrame(autoScrollTick);\n };\n\n const onDragStart = (event: DragEvent): void => {\n if (disableDrag || !editor.isEditable) {\n event.preventDefault();\n return;\n }\n const state = pluginKey.getState(editor.view.state);\n const pos = state?.hoveredPos ?? null;\n if (pos === null) {\n event.preventDefault();\n return;\n }\n // Capture source pos SYNCHRONOUSLY for `performBlockDrop`, which needs\n // it before the deferred plugin-state commit (setTimeout(0) below) and\n // works even after PM has cleared `view.dragging` in its drop handler.\n pendingDraggedFrom = pos;\n const node = editor.view.state.doc.nodeAt(pos);\n if (!node) {\n event.preventDefault();\n return;\n }\n\n const sourceEnd = pos + node.nodeSize;\n const slice = editor.view.state.doc.slice(pos, sourceEnd);\n const nodeSelection = NodeSelection.create(editor.view.state.doc, pos);\n\n // Set the drag preview BEFORE any PM dispatch: the browser only honours\n // `setDragImage` during the initial dragstart tick. If we dispatch a\n // transaction first, PM re-renders and the nodeDOM we captured may be\n // replaced before we set the image.\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n // `text/plain` fallback - Firefox cancels the drag if no data is set.\n event.dataTransfer.setData('text/plain', node.textContent);\n const dom = editor.view.nodeDOM(pos);\n if (dom instanceof HTMLElement) {\n // Build a styled, off-screen clone as the drag preview. Passing\n // the live DOM to setDragImage captures ambient transforms, clip,\n // and scroll offsets from ancestors - the clone is always crisp.\n const ghost = createDragGhost(dom);\n dragPreview = ghost.wrapper;\n event.dataTransfer.setDragImage(ghost.wrapper, 10, 10);\n }\n }\n\n // Inform ProseMirror that a drag is in progress. Including `node` is\n // critical: PM's built-in drop handler deletes the source using this\n // NodeSelection rather than the current view selection, which may\n // shift unexpectedly mid-drag. Without it, the block occasionally\n // survives the drop (the classic \"phantom source\" bug).\n //\n // This assignment is sync-only and doesn't mutate the DOM; it's safe\n // to do inside the dragstart tick.\n asDragView(editor.view).dragging = {\n slice,\n move: true,\n node: nodeSelection,\n };\n\n // CRITICAL - do not move this work back into the sync dragstart tick.\n //\n // Chrome's HTML5 drag machinery commits the drag in the microtask\n // immediately after the `dragstart` handler returns. If the drag\n // source's DOM mutates in any way between dragstart and that commit,\n // Chrome aborts the drag and fires `dragend` INSTANTLY - the user\n // sees \"click and hold does absolutely nothing\" (crbug/168544,\n // react-dnd #1085).\n //\n // Concrete failure we observed: dispatching\n // `setSelection(NodeSelection) + setMeta(draggedFrom)` synchronously\n // caused PM to add the `.ProseMirror-selectednode` class to the\n // dragged block's DOM. That class mutation was enough for Chrome\n // to kill the drag before a single `drag` or `dragover` event fired.\n //\n // Deferring to `setTimeout(..., 0)` runs after the browser has\n // already committed; the subsequent mutations are safe.\n //\n // Skip the dispatch entirely if the drag has already ended by the\n // time this fires - happens on extremely fast drags where dragstart\n // → drop → dragend all complete in a single JS task before the timer\n // gets a chance to run. `onDragEnd` clears `pendingDraggedFrom` to\n // null, so we use that as the \"is drag still alive?\" signal. Without\n // this guard, the post-drag dispatch would attempt to apply a stale\n // `nodeSelection` against a doc whose positions changed during the\n // already-completed drop - PM throws \"Selection passed to\n // setSelection must point at the current document\".\n window.setTimeout(() => {\n if (pendingDraggedFrom === null) return;\n editor.view.dispatch(\n editor.view.state.tr\n .setSelection(nodeSelection)\n .setMeta(pluginKey, { draggedFrom: pos }),\n );\n editorEl?.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n hide();\n }, 0);\n\n // Begin tracking dragover Y and ramping scroll as the cursor nears\n // viewport edges. No-op when `autoScroll: false` or no scroll ancestor.\n startAutoScroll();\n // The shared document-level dragover listener powers BOTH auto-scroll\n // and the drop-indicator. Attached once per drag, removed in dragend.\n startDragListeners();\n };\n\n const teardownDragPreview = (): void => {\n if (dragPreview) {\n dragPreview.remove();\n dragPreview = null;\n }\n };\n\n const onDragEnd = (): void => {\n asDragView(editor.view).dragging = null;\n setDraggedFrom(editor.view, null);\n pendingDraggedFrom = null;\n stopAutoScroll();\n stopDragListeners();\n hideDropIndicator();\n teardownDragPreview();\n releaseDragPress();\n };\n\n return new Plugin<BlockHandlePluginState>({\n key: pluginKey,\n\n state: {\n init: (): BlockHandlePluginState => ({ hoveredPos: null, draggedFrom: null }),\n apply(tr, prev): BlockHandlePluginState {\n const meta = tr.getMeta(pluginKey) as Partial<BlockHandlePluginState> | undefined;\n let next = prev;\n if (meta) {\n if ('hoveredPos' in meta) {\n next = { ...next, hoveredPos: meta.hoveredPos ?? null };\n }\n if ('draggedFrom' in meta) {\n next = { ...next, draggedFrom: meta.draggedFrom ?? null };\n }\n }\n // Map positions through doc changes so collaborative / programmatic\n // transactions that happen while hovering or dragging don't leave\n // us pointing at the wrong block. Use assoc=1 (forward bias) so\n // `setNodeMarkup` on the hovered block - which replaces the node\n // with the same type but new attrs - does NOT treat the left\n // boundary as deleted. Without the forward bias, BlockColor's\n // swatch click would wipe `hoveredPos`, causing the next click\n // on the handle to bail silently.\n if (tr.docChanged) {\n if (next.hoveredPos !== null) {\n const mapped = tr.mapping.mapResult(next.hoveredPos, 1);\n next = { ...next, hoveredPos: mapped.deleted ? null : mapped.pos };\n }\n if (next.draggedFrom !== null) {\n const mapped = tr.mapping.mapResult(next.draggedFrom, 1);\n next = { ...next, draggedFrom: mapped.deleted ? null : mapped.pos };\n }\n }\n return next;\n },\n },\n\n props: {\n // Custom drop handler - gives Notion-like \"above-mid → insert before,\n // below-mid → insert after\" block-level semantics instead of PM's\n // default `posAtCoords + dropPoint` which for short paragraphs\n // rounds to an arbitrary neighbour boundary and surprises users.\n // The `moveBlock` helper handles the delete+insert + position\n // adjustment so the block keeps its attrs (UniqueID, colors) and\n // the doc ends up in a predictable state.\n handleDrop(_view, event, _slice, moved): boolean {\n if (!moved) return false;\n // Delegates to the shared `performBlockDrop`, which is also used\n // by the document-level drop listener so the same move logic runs\n // whether the drop fired on `.ProseMirror` (this path) or on\n // surrounding chrome inside our indicator zone (doc listener).\n if (performBlockDrop(event.clientX, event.clientY)) {\n event.preventDefault();\n return true;\n }\n // Source node missing, no resolved placement - still consume\n // the event so PM doesn't fall back to its default drop logic.\n event.preventDefault();\n return true;\n },\n },\n\n view: (editorView) => {\n editorEl = editorView.dom.closest('.dm-editor');\n if (!editorEl) {\n // No `.dm-editor` container → plugin inert.\n return { destroy: () => { /* noop */ } };\n }\n\n editorEl.classList.add('dm-editor--has-block-handle');\n editorEl.appendChild(root);\n if (dropIndicator) {\n editorEl.appendChild(indicator);\n }\n hide();\n hideDropIndicator();\n\n // Hover detection lives on `.dm-editor`'s parent (typically the page\n // wrapper, e.g. `.notion-page`'s framework-host child) so the listener\n // also catches mouse movement in the side gutter - the area where the\n // BlockHandle visually lives when the editor is centered narrower than\n // the page. `resolveBlockAtCoords` falls back to a Y-range walk when\n // the cursor's X is outside `.ProseMirror`, so the block under the\n // cursor still resolves correctly.\n hoverEl = editorEl.parentElement ?? editorEl;\n hoverEl.addEventListener('mousemove', onMouseMove);\n hoverEl.addEventListener('mouseleave', onMouseLeave);\n hoverEl.addEventListener('mouseenter', onMouseEnter);\n editorEl.addEventListener('dm:dismiss-overlays', onDismissOverlays);\n\n plusBtn.addEventListener('mousedown', onPlusBtnMouseDown);\n plusBtn.addEventListener('click', onPlusClick);\n // dragBtn mousedown is a no-preventDefault listener - we rely on\n // the browser's native drag initiation (`draggable=\"true\"`) and\n // only use mousedown to set a hover-freeze lock so the handle\n // doesn't slide away before the drag threshold is crossed.\n dragBtn.addEventListener('mousedown', onDragBtnMouseDown);\n // (mouseup is attached lazily inside `onDragBtnMouseDown` as a\n // one-shot - see its comment for the click-vs-drag rationale.)\n dragBtn.addEventListener('click', onDragBtnClick);\n dragBtn.addEventListener('dragstart', onDragStart);\n dragBtn.addEventListener('dragend', onDragEnd);\n\n return {\n destroy: () => {\n clearHideTimer();\n // If the editor is destroyed mid-drag, stop the RAF loop and\n // drop the document-level dragover listener immediately.\n stopAutoScroll();\n stopDragListeners();\n hideDropIndicator();\n indicator.remove();\n teardownDragPreview();\n if (hoverRaf !== null) {\n cancelAnimationFrame(hoverRaf);\n hoverRaf = null;\n }\n hoverEl?.removeEventListener('mousemove', onMouseMove);\n hoverEl?.removeEventListener('mouseleave', onMouseLeave);\n hoverEl?.removeEventListener('mouseenter', onMouseEnter);\n editorEl?.removeEventListener('dm:dismiss-overlays', onDismissOverlays);\n plusBtn.removeEventListener('mousedown', onPlusBtnMouseDown);\n plusBtn.removeEventListener('click', onPlusClick);\n dragBtn.removeEventListener('mousedown', onDragBtnMouseDown);\n document.removeEventListener('mouseup', releaseDragPress);\n dragBtn.removeEventListener('click', onDragBtnClick);\n dragBtn.removeEventListener('dragstart', onDragStart);\n dragBtn.removeEventListener('dragend', onDragEnd);\n editorEl?.classList.remove('dm-editor--has-block-handle');\n root.remove();\n editorEl = null;\n hoverEl = null;\n },\n };\n },\n });\n}\n\nexport const BlockHandle = Extension.create<BlockHandleOptions>({\n name: 'blockHandle',\n\n addOptions() {\n return {\n hideDelay: 200,\n disableDrag: false,\n autoScroll: true,\n autoScrollThreshold: 48,\n autoScrollMaxSpeed: 18,\n nested: false,\n dropIndicator: true,\n nestThreshold: DEFAULT_NEST_THRESHOLD,\n };\n },\n\n addProseMirrorPlugins() {\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n return [\n createBlockHandlePlugin({\n pluginKey: blockHandlePluginKey,\n editor,\n hideDelay: this.options.hideDelay ?? 200,\n disableDrag: this.options.disableDrag ?? false,\n autoScroll: this.options.autoScroll ?? true,\n autoScrollThreshold: this.options.autoScrollThreshold ?? 48,\n autoScrollMaxSpeed: this.options.autoScrollMaxSpeed ?? 18,\n nested: resolveNestedConfig(this.options.nested),\n dropIndicator: this.options.dropIndicator ?? true,\n nestThreshold: this.options.nestThreshold ?? DEFAULT_NEST_THRESHOLD,\n }),\n ];\n },\n});\n\n/**\n * Normalises the user-facing `nested` option (boolean | config object)\n * into the resolver-friendly `NestedResolution`:\n *\n * - `false` / `undefined` → top-level-only (mode A).\n * - `true` → default list (list item, task item), Notion-style (mode B).\n * - object → explicit config; defaults fill in for missing fields.\n */\nexport function resolveNestedConfig(nested: BlockHandleOptions['nested']): NestedResolution {\n if (nested === true) {\n return {\n allowedNodes: [...DEFAULT_NESTED_NODES],\n allowedContainers: [],\n gutterBias: null,\n matchers: [...DEFAULT_BLOCK_MATCHERS],\n };\n }\n if (nested && typeof nested === 'object') {\n const allowedNodes = nested.allowedNodes ?? DEFAULT_NESTED_NODES;\n if (allowedNodes.length === 0) {\n return { allowedNodes: [], allowedContainers: [], gutterBias: null, matchers: [] };\n }\n const useDefaults = nested.defaultMatchers ?? true;\n const matchers: BlockMatcher[] = [];\n if (useDefaults) matchers.push(...DEFAULT_BLOCK_MATCHERS);\n if (nested.matchers) matchers.push(...nested.matchers);\n return {\n allowedNodes: [...allowedNodes],\n allowedContainers: nested.allowedContainers ? [...nested.allowedContainers] : [],\n gutterBias: resolveGutterBias(nested.promoteOnEdge),\n matchers,\n };\n }\n return { allowedNodes: [], allowedContainers: [], gutterBias: null, matchers: [] };\n}\n","/**\n * `Mod-Shift-ArrowUp` / `Mod-Shift-ArrowDown` move the top-level block\n * containing the selection. Accessibility companion to BlockHandle drag.\n * Shares `moveBlock` so position math and self-move rejection match.\n */\nimport { Extension } from '@domternal/core';\nimport type { Editor } from '@domternal/core';\nimport { TextSelection } from '@domternal/pm/state';\nimport { findTopLevelBlock } from './helpers/findTopLevelBlock.js';\nimport { moveBlock } from './helpers/moveBlock.js';\n\nexport const KeyboardReorder = Extension.create({\n name: 'keyboardReorder',\n\n addKeyboardShortcuts() {\n const { editor } = this;\n return {\n 'Mod-Shift-ArrowUp': () => moveCurrentBlock(editor as Editor | null, 'up'),\n 'Mod-Shift-ArrowDown': () => moveCurrentBlock(editor as Editor | null, 'down'),\n };\n },\n});\n\n/**\n * Moves the top-level block containing the current selection up or down.\n * Returns `true` when a move happened, `false` otherwise (lets the browser\n * handle the shortcut if we don't consume it).\n */\nfunction moveCurrentBlock(editor: Editor | null, direction: 'up' | 'down'): boolean {\n if (!editor || editor.isDestroyed) return false;\n if (!editor.isEditable) return false;\n const { state, view } = editor;\n const { $from } = state.selection;\n\n const topLevel = findTopLevelBlock(state.doc, $from.pos);\n if (!topLevel) return false;\n\n if (direction === 'up' && topLevel.index === 0) return false;\n if (direction === 'down' && topLevel.index >= state.doc.childCount - 1) return false;\n\n // Relative offset of the selection WITHIN the source block (survives\n // nested containers like list-item/details-content because we work with\n // absolute positions inside the block, not depth-based math).\n const selectionOffsetInBlock = Math.max(\n 0,\n Math.min($from.pos - topLevel.pos, topLevel.node.nodeSize - 1),\n );\n\n let targetPos: number;\n if (direction === 'up') {\n targetPos = state.doc.resolve(topLevel.pos).posAtIndex(topLevel.index - 1, 0);\n } else {\n const nextSibling = state.doc.child(topLevel.index + 1);\n const nextStart = state.doc.resolve(topLevel.pos).posAtIndex(topLevel.index + 1, 0);\n targetPos = nextStart + nextSibling.nodeSize;\n }\n\n const tr = state.tr;\n moveBlock(tr, topLevel.pos, targetPos);\n\n // Restore selection inside the moved block. `moveBlock` deletes then\n // inserts; the block's new start position is `adjustedTarget`, which\n // equals `targetPos` when moving up and `targetPos - source.nodeSize`\n // when moving down.\n const newBlockPos = direction === 'up'\n ? targetPos\n : targetPos - topLevel.node.nodeSize;\n const selectionPos = Math.min(\n newBlockPos + selectionOffsetInBlock,\n Math.max(0, tr.doc.content.size - 1),\n );\n tr.setSelection(TextSelection.near(tr.doc.resolve(selectionPos)));\n\n view.dispatch(tr.scrollIntoView());\n return true;\n}\n","import type { Attrs, NodeType } from '@domternal/pm/model';\nimport type { Transaction } from '@domternal/pm/state';\nimport { TextSelection } from '@domternal/pm/state';\nimport { expandToEmptyWrappers } from './expandToEmptyWrappers.js';\n\n/**\n * Block-level transaction helpers shared between BlockContextMenu commands\n * (Delete, Duplicate, Turn into) and other feature implementations that\n * need to operate on a top-level block.\n *\n * All helpers mutate and return the given transaction (chainable) rather\n * than creating a new one.\n */\n\n/**\n * Removes the block at `blockPos` entirely.\n *\n * Two correctness properties:\n *\n * 1. **Single-child wrapper expansion.** Deleting an inner block whose\n * parent only had that block as its single child would leave PM\n * fitting an empty placeholder (e.g. a `<ul>` with one `<li>` whose\n * paragraph is blank) to satisfy schemas like `bulletList → listItem+`.\n * Worse: in some schemas the fitter unwraps the parent and the\n * user perceives \"delete killed the whole list\". We expand the\n * deletion range outward through such wrappers (same logic as\n * `moveBlock`) so the entire orphan chain is removed atomically.\n *\n * 2. **Doc-empty fallback.** If the expanded range covers the entire\n * doc (e.g. doc had `[ul[only-li]]` and we expand to remove ul +\n * li), the delete would leave an empty doc and violate `block+`\n * on the doc itself. We replace with a fresh paragraph instead so\n * the editor stays usable (matches Notion).\n */\nexport function deleteBlock(tr: Transaction, blockPos: number): Transaction {\n if (blockPos < 0 || blockPos >= tr.doc.content.size) return tr;\n const node = tr.doc.nodeAt(blockPos);\n if (!node) return tr;\n const blockEnd = blockPos + node.nodeSize;\n\n const { from, to } = expandToEmptyWrappers(tr.doc, blockPos, blockEnd);\n\n // After expansion, would the doc be left empty? Compare the expanded\n // range to the doc's full content range - equality means we covered\n // every top-level child via single-child wrapper chains.\n const wouldEmptyDoc = from === 0 && to === tr.doc.content.size;\n if (wouldEmptyDoc) {\n const paragraphType = tr.doc.type.schema.nodes['paragraph'];\n if (!paragraphType) {\n // Schema has no `paragraph` type - bail rather than risk an\n // invalid replacement.\n return tr;\n }\n const replacement = paragraphType.createAndFill();\n if (!replacement) return tr;\n tr.replaceWith(from, to, replacement);\n tr.setSelection(TextSelection.near(tr.doc.resolve(from + 1)));\n return tr;\n }\n\n tr.delete(from, to);\n return tr;\n}\n\n/**\n * Duplicates the block at `blockPos` by inserting a copy immediately after\n * it. The copy preserves content, attrs, AND node-level marks (important\n * for annotation / comment extensions that attach marks to blocks).\n *\n * @param transformAttrs Optional mapper invoked on the source attrs to\n * produce the copy's attrs. Use this to regenerate unique IDs so the\n * duplicate doesn't collide with the original (e.g. `{ ...attrs, id: uuid() }`).\n */\nexport function duplicateBlock(\n tr: Transaction,\n blockPos: number,\n transformAttrs?: (attrs: Attrs) => Attrs,\n): Transaction {\n if (blockPos < 0 || blockPos >= tr.doc.content.size) return tr;\n const node = tr.doc.nodeAt(blockPos);\n if (!node) return tr;\n const blockEnd = blockPos + node.nodeSize;\n const attrs = transformAttrs ? transformAttrs(node.attrs) : node.attrs;\n // `type.create(attrs, content, marks)` preserves all three; plain\n // `node.copy(content)` drops the node's marks which breaks use cases\n // like block-level annotations.\n const copy = node.type.create(attrs, node.content, node.marks);\n tr.insert(blockEnd, copy);\n return tr;\n}\n\n/**\n * Transforms the block at `blockPos` into a different textblock type while\n * preserving its inline content AND any attributes that are valid on the\n * target type. Without this, `setBlockType` would reset global attrs\n * (bgColor, textColor, id, etc.) to their defaults - surprising users who\n * expect \"Turn into\" to keep a block's color and identity.\n *\n * Which attrs carry over is decided by the target type's schema: attrs that\n * exist on BOTH source and target flow through; attrs specific to the\n * source type (e.g., `level` on a Heading when turning into Paragraph) are\n * dropped naturally because the target doesn't declare them.\n *\n * The explicit `attrs` argument (e.g., `{ level: 2 }` for Heading 2) takes\n * precedence over source attrs with the same key.\n *\n * Returns the transaction unchanged if the target type is not a textblock\n * or if the node at `blockPos` can't be transformed.\n */\nexport function turnIntoBlock(\n tr: Transaction,\n blockPos: number,\n targetType: NodeType,\n attrs?: Attrs,\n): Transaction {\n if (blockPos < 0 || blockPos >= tr.doc.content.size) return tr;\n const node = tr.doc.nodeAt(blockPos);\n if (!node) return tr;\n // `setBlockType` requires the target to be a textblock; if it isn't, bail.\n if (!targetType.isTextblock) return tr;\n const blockEnd = blockPos + node.nodeSize;\n\n // Preserve source attrs that the target type also declares, then overlay\n // caller-provided attrs on top. `targetType.spec.attrs` is the schema\n // truth about which attrs are valid on the new type.\n const validKeys = Object.keys(targetType.spec.attrs ?? {});\n const preserved: Record<string, unknown> = {};\n const sourceAttrs = node.attrs as Record<string, unknown>;\n for (const key of validKeys) {\n if (key in sourceAttrs) preserved[key] = sourceAttrs[key];\n }\n const mergedAttrs = attrs ? { ...preserved, ...attrs } : preserved;\n\n tr.setBlockType(blockPos, blockEnd, targetType, mergedAttrs);\n return tr;\n}\n","import { TextSelection } from '@domternal/pm/state';\nimport type { Editor } from '@domternal/core';\n\n/**\n * Editor commands the menu can route to for wrapper-style \"Turn into\".\n * Each maps to a command from the corresponding node extension.\n */\nexport type WrapperCommand =\n | 'toggleBulletList'\n | 'toggleOrderedList'\n | 'toggleTaskList'\n | 'toggleBlockquote';\n\n/**\n * Wrap-style \"Turn into\" for non-textblock targets (lists, blockquote).\n *\n * The textblock targets (paragraph, heading, codeBlock) are handled by\n * `turnIntoBlock` via `setBlockType`. Wrappers can't go through that\n * path - the inner block stays put, only its parent changes. So this\n * helper:\n *\n * 1. (Optionally) downgrades the source block to paragraph. ListItem\n * and TaskItem both declare `content: 'paragraph block*'`, meaning\n * the FIRST child of a list item must be a paragraph. A bare\n * heading or codeBlock would be rejected by the schema during the\n * wrap step. Blockquote has `content: 'block+'` and accepts any\n * block, so step-down only applies to list targets.\n * 2. Moves the selection into the (now-paragraph) block.\n * 3. Dispatches the wrapper command. `toggleList` / `toggleBlockquote`\n * operate on `state.selection`, so the selection-set must land\n * before the command runs.\n *\n * Note: the step-down dispatch and the wrapper command produce two\n * undo steps. Composing them into a single transaction would require\n * re-implementing the toggleList Command's body inline; the two-step\n * undo is an acceptable tradeoff for the (rare) heading/codeBlock →\n * list path.\n */\nexport function turnIntoWrapper(\n editor: Editor,\n blockPos: number,\n command: WrapperCommand,\n): boolean {\n const { state } = editor.view;\n if (blockPos < 0 || blockPos >= state.doc.content.size) return false;\n const node = state.doc.nodeAt(blockPos);\n if (!node?.type.isTextblock) return false;\n\n const isListTarget = command !== 'toggleBlockquote';\n const needsStepDown = isListTarget && node.type.name !== 'paragraph';\n\n const tr = state.tr;\n if (needsStepDown) {\n const paragraphType = state.schema.nodes['paragraph'];\n if (!paragraphType) return false;\n tr.setBlockType(blockPos, blockPos + node.nodeSize, paragraphType);\n }\n // blockPos points at the OPENING token of the block; +1 lands inside\n // its inline content (or at the empty cursor position for an empty\n // textblock).\n tr.setSelection(TextSelection.create(tr.doc, blockPos + 1));\n editor.view.dispatch(tr);\n\n // Dispatch the wrapper command via the editor's commands map. The\n // map is typed `Record<string, (...) => boolean>` so switch on the\n // discriminant to keep type-safety without a wide cast.\n switch (command) {\n case 'toggleBulletList':\n return editor.commands.toggleBulletList();\n case 'toggleOrderedList':\n return editor.commands.toggleOrderedList();\n case 'toggleTaskList':\n return editor.commands.toggleTaskList();\n case 'toggleBlockquote':\n return editor.commands.toggleBlockquote();\n }\n}\n","/**\n * BlockContextMenu Extension\n *\n * Popup menu that opens when the user clicks the BlockHandle `⋮⋮` drag\n * handle without dragging. Offers block-level operations for the target:\n *\n * - **Delete** - remove the block\n * - **Duplicate** - insert an identical copy below\n * - **Turn into** - change the block type (paragraph, heading, quote, etc.)\n *\n * Triggered by the `dm:block-context-menu-open` custom event dispatched\n * from BlockHandle; payload carries `{ blockPos, anchorElement }`.\n *\n * Implementation mirrors FloatingMenu / SlashCommand styling conventions\n * so theming is consistent: `role=\"menu\"` container, `role=\"menuitem\"`\n * buttons, `data-show` for visibility, positioned via `positionFloatingOnce`.\n */\nimport { Extension, defaultIcons, positionFloatingOnce, stripInlineColorConflicts, writeToClipboard } from '@domternal/core';\nimport type { Editor } from '@domternal/core';\nimport { Plugin, PluginKey } from '@domternal/pm/state';\nimport type { Transaction } from '@domternal/pm/state';\nimport type { Attrs } from '@domternal/pm/model';\nimport { Decoration, DecorationSet } from '@domternal/pm/view';\nimport {\n deleteBlock,\n duplicateBlock,\n turnIntoBlock,\n} from './helpers/blockOperations.js';\nimport { turnIntoWrapper, type WrapperCommand } from './helpers/turnIntoWrapper.js';\n\n/**\n * Shape of the `uniqueID` extension's options. We only read the two fields\n * we care about; duplicating the full `UniqueIDOptions` type here avoids\n * importing it from core (which would couple an otherwise-optional feature).\n */\ninterface UniqueIDOptionsShape {\n attributeName?: string;\n generateID?: () => string;\n}\n\n/**\n * Same pattern for `blockColor` - we peek at the palette + types list but\n * don't import `BlockColorOptions` directly because the Colors UI degrades\n * gracefully when the extension isn't loaded.\n */\ninterface BlockColorOptionsShape {\n types?: string[];\n bgColors?: string[];\n textColors?: string[];\n}\n\n/**\n * `props.decorations` reads `activeBlockPos` and applies the\n * `dm-block-context-active` class via a PM Decoration. Decoration\n * survives view rerenders that other transactions trigger (e.g.\n * UniqueID stamping `id` via setNodeMarkup); inline classList\n * mutation does not.\n */\nexport interface BlockContextMenuPluginState {\n activeBlockPos: number | null;\n}\n\nexport const blockContextMenuPluginKey = new PluginKey<BlockContextMenuPluginState>('blockContextMenu');\n\n/**\n * A target type the user can convert the current block into via the\n * \"Turn into\" submenu.\n */\nexport interface TurnIntoTarget {\n /** Display label, e.g. \"Heading 1\". */\n label: string;\n /** Icon key resolved against `defaultIcons`. */\n icon: string;\n /** Schema node name, e.g. \"heading\", \"paragraph\", \"blockquote\". */\n nodeType: string;\n /** Optional node attributes (e.g. `{ level: 1 }` for Heading 1). */\n attrs?: Attrs;\n /**\n * Editor command to invoke for non-textblock (wrapper) targets like\n * lists and blockquote. When set, runTurnInto routes through\n * `turnIntoWrapper` which sets selection then dispatches the\n * command, instead of calling `setBlockType`. Leave undefined for\n * textblock targets (paragraph, heading, codeBlock).\n */\n command?: WrapperCommand;\n}\n\nconst DEFAULT_TURN_INTO: TurnIntoTarget[] = [\n { label: 'Paragraph', icon: 'textT', nodeType: 'paragraph' },\n { label: 'Heading 1', icon: 'textHOne', nodeType: 'heading', attrs: { level: 1 } },\n { label: 'Heading 2', icon: 'textHTwo', nodeType: 'heading', attrs: { level: 2 } },\n { label: 'Heading 3', icon: 'textHThree', nodeType: 'heading', attrs: { level: 3 } },\n { label: 'Bullet list', icon: 'listBullets', nodeType: 'bulletList', command: 'toggleBulletList' },\n { label: 'Ordered list', icon: 'listNumbers', nodeType: 'orderedList', command: 'toggleOrderedList' },\n { label: 'To-do list', icon: 'listChecks', nodeType: 'taskList', command: 'toggleTaskList' },\n { label: 'Quote', icon: 'quotes', nodeType: 'blockquote', command: 'toggleBlockquote' },\n { label: 'Code block', icon: 'codeBlock', nodeType: 'codeBlock' },\n];\n\nexport interface BlockContextMenuOptions {\n /**\n * Show the \"Turn into\" section of the menu. Disable to limit operations\n * to Delete + Duplicate.\n * @default true\n */\n turnIntoEnabled?: boolean;\n /**\n * Block types offered by \"Turn into\". Override to curate the list or\n * add project-specific block types.\n * @default DEFAULT_TURN_INTO\n */\n turnIntoTargets?: TurnIntoTarget[];\n /**\n * Show \"Copy link\" when the target block has an id attribute AND the\n * `UniqueID` extension is loaded in the editor. Without UniqueID this\n * option has no effect - the item never appears regardless of value.\n * @default true\n */\n copyLinkEnabled?: boolean;\n /**\n * Build the URL written to the clipboard when the user clicks \"Copy link\".\n * Receives the block's id and the editor; returns a full URL. Default\n * appends `#<id>` to the current pathname+search, which works for static\n * pages. Frameworks with client-side routing should provide a callback\n * matching their URL scheme.\n */\n onCopyLink?: (blockId: string, editor: Editor) => string;\n /**\n * Show the Colors section (text color + background) when the `BlockColor`\n * extension is loaded and the target block is in its `types` list.\n * Without BlockColor this option has no effect.\n * @default true\n */\n blockColorEnabled?: boolean;\n}\n\nexport interface CreateBlockContextMenuPluginOptions {\n pluginKey: PluginKey<BlockContextMenuPluginState>;\n editor: Editor;\n turnIntoEnabled: boolean;\n turnIntoTargets: TurnIntoTarget[];\n copyLinkEnabled: boolean;\n onCopyLink: (blockId: string, editor: Editor) => string;\n blockColorEnabled: boolean;\n}\n\n/**\n * Default URL template for \"Copy link to block\" - appends `#<blockId>` to\n * the current pathname+search. Works for static sites; SPA hosts should\n * override via the `onCopyLink` option.\n */\nfunction defaultCopyLinkUrl(blockId: string): string {\n if (typeof window === 'undefined') return `#${blockId}`;\n const { pathname, search } = window.location;\n return `${pathname}${search}#${blockId}`;\n}\n\n/**\n * Shape of the custom event dispatched by BlockHandle when the user\n * clicks the drag handle without starting a drag.\n */\ninterface BlockContextMenuOpenDetail {\n blockPos: number;\n anchorElement: HTMLElement;\n}\n\n/**\n * Derive a selector that can re-locate an anchor button if its DOM identity\n * changes (e.g. the vanilla bubble menu rebuilding its trailing buttons via\n * `replaceChildren`). Returns `null` for anchors we cannot reliably re-resolve\n * (e.g. the BlockHandle drag button, which lives outside any bubble menu and\n * is keyed by absolute position, not class).\n */\nfunction matchingSelectorFor(anchor: HTMLElement): string | null {\n const ariaLabel = anchor.getAttribute('aria-label');\n if (ariaLabel) {\n const escaped = ariaLabel.replace(/\"/g, '\\\\\"');\n return `button[aria-label=\"${escaped}\"]`;\n }\n return null;\n}\n\n/**\n * Creates the BlockContextMenu ProseMirror plugin. Builds an absolutely\n * positioned popup DOM, listens for `dm:block-context-menu-open` on the\n * `.dm-editor` container, and executes block operations via the shared\n * helpers in `helpers/blockOperations.ts`.\n */\nexport function createBlockContextMenuPlugin(\n options: CreateBlockContextMenuPluginOptions,\n): Plugin {\n const { pluginKey, editor, turnIntoEnabled, turnIntoTargets, copyLinkEnabled, onCopyLink, blockColorEnabled } = options;\n\n // Cache optional-extension detection once at plugin construction. With\n // the standard `Extension.configure(...)` setup the extension list AND\n // its options are immutable for the editor's lifetime, so there's no\n // need to re-check on every menu open. `null` for each means the paired\n // extension isn't loaded (and the matching menu section is hidden).\n //\n // CONSTRAINT: hosts that re-register `uniqueID` / `blockColor` at\n // runtime (or live-mutate their options) won't see the change reflected\n // here - the menu would still read the values it captured at construction.\n // We don't support that flow today; if it becomes a need, move these\n // reads inside `renderItems()` so each open re-resolves fresh state.\n const uniqueIDExt = editor.extensionManager.extensions.find((ext) => ext.name === 'uniqueID');\n const uniqueIDAttrName: string | null = uniqueIDExt\n ? ((uniqueIDExt.options as UniqueIDOptionsShape).attributeName ?? 'id')\n : null;\n const uniqueIDGenerate: (() => string) | null = uniqueIDExt\n ? ((uniqueIDExt.options as UniqueIDOptionsShape).generateID ?? null)\n : null;\n\n const blockColorExt = editor.extensionManager.extensions.find((ext) => ext.name === 'blockColor');\n const blockColorOpts = blockColorExt\n ? (blockColorExt.options as BlockColorOptionsShape)\n : null;\n const blockColorTypes: string[] | null = blockColorOpts?.types ?? null;\n const blockBgPalette: string[] = blockColorOpts?.bgColors ?? [];\n const blockTextPalette: string[] = blockColorOpts?.textColors ?? [];\n\n // --- Build popup DOM once.\n const root = document.createElement('div');\n root.className = 'dm-block-context-menu';\n root.setAttribute('role', 'menu');\n root.setAttribute('aria-label', 'Block options');\n root.setAttribute('data-dm-editor-ui', '');\n\n let editorEl: HTMLElement | null = null;\n let cleanupFloating: (() => void) | null = null;\n let currentBlockPos: number | null = null;\n // Roving tabindex: which menuitem is currently focused. Initialised to 0\n // because the menu auto-focuses the first item on open.\n let focusedIndex = 0;\n let menuItemButtons: HTMLButtonElement[] = [];\n // Tracks the rAF id scheduled by `open()` for the initial focus so we\n // can cancel it if the menu closes before the frame fires (otherwise the\n // callback races with teardown and may focus a stale button).\n let initialFocusRaf: number | null = null;\n // Idempotency guard for the document-level wheel/touchmove listeners\n // that block page scroll while the menu is open.\n let scrollLocked = false;\n\n const isOpen = (): boolean => root.hasAttribute('data-show');\n\n /**\n * Suppresses page scroll while the menu is open. Native scroll\n * INSIDE the menu is allowed only when the menu actually has\n * scrollable overflow; without that check a short menu would let\n * wheel events bubble through and scroll the page.\n * `overscroll-behavior: contain` in the theme stops chaining at\n * the menu's scroll edges.\n */\n const onBlockScroll = (event: Event): void => {\n const target = event.target;\n if (target instanceof Node && root.contains(target)) {\n const hasOverflow = root.scrollHeight > root.clientHeight;\n if (hasOverflow) return;\n }\n event.preventDefault();\n };\n\n const lockScroll = (): void => {\n if (scrollLocked) return;\n scrollLocked = true;\n // `passive: false` is required so preventDefault() takes effect:\n // browsers default wheel/touchmove to passive for scroll perf.\n document.addEventListener('wheel', onBlockScroll, { passive: false });\n document.addEventListener('touchmove', onBlockScroll, { passive: false });\n };\n\n const unlockScroll = (): void => {\n if (!scrollLocked) return;\n scrollLocked = false;\n document.removeEventListener('wheel', onBlockScroll);\n document.removeEventListener('touchmove', onBlockScroll);\n };\n\n const hide = (): void => {\n if (initialFocusRaf !== null) {\n cancelAnimationFrame(initialFocusRaf);\n initialFocusRaf = null;\n }\n cleanupFloating?.();\n cleanupFloating = null;\n unlockScroll();\n editorEl?.removeAttribute('data-block-context-menu-open');\n // `editor.view` is undefined during the first `hide()` triggered\n // by plugin init - skip the dispatch in that case.\n const view = editor.view as typeof editor.view | undefined;\n if (view) {\n const tr = view.state.tr.setMeta(pluginKey, { activeBlockPos: null });\n tr.setMeta('addToHistory', false);\n view.dispatch(tr);\n }\n root.removeAttribute('data-show');\n currentBlockPos = null;\n menuItemButtons = [];\n focusedIndex = 0;\n };\n\n const focusItem = (index: number): void => {\n if (menuItemButtons.length === 0) return;\n const clamped = Math.max(0, Math.min(index, menuItemButtons.length - 1));\n // Roving tabindex: only the currently-focused item is in the Tab order.\n // Without this, Tab-away-and-back lands on the wrong item (WAI-ARIA menu pattern).\n for (let i = 0; i < menuItemButtons.length; i++) {\n const btn = menuItemButtons[i];\n if (btn) btn.tabIndex = i === clamped ? 0 : -1;\n }\n focusedIndex = clamped;\n menuItemButtons[clamped]?.focus();\n };\n\n /**\n * Executes a block operation, then closes the menu and returns focus to\n * the editor so the user can continue typing.\n */\n const runAndClose = (apply: (tr: Transaction) => void): void => {\n const tr = editor.view.state.tr;\n try {\n apply(tr);\n editor.view.dispatch(tr.scrollIntoView());\n } finally {\n hide();\n editor.view.focus();\n }\n };\n\n const runDelete = (): void => {\n if (currentBlockPos === null) return;\n const pos = currentBlockPos;\n runAndClose((tr) => { deleteBlock(tr, pos); });\n };\n\n const runDuplicate = (): void => {\n if (currentBlockPos === null) return;\n const pos = currentBlockPos;\n // When UniqueID is loaded, regenerate the id on the copy so it doesn't\n // collide with the source. All other attrs (colors, levels, etc.) are\n // preserved by spreading.\n const transformAttrs = uniqueIDAttrName && uniqueIDGenerate\n ? (attrs: Attrs): Attrs => ({ ...attrs, [uniqueIDAttrName]: uniqueIDGenerate() })\n : undefined;\n runAndClose((tr) => { duplicateBlock(tr, pos, transformAttrs); });\n };\n\n const runCopyLink = (blockId: string): void => {\n const url = onCopyLink(blockId, editor);\n void writeToClipboard(url).then((ok: boolean) => {\n // Semantic event split: `success` fires only when the write actually\n // succeeded, `error` fires otherwise. Host apps listen to one or both.\n // Detail carries the URL and id so the host can format its own message.\n const name = ok ? 'dm:copy-link-success' : 'dm:copy-link-error';\n editorEl?.dispatchEvent(new CustomEvent(name, {\n bubbles: false,\n detail: { url, blockId },\n }));\n });\n hide();\n editor.view.focus();\n };\n\n const runTurnInto = (target: TurnIntoTarget): void => {\n if (currentBlockPos === null) return;\n const sourceNode = editor.view.state.doc.nodeAt(currentBlockPos);\n if (!sourceNode) return;\n\n // When the targeted block is a wrapper (listItem / taskItem /\n // blockquote), descend to its inner first textblock so the wrapper\n // command operates on a valid textblock source. The filter in\n // renderItems guarantees we only reach here for wrapper targets\n // when source is a wrapper - textblock targets on wrapper sources\n // are filtered out upstream.\n const pos = sourceNode.type.isTextblock ? currentBlockPos : currentBlockPos + 1;\n\n // Wrapper targets (lists, blockquote) use the helper which routes\n // through the corresponding editor command. The command dispatches\n // its own transaction (with scrollIntoView), so we only need to\n // close the menu and restore focus afterwards.\n if (target.command) {\n turnIntoWrapper(editor, pos, target.command);\n hide();\n editor.view.focus();\n return;\n }\n // Textblock targets: position-precise setBlockType via the existing\n // pure helper. runAndClose handles dispatch + scrollIntoView + hide.\n const targetType = editor.view.state.schema.nodes[target.nodeType];\n if (!targetType) return;\n runAndClose((tr) => { turnIntoBlock(tr, pos, targetType, target.attrs); });\n };\n\n /**\n * Sets `bgColor` or `textColor` directly on the block at `currentBlockPos`\n * via `setNodeMarkup`. Bypasses the BlockColor command's ancestor walk\n * because the menu already knows which block was targeted. Inline color\n * marks of the same kind inside the block are stripped so the new block\n * tint wins (\"last action wins\"); see `stripInlineColorConflicts`.\n */\n const runSetColor = (attr: 'bgColor' | 'textColor', color: string | null): void => {\n if (currentBlockPos === null) return;\n const pos = currentBlockPos;\n runAndClose((tr) => {\n const n = tr.doc.nodeAt(pos);\n if (!n) return;\n tr.setNodeMarkup(pos, undefined, { ...n.attrs, [attr]: color });\n stripInlineColorConflicts(\n tr,\n editor.view.state,\n pos,\n pos + n.nodeSize,\n attr === 'textColor' ? 'text' : 'bg',\n );\n });\n };\n\n /**\n * Re-renders menu items based on the current target block. Hides \"Turn\n * into\" targets that match the current block's type (no-op conversions)\n * and filters \"Turn into\" entirely when the target type is not a textblock.\n */\n const renderItems = (blockPos: number): void => {\n root.innerHTML = '';\n menuItemButtons = [];\n\n const node = editor.view.state.doc.nodeAt(blockPos);\n if (!node) return;\n\n // --- Primary actions section\n const primaryGroup = document.createElement('div');\n primaryGroup.className = 'dm-block-context-menu-group';\n primaryGroup.setAttribute('role', 'group');\n\n primaryGroup.appendChild(\n makeItem('Delete', 'trash', runDelete),\n );\n if (node.type.name !== 'horizontalRule') {\n primaryGroup.appendChild(\n makeItem('Duplicate', 'copy', runDuplicate),\n );\n }\n // Copy link - only when UniqueID is loaded AND this block has an id attr\n // AND the feature is enabled. Items on paragraphs without an id (legacy\n // content) gracefully skip the item rather than copying an empty hash.\n if (copyLinkEnabled && uniqueIDAttrName) {\n const id = (node.attrs as Record<string, unknown>)[uniqueIDAttrName];\n if (typeof id === 'string' && id.length > 0) {\n primaryGroup.appendChild(\n makeItem('Copy link', 'link', () => { runCopyLink(id); }),\n );\n }\n }\n root.appendChild(primaryGroup);\n\n // --- Colors section (text color + background)\n // Shown only when BlockColor is loaded AND the target block type is in\n // its `types` list. The picker renders two rows of swatches (bg + text)\n // plus a \"clear\" swatch that unsets the attribute.\n if (blockColorEnabled && blockColorTypes?.includes(node.type.name)) {\n const label = document.createElement('div');\n label.className = 'dm-block-context-menu-group-label';\n label.textContent = 'Colors';\n root.appendChild(label);\n\n const currentBg = (node.attrs as Record<string, unknown>)['bgColor'] as string | null;\n const currentText = (node.attrs as Record<string, unknown>)['textColor'] as string | null;\n\n root.appendChild(\n buildSwatchRow(\n 'Text color',\n 'text',\n blockTextPalette,\n currentText,\n (color) => { runSetColor('textColor', color); },\n ),\n );\n root.appendChild(\n buildSwatchRow(\n 'Background',\n 'bg',\n blockBgPalette,\n currentBg,\n (color) => { runSetColor('bgColor', color); },\n ),\n );\n }\n\n // --- Turn into section. Two source modes:\n //\n // A. Textblock source (paragraph, heading, codeBlock): both\n // textblock and wrapper targets are eligible (subject to filter).\n // B. Wrapper source (listItem, taskItem, blockquote whose first\n // child is a textblock): only wrapper targets are eligible,\n // and we descend to the inner textblock for the ancestor walk.\n // Textblock targets would need a lift-then-convert step that\n // is out of scope - they're filtered out.\n //\n // Pure non-textblock atoms (HR) and wrapper-of-wrapper (bulletList\n // whose first child is listItem, not a textblock) hide Turn into\n // entirely - Notion matches this.\n const sourceIsTextblock = node.type.isTextblock;\n const sourceIsWrapper = !sourceIsTextblock && node.firstChild?.isTextblock === true;\n if (turnIntoEnabled && (sourceIsTextblock || sourceIsWrapper)) {\n // For wrapper sources, the ancestor walk starts at the inner\n // textblock (blockPos + 1 = past the wrapper opening token) so\n // it picks up listItem / taskList / blockquote correctly.\n const ancestorPos = sourceIsTextblock ? blockPos : blockPos + 1;\n const $pos = editor.view.state.doc.resolve(ancestorPos);\n const ancestorTypeNames = new Set<string>();\n for (let d = 0; d <= $pos.depth; d++) {\n ancestorTypeNames.add($pos.node(d).type.name);\n }\n\n // listItem / taskItem schema requires their FIRST child to be a\n // paragraph. Calling toggleBlockquote on that inner paragraph\n // would try to make blockquote the first child, which the schema\n // rejects. Hide the Quote target upfront to avoid a clickable-\n // but-no-op item.\n const isListItemFamilySource =\n node.type.name === 'listItem' || node.type.name === 'taskItem';\n\n const eligible = turnIntoTargets.filter((target) => {\n const type = editor.view.state.schema.nodes[target.nodeType];\n if (!type) return false;\n\n // Wrapper target (toggleList / toggleBlockquote). Hide when an\n // ancestor of the same type already wraps the block - Notion-\n // style \"you're already there, no point offering\".\n if (target.command) {\n if (ancestorTypeNames.has(target.nodeType)) return false;\n if (target.command === 'toggleBlockquote' && isListItemFamilySource) return false;\n return true;\n }\n\n // Textblock target. Only valid when source is itself a textblock.\n // Wrapper sources need lift-then-convert (out of scope).\n if (!sourceIsTextblock) return false;\n if (!type.isTextblock) return false;\n // Skip targets identical to the current block (same node type AND\n // matching attrs - e.g. hide \"Heading 1\" when already on H1).\n if (type.name !== node.type.name) return true;\n const targetAttrs = target.attrs;\n if (!targetAttrs) return false;\n const nodeAttrs = node.attrs as Record<string, unknown>;\n for (const k of Object.keys(targetAttrs)) {\n if (nodeAttrs[k] !== (targetAttrs as Record<string, unknown>)[k]) return true;\n }\n return false;\n });\n\n if (eligible.length > 0) {\n const label = document.createElement('div');\n label.className = 'dm-block-context-menu-group-label';\n label.textContent = 'Turn into';\n root.appendChild(label);\n\n const group = document.createElement('div');\n group.className = 'dm-block-context-menu-group';\n group.setAttribute('role', 'group');\n group.setAttribute('aria-label', 'Turn into');\n\n for (const target of eligible) {\n group.appendChild(\n makeItem(target.label, target.icon, () => { runTurnInto(target); }),\n );\n }\n root.appendChild(group);\n }\n }\n };\n\n /**\n * Construct the chrome shared by every menu button (regular item + color\n * swatch): role=menuitem, roving-tabindex registration, mousedown\n * preventDefault (keeps editor focus), click handler.\n */\n const createMenuButton = (config: {\n className: string;\n ariaLabel: string;\n onClick: () => void;\n attributes?: Record<string, string>;\n }): HTMLButtonElement => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = config.className;\n btn.setAttribute('role', 'menuitem');\n btn.setAttribute('aria-label', config.ariaLabel);\n if (config.attributes) {\n for (const [k, v] of Object.entries(config.attributes)) {\n btn.setAttribute(k, v);\n }\n }\n btn.tabIndex = menuItemButtons.length === 0 ? 0 : -1;\n btn.addEventListener('mousedown', (e: MouseEvent) => { e.preventDefault(); });\n btn.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault();\n config.onClick();\n });\n menuItemButtons.push(btn);\n return btn;\n };\n\n /** Helper to construct a menuitem button (icon + label) and register it for nav. */\n const makeItem = (\n label: string,\n iconKey: string,\n onClick: () => void,\n ): HTMLButtonElement => {\n const btn = createMenuButton({\n className: 'dm-block-context-menu-item',\n ariaLabel: label,\n onClick,\n });\n\n // Build DOM safely: icon SVG is trusted (from our own phosphor set), but\n // `label` may come from user-supplied `turnIntoTargets` config - use\n // textContent for any string that could originate outside this package.\n const iconHTML = defaultIcons[iconKey] ?? '';\n const iconSpan = document.createElement('span');\n iconSpan.className = 'dm-block-context-menu-item-icon';\n iconSpan.setAttribute('aria-hidden', 'true');\n iconSpan.innerHTML = iconHTML;\n\n const labelSpan = document.createElement('span');\n labelSpan.className = 'dm-block-context-menu-item-label';\n labelSpan.textContent = label;\n\n btn.appendChild(iconSpan);\n btn.appendChild(labelSpan);\n return btn;\n };\n\n /**\n * Build a single color-picker swatch. `null` color becomes a \"clear\"\n * swatch (unset the attribute). Swatches participate in roving-tabindex\n * keyboard nav alongside menu items.\n */\n const makeSwatch = (\n variant: 'bg' | 'text',\n color: string | null,\n current: string | null,\n onClick: (c: string | null) => void,\n ): HTMLButtonElement => {\n const ariaLabel = color === null\n ? (variant === 'bg' ? 'No background' : 'Default text color')\n : `${variant === 'bg' ? 'Background' : 'Text color'}: ${color}`;\n const isPressed = (current === color || (color === null && !current));\n return createMenuButton({\n className: `dm-block-color-swatch dm-block-color-swatch--${variant}`,\n ariaLabel,\n onClick: () => { onClick(color); },\n attributes: {\n 'data-color': color ?? 'null',\n 'aria-pressed': isPressed ? 'true' : 'false',\n },\n });\n };\n\n /**\n * Compose a labelled swatch row (a strip of color buttons) for either\n * text color or background. The first entry is always a \"clear\" swatch\n * that unsets the attribute.\n */\n const buildSwatchRow = (\n rowLabel: string,\n variant: 'bg' | 'text',\n palette: string[],\n current: string | null,\n onClick: (color: string | null) => void,\n ): HTMLElement => {\n const row = document.createElement('div');\n row.className = 'dm-block-color-row';\n row.setAttribute('role', 'group');\n row.setAttribute('aria-label', rowLabel);\n\n const visuallyHidden = document.createElement('span');\n visuallyHidden.className = 'dm-block-color-row-label';\n visuallyHidden.textContent = rowLabel;\n row.appendChild(visuallyHidden);\n\n row.appendChild(makeSwatch(variant, null, current, onClick));\n for (const c of palette) {\n row.appendChild(makeSwatch(variant, c, current, onClick));\n }\n return row;\n };\n\n /**\n * Opens the menu anchored to `anchorElement`, targeting `blockPos`.\n * Dispatches `dm:dismiss-overlays` first so any other chrome closes.\n *\n * `detail.blockPos` is whatever block the dispatcher (BlockHandle)\n * resolved under the cursor - this includes nested list items when\n * `BlockHandle.nested` is enabled. Using `findTopLevelBlock` here\n * would walk past those and target the wrapping list, which would\n * mean a \"Delete\" click on a single list item nukes the entire list\n * (the user's reported bug).\n */\n const open = (detail: BlockContextMenuOpenDetail): void => {\n if (!editorEl) return;\n\n const node = editor.view.state.doc.nodeAt(detail.blockPos);\n if (!node) return;\n\n currentBlockPos = detail.blockPos;\n renderItems(detail.blockPos);\n if (menuItemButtons.length === 0) return;\n\n // Must set the cross-plugin signal BEFORE the dismiss dispatch\n // so BlockHandle's dismiss listener can distinguish \"menu opening\"\n // from \"another overlay dismissing me\" and keep the drag handle\n // anchored.\n editorEl.setAttribute('data-block-context-menu-open', '');\n editorEl.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n root.setAttribute('data-show', '');\n lockScroll();\n {\n const tr = editor.view.state.tr.setMeta(pluginKey, { activeBlockPos: detail.blockPos });\n tr.setMeta('addToHistory', false);\n editor.view.dispatch(tr);\n }\n\n cleanupFloating?.();\n // Virtual reference: caches the last valid rect and returns it when the\n // anchor element later becomes disconnected. Vanilla bubble menus rebuild\n // their DOM via `replaceChildren()` on every editor transaction, which\n // orphans the anchor we were given; without this caching, `autoUpdate`\n // re-computes against a zero rect and the menu flies to the corner.\n let anchorEl: HTMLElement = detail.anchorElement;\n const bubbleMenuRef = anchorEl.closest<HTMLElement>('.dm-bubble-menu');\n const matchingSelector = matchingSelectorFor(anchorEl);\n let lastRect = anchorEl.getBoundingClientRect();\n const virtualRef: { getBoundingClientRect: () => DOMRect } = {\n getBoundingClientRect: () => {\n if (anchorEl.isConnected) {\n lastRect = anchorEl.getBoundingClientRect();\n return lastRect;\n }\n // Anchor disconnected. Try to find an equivalent in the same bubble\n // menu (where applicable) so the menu tracks live DOM rather than\n // pinning to the now-stale rect.\n if (matchingSelector && bubbleMenuRef?.isConnected) {\n const fresh = bubbleMenuRef.querySelector<HTMLElement>(matchingSelector);\n if (fresh) {\n anchorEl = fresh;\n lastRect = fresh.getBoundingClientRect();\n return lastRect;\n }\n }\n return lastRect;\n },\n };\n cleanupFloating = positionFloatingOnce(virtualRef, root, {\n placement: 'right-start',\n offsetValue: 4,\n });\n\n // Focus first menu item so keyboard users can Arrow through immediately.\n focusedIndex = 0;\n // Wait for layout so the focus call sees the newly visible element.\n // Track the rAF id so `hide()` can cancel it if the menu closes before\n // the frame fires.\n initialFocusRaf = requestAnimationFrame(() => {\n initialFocusRaf = null;\n menuItemButtons[0]?.focus();\n });\n };\n\n // --- Event handlers\n const onOpen = (event: Event): void => {\n // CustomEvent<T> extends Event so the downcast is safe; we widen detail\n // to `T | undefined` to keep the runtime guard for cases where a plain\n // Event was dispatched without detail.\n const detail = (event as CustomEvent<BlockContextMenuOpenDetail | undefined>).detail;\n if (!detail) return;\n open(detail);\n };\n\n const onDismiss = (): void => {\n if (!isOpen()) return;\n hide();\n };\n\n const onClickOutside = (event: Event): void => {\n if (!isOpen()) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (root.contains(target)) return;\n hide();\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n if (!isOpen()) return;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusItem((focusedIndex + 1) % menuItemButtons.length);\n return;\n case 'ArrowUp':\n event.preventDefault();\n focusItem((focusedIndex - 1 + menuItemButtons.length) % menuItemButtons.length);\n return;\n case 'Home':\n event.preventDefault();\n focusItem(0);\n return;\n case 'End':\n event.preventDefault();\n focusItem(menuItemButtons.length - 1);\n return;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n hide();\n editor.view.focus();\n return;\n default:\n return;\n }\n };\n\n return new Plugin<BlockContextMenuPluginState>({\n key: pluginKey,\n state: {\n init: () => ({ activeBlockPos: null }),\n apply(tr, value) {\n const meta = tr.getMeta(pluginKey) as { activeBlockPos?: number | null } | undefined;\n if (meta && 'activeBlockPos' in meta) {\n return { activeBlockPos: meta.activeBlockPos ?? null };\n }\n // Re-map across doc changes so the highlight tracks structural edits.\n if (value.activeBlockPos !== null && tr.docChanged) {\n const mapped = tr.mapping.mapResult(value.activeBlockPos, 1);\n return { activeBlockPos: mapped.deleted ? null : mapped.pos };\n }\n return value;\n },\n },\n props: {\n decorations(state) {\n const plugin = pluginKey.getState(state);\n const activePos = plugin?.activeBlockPos ?? null;\n if (activePos === null) return null;\n const node = state.doc.nodeAt(activePos);\n if (!node) return null;\n return DecorationSet.create(state.doc, [\n Decoration.node(activePos, activePos + node.nodeSize, { class: 'dm-block-context-active' }),\n ]);\n },\n },\n\n view: (editorView) => {\n editorEl = editorView.dom.closest('.dm-editor');\n if (!editorEl) return { destroy: () => { /* noop */ } };\n\n editorEl.appendChild(root);\n hide();\n\n editorEl.addEventListener('dm:block-context-menu-open', onOpen);\n editorEl.addEventListener('dm:dismiss-overlays', onDismiss);\n document.addEventListener('mousedown', onClickOutside, true);\n root.addEventListener('keydown', onKeyDown);\n\n return {\n destroy: () => {\n hide();\n editorEl?.removeEventListener('dm:block-context-menu-open', onOpen);\n editorEl?.removeEventListener('dm:dismiss-overlays', onDismiss);\n document.removeEventListener('mousedown', onClickOutside, true);\n root.removeEventListener('keydown', onKeyDown);\n root.remove();\n editorEl = null;\n },\n };\n },\n });\n}\n\nexport const BlockContextMenu = Extension.create<BlockContextMenuOptions>({\n name: 'blockContextMenu',\n\n addOptions() {\n return {\n turnIntoEnabled: true,\n turnIntoTargets: DEFAULT_TURN_INTO,\n copyLinkEnabled: true,\n onCopyLink: defaultCopyLinkUrl,\n blockColorEnabled: true,\n };\n },\n\n addProseMirrorPlugins() {\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n // `addOptions()` provides defaults, but the public option interface\n // marks each field optional so consumers can pass a partial config.\n // Re-applying defaults here narrows the types back to non-optional\n // for the plugin factory.\n const opts = this.options;\n return [\n createBlockContextMenuPlugin({\n pluginKey: blockContextMenuPluginKey,\n editor,\n turnIntoEnabled: opts.turnIntoEnabled ?? true,\n turnIntoTargets: opts.turnIntoTargets ?? DEFAULT_TURN_INTO,\n copyLinkEnabled: opts.copyLinkEnabled ?? true,\n onCopyLink: opts.onCopyLink ?? defaultCopyLinkUrl,\n blockColorEnabled: opts.blockColorEnabled ?? true,\n }),\n ];\n },\n});\n","/**\n * Default DOM renderer factory for SlashCommand.\n *\n * Returns `{ onStart, onUpdate, onExit, onKeyDown }` callbacks that build\n * and manage a grouped popup anchored at the cursor. Mirrors the\n * Mention/Emoji suggestion renderer pattern so consumers already familiar\n * with those APIs have zero learning curve.\n *\n * The popup DOM reuses the same visual vocabulary as FloatingMenu:\n * `role=\"menu\"` container, `role=\"group\"` sections, `role=\"menuitem\"`\n * buttons with `icon + label + shortcut chip` layout. A dedicated\n * `dm-slash-command-menu` root class scopes SCSS overrides.\n */\nimport {\n defaultIcons,\n groupFloatingMenuItems,\n positionFloatingOnce,\n} from '@domternal/core';\nimport type { FloatingMenuItem } from '@domternal/core';\nimport type { SlashCommandProps, SlashCommandRenderer } from './SlashCommand.js';\n\n// Module-level counter for unique id suffixes - lets us set\n// `aria-activedescendant` on the menu root so screen readers announce the\n// selection as the user arrow-keys through items.\nlet idCounter = 0;\n\nexport function createSlashSuggestionRenderer(): SlashCommandRenderer {\n let root: HTMLDivElement | null = null;\n let cleanupFloating: (() => void) | null = null;\n // Flat list of rendered menuitem buttons, parallel to filtered item list.\n let itemButtons: HTMLButtonElement[] = [];\n let flatItems: FloatingMenuItem[] = [];\n let selectedIndex = 0;\n let currentCommand: SlashCommandProps['command'] | null = null;\n // Flag set during onExit so any pending event that was already queued\n // (e.g. a trailing mousedown+click after the teardown starts) can bail\n // instead of dispatching into a now-destroyed editor.\n let destroyed = false;\n const rendererId = `dm-slash-${String(++idCounter)}`;\n\n const renderPopup = (props: SlashCommandProps): void => {\n if (!root) return;\n root.innerHTML = '';\n itemButtons = [];\n flatItems = [];\n\n if (props.items.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'dm-slash-command-empty';\n // `role=\"status\"` + `aria-live=\"polite\"` makes screen readers\n // announce the filter result change without stealing focus.\n empty.setAttribute('role', 'status');\n empty.setAttribute('aria-live', 'polite');\n empty.textContent = 'No matches';\n root.appendChild(empty);\n return;\n }\n\n const groups = groupFloatingMenuItems(props.items);\n for (const group of groups) {\n if (group.name) {\n const label = document.createElement('div');\n label.className = 'dm-slash-command-group-label';\n label.textContent = group.name;\n root.appendChild(label);\n }\n const groupEl = document.createElement('div');\n groupEl.className = 'dm-slash-command-group';\n groupEl.setAttribute('role', 'group');\n if (group.name) groupEl.setAttribute('aria-label', group.name);\n\n for (const item of group.items) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'dm-slash-command-item';\n btn.setAttribute('role', 'menuitem');\n btn.setAttribute('aria-label', item.label);\n btn.tabIndex = -1;\n // Stable id per-button so the root element can set\n // `aria-activedescendant` to announce the current selection.\n btn.id = `${rendererId}-item-${String(flatItems.length)}`;\n\n // Build DOM safely: only the icon SVG (from our trusted phosphor\n // set) is interpolated as HTML. label / description / shortcut use\n // textContent since FloatingMenuItem fields may come from arbitrary\n // extension authors and could carry unescaped HTML/scripts.\n const iconHTML = item.icon ? (defaultIcons[item.icon] ?? '') : '';\n if (iconHTML) {\n const iconSpan = document.createElement('span');\n iconSpan.className = 'dm-slash-command-item-icon';\n iconSpan.setAttribute('aria-hidden', 'true');\n iconSpan.innerHTML = iconHTML;\n btn.appendChild(iconSpan);\n }\n\n const textSpan = document.createElement('span');\n textSpan.className = 'dm-slash-command-item-text';\n\n const labelSpan = document.createElement('span');\n labelSpan.className = 'dm-slash-command-item-label';\n labelSpan.textContent = item.label;\n textSpan.appendChild(labelSpan);\n\n if (item.description) {\n const descSpan = document.createElement('span');\n descSpan.className = 'dm-slash-command-item-description';\n descSpan.textContent = item.description;\n textSpan.appendChild(descSpan);\n }\n\n btn.appendChild(textSpan);\n\n if (item.shortcut) {\n const shortcutSpan = document.createElement('span');\n shortcutSpan.className = 'dm-slash-command-item-shortcut';\n shortcutSpan.setAttribute('aria-hidden', 'true');\n shortcutSpan.textContent = item.shortcut;\n btn.appendChild(shortcutSpan);\n }\n\n const indexForItem = flatItems.length;\n btn.addEventListener('mousedown', (e: MouseEvent) => { e.preventDefault(); });\n btn.addEventListener('mouseenter', () => { selectItem(indexForItem); });\n btn.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault();\n // Guard against post-teardown clicks: a mousedown-to-click pair\n // can span `onExit` if the user was holding the mouse button\n // when the popup was dismissed by an outside event.\n if (destroyed) return;\n currentCommand?.(item);\n });\n\n itemButtons.push(btn);\n flatItems.push(item);\n groupEl.appendChild(btn);\n }\n root.appendChild(groupEl);\n }\n\n if (selectedIndex >= flatItems.length) selectedIndex = 0;\n highlight(selectedIndex);\n };\n\n const highlight = (index: number): void => {\n for (const [i, btn] of itemButtons.entries()) {\n if (i === index) {\n btn.setAttribute('data-selected', '');\n } else {\n btn.removeAttribute('data-selected');\n }\n }\n const selected = itemButtons[index];\n // Scroll the selected item into view WITHIN the popup only - never via\n // `scrollIntoView`, which walks ancestors and would yank the page when\n // called during `renderPopup` (runs before `positionFloatingOnce`\n // resolves, so the popup is still at its natural flow position at the\n // bottom of `.dm-editor`).\n if (root && selected) {\n const btnTop = selected.offsetTop;\n const btnBottom = btnTop + selected.offsetHeight;\n const viewTop = root.scrollTop;\n const viewBottom = viewTop + root.clientHeight;\n if (btnTop < viewTop) root.scrollTop = btnTop;\n else if (btnBottom > viewBottom) root.scrollTop = btnBottom - root.clientHeight;\n root.setAttribute('aria-activedescendant', selected.id);\n } else {\n root?.removeAttribute('aria-activedescendant');\n }\n };\n\n const selectItem = (index: number): void => {\n if (index < 0 || index >= itemButtons.length) return;\n selectedIndex = index;\n highlight(index);\n };\n\n const reposition = (props: SlashCommandProps): void => {\n if (!root) return;\n cleanupFloating?.();\n // Pass a callable virtualRef so floating-ui's autoUpdate reads fresh\n // cursor coords on every tick (scroll, resize). Capturing a single rect\n // at call time would freeze the anchor and the popup would drift on\n // scroll. Mirrors the emoji suggestion renderer's pattern.\n const virtualRef = {\n getBoundingClientRect: (): DOMRect => props.clientRect() ?? new DOMRect(),\n };\n cleanupFloating = positionFloatingOnce(\n virtualRef,\n root,\n { placement: 'bottom-start', offsetValue: 4 },\n );\n };\n\n return {\n onStart(props): void {\n currentCommand = props.command;\n selectedIndex = 0;\n destroyed = false;\n\n root = document.createElement('div');\n root.className = 'dm-slash-command-menu';\n root.setAttribute('role', 'menu');\n root.setAttribute('aria-label', 'Insert block');\n root.setAttribute('data-dm-editor-ui', '');\n\n const editorEl = props.element.closest('.dm-editor');\n (editorEl ?? document.body).appendChild(root);\n root.setAttribute('data-show', '');\n\n renderPopup(props);\n reposition(props);\n },\n\n onUpdate(props): void {\n currentCommand = props.command;\n if (!root) return;\n renderPopup(props);\n reposition(props);\n },\n\n onExit(): void {\n destroyed = true;\n cleanupFloating?.();\n cleanupFloating = null;\n root?.remove();\n root = null;\n itemButtons = [];\n flatItems = [];\n selectedIndex = 0;\n currentCommand = null;\n },\n\n onKeyDown(event): boolean {\n if (!root || flatItems.length === 0) return false;\n\n switch (event.key) {\n case 'ArrowDown':\n selectItem((selectedIndex + 1) % flatItems.length);\n return true;\n case 'ArrowUp':\n selectItem((selectedIndex - 1 + flatItems.length) % flatItems.length);\n return true;\n case 'Home':\n selectItem(0);\n return true;\n case 'End':\n selectItem(flatItems.length - 1);\n return true;\n case 'Enter':\n case 'Tab': {\n const item = flatItems[selectedIndex];\n if (item && currentCommand) currentCommand(item);\n return true;\n }\n default:\n return false;\n }\n },\n };\n}\n","/**\n * `/` trigger that opens a filtered popup of insertable blocks. Items are\n * shared with FloatingMenu and BlockHandle via `addFloatingMenuItems()`.\n * On select, the `/query` range is deleted and the item's command runs at\n * the now-empty cursor (so \"Heading 1\" transforms the block, \"Image\" opens\n * its popover, etc.).\n */\nimport {\n Extension,\n FloatingMenuController,\n} from '@domternal/core';\nimport type {\n Editor,\n FloatingMenuItem,\n FloatingMenuItemsOverride,\n} from '@domternal/core';\nimport { Plugin, PluginKey } from '@domternal/pm/state';\nimport type { EditorState, Transaction } from '@domternal/pm/state';\nimport type { EditorView } from '@domternal/pm/view';\nimport { Decoration, DecorationSet } from '@domternal/pm/view';\nimport { ReplaceStep } from '@domternal/pm/transform';\nimport { createSlashSuggestionRenderer } from './createSlashSuggestionRenderer.js';\n\nexport const slashCommandPluginKey = new PluginKey<SlashCommandPluginState>('slashCommand');\n\n// Object Replacement Character. ProseMirror uses U+FFFC as a placeholder\n// for non-text leaf nodes when flattening a range to a string, so we never\n// want a real query char to collide with it.\nconst PM_LEAF_PLACEHOLDER = '';\n\n// ─── Public renderer contract ─────────────────────────────────────────────\n\nexport interface SlashCommandProps {\n /** The editor instance (passed so custom renderers can read state). */\n editor: Editor;\n /** Current query string (text after the `/`). */\n query: string;\n /** Document range of the `/` + query (for replacement). */\n range: { from: number; to: number };\n /** Filtered and ranked items matching the query. */\n items: FloatingMenuItem[];\n /** Execute the selected item and close the popup. */\n command: (item: FloatingMenuItem) => void;\n /** Returns the client rect of the cursor for positioning the popup. */\n clientRect: () => DOMRect | null;\n /** The editor's ProseMirror DOM node (for portal parents etc.). */\n element: HTMLElement;\n}\n\nexport interface SlashCommandRenderer {\n onStart: (props: SlashCommandProps) => void;\n onUpdate: (props: SlashCommandProps) => void;\n onExit: () => void;\n /** Return `true` to consume the key event and prevent default handling. */\n onKeyDown: (event: KeyboardEvent) => boolean;\n}\n\n// ─── Options ──────────────────────────────────────────────────────────────\n\nexport interface SlashCommandOptions {\n /**\n * The trigger character. @default '/'\n */\n char?: string;\n /**\n * Items override. When omitted, items from `editor.floatingMenuItems`\n * (collected via `addFloatingMenuItems()`) are used. An array replaces\n * defaults; a function transforms them.\n */\n items?: FloatingMenuItemsOverride;\n /**\n * Factory returning render callbacks for the popup. Default uses\n * `createSlashSuggestionRenderer()`.\n */\n render?: () => SlashCommandRenderer;\n /**\n * Node types where slash should NOT activate (e.g. `codeBlock`).\n * @default ['codeBlock']\n */\n invalidNodes?: string[];\n}\n\nexport interface CreateSlashCommandPluginOptions {\n pluginKey: PluginKey<SlashCommandPluginState>;\n editor: Editor;\n char: string;\n items?: FloatingMenuItemsOverride;\n render: () => SlashCommandRenderer;\n invalidNodes: string[];\n}\n\n// ─── Internal state ───────────────────────────────────────────────────────\n\nexport interface SlashCommandPluginState {\n active: boolean;\n query: string;\n range: { from: number; to: number } | null;\n}\n\nconst INITIAL_STATE: SlashCommandPluginState = {\n active: false,\n query: '',\n range: null,\n};\n\n/**\n * Returns `true` only when the transaction's effect was inserting EXACTLY\n * the trigger character as a single ReplaceStep with a single-char text\n * slice (no opening/closing depth, no surrounding inserted content).\n *\n * This is the \"did the user just type `/`\" heuristic that gates popup\n * activation. It distinguishes:\n * - real typing (`/`) ✓\n * - typing `/` while a range was selected ✓ (one ReplaceStep, slice \"/\")\n * - paste of `/text...` ✗ (slice.size > 1)\n * - programmatic `insertContent('/foo')` ✗ (slice.size > 1)\n * - selection-only changes (click/arrow) ✗ (no steps)\n * - undo/redo creating a `/` ✗ (multi-step / non-Replace)\n *\n * Rationale: tying activation to the typing event - not to the static\n * presence of `/` before the cursor - matches Notion. Once a slash session\n * is dismissed, the same `/` becomes plain text and doesn't reopen the\n * popup if the user later clicks back next to it.\n */\nfunction justTypedTrigger(tr: Transaction, char: string): boolean {\n if (tr.steps.length !== 1) return false;\n const step = tr.steps[0];\n if (!(step instanceof ReplaceStep)) return false;\n const slice = step.slice;\n if (slice.size !== 1 || slice.openStart !== 0 || slice.openEnd !== 0) return false;\n const node = slice.content.firstChild;\n return !!(node && node.isText && node.text === char);\n}\n\n/**\n * Resolves the current `/query` at the cursor, if any. Returns null if the\n * cursor isn't after a `/` on a qualifying line.\n */\nfunction findSlashQuery(\n state: EditorState,\n triggerChar: string,\n invalidNodes: string[],\n): { query: string; range: { from: number; to: number } } | null {\n const { selection } = state;\n if (!selection.empty) return null;\n\n const { $from } = selection;\n // Disallow in code blocks and any explicitly blocked node types.\n if ($from.parent.type.spec.code) return null;\n if (invalidNodes.includes($from.parent.type.name)) return null;\n\n const textBefore = $from.parent.textBetween(\n 0,\n $from.parentOffset,\n undefined,\n PM_LEAF_PLACEHOLDER,\n );\n const triggerIndex = textBefore.lastIndexOf(triggerChar);\n if (triggerIndex === -1) return null;\n\n // Trigger must be at textblock start OR preceded by whitespace.\n if (triggerIndex > 0 && !/\\s/.test(textBefore[triggerIndex - 1] ?? '')) return null;\n\n const queryText = textBefore.slice(triggerIndex + triggerChar.length);\n // Block queries that contain newlines or tabs (they'd break display).\n if (/[\\n\\t]/.test(queryText)) return null;\n\n const from = $from.start() + triggerIndex;\n const to = $from.pos;\n return { query: queryText, range: { from, to } };\n}\n\n/**\n * Removes items whose `hideWhenInside` matches the cursor's wrapping\n * list type WHEN the cursor sits in the LABEL paragraph of a list-item\n * (the first-child slot). Picking the same list type from a label would\n * lift the user out of the list (PM `liftListItem` semantics) - that's\n * surprising, so we hide the option.\n *\n * The CHILDREN-ZONE case (cursor in a non-first paragraph of a list\n * item) is preserved on purpose: picking the same list type there\n * creates a nested sublist, which is useful and Notion-like.\n */\nexport function filterByCursorAncestors(\n items: FloatingMenuItem[],\n editor: Editor,\n): FloatingMenuItem[] {\n const { $from } = editor.view.state.selection;\n\n // Find the cursor's nearest list-item ancestor; if cursor is in the\n // LABEL slot of that item, record its wrapping list's type name.\n let wrappingListType: string | null = null;\n for (let d = $from.depth; d >= 1; d--) {\n const t = $from.node(d).type.name;\n if (t === 'listItem' || t === 'taskItem') {\n if ($from.index(d) === 0 && d >= 1) {\n wrappingListType = $from.node(d - 1).type.name;\n }\n break;\n }\n }\n\n return items.filter((item) => {\n if (!item.hideWhenInside || item.hideWhenInside.length === 0) return true;\n if (!wrappingListType) return true;\n return !item.hideWhenInside.includes(wrappingListType);\n });\n}\n\n/**\n * Filters and ranks FloatingMenuItems against a query. Priority:\n * 1. Exact label prefix (case-insensitive)\n * 2. Label substring match\n * 3. Keyword match (preserving original keyword index for stable ranking)\n * Returns items in rank order, stable within the same rank.\n */\nexport function filterSlashItems(items: FloatingMenuItem[], query: string): FloatingMenuItem[] {\n if (query.length === 0) return items;\n const q = query.toLowerCase();\n\n const ranked: { item: FloatingMenuItem; score: number }[] = [];\n for (const item of items) {\n const label = item.label.toLowerCase();\n if (label.startsWith(q)) {\n ranked.push({ item, score: 0 });\n continue;\n }\n if (label.includes(q)) {\n ranked.push({ item, score: 1 });\n continue;\n }\n const keywords = item.keywords ?? [];\n const kwIndex = keywords.findIndex((k) => k.toLowerCase().includes(q));\n if (kwIndex !== -1) {\n ranked.push({ item, score: 2 + kwIndex * 0.01 });\n }\n }\n ranked.sort((a, b) => a.score - b.score);\n return ranked.map((r) => r.item);\n}\n\n// ─── Plugin factory ───────────────────────────────────────────────────────\n\nexport function createSlashCommandPlugin(\n options: CreateSlashCommandPluginOptions,\n): Plugin<SlashCommandPluginState> {\n const { pluginKey, editor, char, items: itemsOverride, render, invalidNodes } = options;\n let renderer: SlashCommandRenderer | null = null;\n\n return new Plugin<SlashCommandPluginState>({\n key: pluginKey,\n\n state: {\n init: (): SlashCommandPluginState => ({ ...INITIAL_STATE }),\n apply(tr: Transaction, prev, _oldState, newState): SlashCommandPluginState {\n if (tr.getMeta(pluginKey) === 'dismiss') return { ...INITIAL_STATE };\n\n // Neither doc nor selection changed - nothing to do (popup stays as-is).\n if (!tr.docChanged && !tr.selectionSet) return prev;\n\n // ── Branch 1: popup was ALREADY active ─────────────────────────\n //\n // The query is the text between the trigger position (`range.from`)\n // and the typed-end position (`range.to`). Crucially, `range.to`\n // tracks WHAT THE USER TYPED, not the current cursor. That way\n // navigating the cursor with arrow keys past existing text does\n // not \"swallow\" surrounding chars into the query.\n //\n // Rules per transaction kind:\n // - docChange (typing / backspace / paste / collab):\n // * map both range bounds forward through tr.mapping\n // * if the trigger position itself was deleted, dismiss\n // * if the char at `range.from` is no longer the trigger,\n // dismiss (the `/` got replaced or pushed away)\n // * if the cursor moved PAST the mapped `to`, the user\n // typed more chars at the end - extend `to` to cursor\n // - selection-only (mouse click / arrow key without typing):\n // * cursor must remain in the typed query span\n // [from + 1, to]. Stepping out either end dismisses.\n // Mid-query navigation keeps the popup open with the\n // same query.\n // - non-empty selection (shift+arrow drag): dismiss.\n if (prev.active && prev.range) {\n let { from, to } = prev.range;\n\n if (tr.docChanged) {\n // bias = 1 (default, right): an insertion AT the trigger\n // position pushes the `/` forward; we want our `from` to\n // follow it. Same bias for `to` so a typed char inserted\n // exactly at the end of the query extends the range.\n const fromResult = tr.mapping.mapResult(from);\n const toResult = tr.mapping.mapResult(to);\n if (fromResult.deleted) return { ...INITIAL_STATE };\n from = fromResult.pos;\n to = toResult.pos;\n\n // The char that was the trigger may have been replaced\n // (e.g. autocomplete inserting AT `from`, or the user\n // pasting over it). If so, the session is gone.\n if (\n newState.doc.textBetween(from, from + 1, undefined, PM_LEAF_PLACEHOLDER) !== char\n ) {\n return { ...INITIAL_STATE };\n }\n }\n\n // Range selections (shift+arrow, click-drag) make no sense for\n // a single-cursor suggestion popup.\n if (!newState.selection.empty) return { ...INITIAL_STATE };\n const cursor = newState.selection.from;\n\n // Cursor must remain at or after the first char of the query\n // (i.e. at-or-past the position immediately after `/`).\n if (cursor < from + 1) return { ...INITIAL_STATE };\n\n if (cursor > to) {\n // Past the typed end: only legal as the natural side-effect\n // of typing more chars (cursor moves forward by the inserted\n // length). A pure selection move past `to` (arrow-right past\n // existing text) means the user left the typing session.\n if (!tr.docChanged) return { ...INITIAL_STATE };\n to = cursor;\n }\n\n // Defensive: a collab edit could have flipped the surrounding\n // block into a code block / other invalidNodes type, in which\n // case the slash session should not survive.\n const $cursor = newState.doc.resolve(cursor);\n if ($cursor.parent.type.spec.code) return { ...INITIAL_STATE };\n if (invalidNodes.includes($cursor.parent.type.name)) {\n return { ...INITIAL_STATE };\n }\n\n const query = newState.doc.textBetween(\n from + 1,\n to,\n undefined,\n PM_LEAF_PLACEHOLDER,\n );\n if (/[\\n\\t]/.test(query)) return { ...INITIAL_STATE };\n\n return { active: true, query, range: { from, to } };\n }\n\n // ── Branch 2: popup was INACTIVE ───────────────────────────────\n // Activation is gated to a real typing event of the trigger char.\n // Selection-only changes (mouse click into existing `/text`,\n // arrow-key navigation) and bulk doc changes (paste, programmatic\n // `insertContent` of >1 char) MUST NOT open the popup, even if\n // the cursor lands right after a `/` already in the document.\n // This keeps the slash menu tied to a typing session - matching\n // Notion: once the session is dismissed, the same `/` becomes\n // plain text and clicking back next to it doesn't reopen anything.\n if (!tr.docChanged) return prev;\n if (!justTypedTrigger(tr, char)) return prev;\n\n const result = findSlashQuery(newState, char, invalidNodes);\n if (result) return { active: true, query: result.query, range: result.range };\n return prev;\n },\n },\n\n view(editorView) {\n // Cooperative dismissal: other overlays broadcast `dm:dismiss-overlays`\n // when they open; listen and close the slash popup so two floating\n // menus never appear at once. We suppress the handler while WE are\n // the one dispatching - otherwise the slash popup would dismiss\n // itself the moment it opens (the dispatch is synchronous and reaches\n // our own listener before `update` reaches `renderer.onStart`).\n const editorEl = editorView.dom.closest<HTMLElement>('.dm-editor');\n let suppressDismissHandler = false;\n const dismissHandler = (): void => {\n if (suppressDismissHandler) return;\n const state = pluginKey.getState(editor.view.state);\n if (state?.active) dismissSlashCommand(editor.view);\n };\n editorEl?.addEventListener('dm:dismiss-overlays', dismissHandler);\n\n // Track whether we've already fired the open-time dismiss so we only\n // do it on transition false→true.\n let wasActive = false;\n\n return {\n update(view: EditorView) {\n const state = pluginKey.getState(view.state);\n if (!state) return;\n\n // On activation (first true after being false), broadcast dismiss\n // to close any other overlays that might be open. The local\n // suppression flag prevents our own dismissHandler from firing\n // back at us (the dispatch is synchronous and would otherwise\n // self-dismiss the popup the instant it opens).\n //\n // We MUST flip `wasActive = true` BEFORE dispatching, not after.\n // The dispatch synchronously triggers other listeners (e.g.\n // BlockHandle's `onDismissOverlays` which itself dispatches a\n // ProseMirror transaction to clear `hoveredPos`); that re-enters\n // this same `update` callback. Without flipping `wasActive` first\n // the re-entry would think the popup is still opening and dispatch\n // a *second* `dm:dismiss-overlays` whose nested `finally` would\n // reset `suppressDismissHandler` to false - letting our own\n // dismiss listener fire on the way out and tear down the popup\n // we just created. (`clientRect()` then returns null because the\n // plugin state was just cleared, so the second `onStart` paints\n // an unpositioned popup at the bottom of `.dm-editor`.)\n const becameActive = state.active && !wasActive;\n wasActive = state.active;\n if (becameActive) {\n suppressDismissHandler = true;\n try {\n editorEl?.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n } finally {\n suppressDismissHandler = false;\n }\n }\n\n if (state.active && state.range) {\n const items = FloatingMenuController.resolveItems(editor, itemsOverride);\n const contextual = filterByCursorAncestors(items, editor);\n const filtered = filterSlashItems(contextual, state.query);\n\n const command = (item: FloatingMenuItem): void => {\n const current = pluginKey.getState(view.state);\n if (!current?.range) return;\n\n // Delete the `/query` range first so item's command runs on\n // the now-clean cursor position. Close popup state in the\n // same transaction to avoid a stale-render flash.\n const tr = view.state.tr;\n tr.delete(current.range.from, current.range.to);\n tr.setMeta(pluginKey, 'dismiss');\n view.dispatch(tr);\n\n // Execute the item on a fresh transaction (its command will\n // read the latest state). Items that open a popover (Image\n // URL, Link, etc.) need the popover to claim focus - don't\n // force focus back to the editor here. Simple insert items\n // already leave focus in the editor, so no focus() call is\n // needed in either case.\n FloatingMenuController.executeItem(editor, item);\n };\n\n const clientRect = (): DOMRect | null => {\n const current = pluginKey.getState(view.state);\n if (!current?.range) return null;\n try {\n const coords = view.coordsAtPos(current.range.from);\n return new DOMRect(\n coords.left,\n coords.top,\n 0,\n coords.bottom - coords.top,\n );\n } catch {\n return null;\n }\n };\n\n const props: SlashCommandProps = {\n editor,\n query: state.query,\n range: state.range,\n items: filtered,\n command,\n clientRect,\n element: view.dom,\n };\n\n if (!renderer) {\n renderer = render();\n renderer.onStart(props);\n } else {\n renderer.onUpdate(props);\n }\n } else if (renderer) {\n renderer.onExit();\n renderer = null;\n }\n },\n\n destroy() {\n editorEl?.removeEventListener('dm:dismiss-overlays', dismissHandler);\n if (renderer) {\n try {\n renderer.onExit();\n } finally {\n renderer = null;\n }\n }\n },\n };\n },\n\n props: {\n // Use handleDOMEvents.keydown (not handleKeyDown) so we intercept\n // keys BEFORE other keymap plugins claim them (same trick as Mention).\n handleDOMEvents: {\n keydown(view, event): boolean {\n const state = pluginKey.getState(view.state);\n if (!state?.active) return false;\n\n if (event.key === 'Escape') {\n event.preventDefault();\n const tr = view.state.tr;\n tr.setMeta(pluginKey, 'dismiss');\n view.dispatch(tr);\n return true;\n }\n\n if (renderer) {\n const handled = renderer.onKeyDown(event);\n if (handled) event.preventDefault();\n return handled;\n }\n return false;\n },\n },\n\n decorations(state): DecorationSet {\n const pluginState = pluginKey.getState(state);\n if (!pluginState?.active || !pluginState.range) return DecorationSet.empty;\n return DecorationSet.create(state.doc, [\n Decoration.inline(pluginState.range.from, pluginState.range.to, {\n class: 'dm-slash-command-query',\n nodeName: 'span',\n }),\n ]);\n },\n },\n });\n}\n\nexport const SlashCommand = Extension.create<SlashCommandOptions>({\n name: 'slashCommand',\n\n addOptions() {\n return {\n char: '/',\n invalidNodes: ['codeBlock'],\n };\n },\n\n addProseMirrorPlugins() {\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n return [\n createSlashCommandPlugin({\n pluginKey: slashCommandPluginKey,\n editor,\n char: this.options.char ?? '/',\n ...(this.options.items !== undefined && { items: this.options.items }),\n render: this.options.render ?? createSlashSuggestionRenderer,\n invalidNodes: this.options.invalidNodes ?? ['codeBlock'],\n }),\n ];\n },\n});\n\n/**\n * Programmatically dismisses the slash suggestion.\n */\nexport function dismissSlashCommand(view: EditorView): void {\n view.dispatch(view.state.tr.setMeta(slashCommandPluginKey, 'dismiss'));\n}\n","/**\n * Pasting block-level content at an INLINE position normally goes through PM's\n * content fitter, which strips the block wrapper and pastes only inline text.\n * SmartPaste catches the relevant cases and routes each to the right strategy:\n *\n * 1. List slice into a list ancestor: items adapted (`convertListItemForParent`)\n * and merged as siblings, preserving the surrounding list.\n * 2. Trailing hardBreak (Shift+Enter scenario): trim the hardBreak and insert\n * the slice as a sibling after the parent.\n * 3. Truly empty parent paragraph (`parentSize === 0`): replace the parent.\n * 4-6. Caret at start / end / middle: insert as sibling or split-and-insert.\n * 7. Range selection: delete first, then run through 2-6.\n *\n * Skipped (PM default applies) when:\n * - Cursor isn't inside a textblock.\n * - Slice's top-level blocks are ALL plain paragraphs.\n * - Slice is a SINGLE top-level block of the SAME TYPE as the destination\n * (heading-into-heading, etc.) - PM's inline merge is the intended behavior.\n *\n * Note: do NOT bail on `openStart > 0` - PM's clipboard parser routinely sets\n * `openStart=1` even for closed-looking input like `<h1>x</h1>`. Top-level\n * children of the slice are what matter.\n */\n\nimport { Extension } from '@domternal/core';\nimport { Plugin, TextSelection, Selection } from '@domternal/pm/state';\nimport type { Slice, Node as PMNode, Fragment } from '@domternal/pm/model';\nimport type { EditorView } from '@domternal/pm/view';\nimport type { Transaction } from '@domternal/pm/state';\nimport { convertListItemForParent } from './helpers/convertListItemForParent.js';\n\nconst LIST_TYPES = new Set(['bulletList', 'orderedList', 'taskList']);\nconst LIST_ITEM_TYPES = new Set(['listItem', 'taskItem']);\n\nexport interface SmartPasteOptions {\n /**\n * Disable the plugin without removing the extension. Useful for tests\n * or to fall back to PM's default paste handling temporarily.\n * @default true\n */\n enabled?: boolean;\n}\n\nexport const SmartPaste = Extension.create<SmartPasteOptions>({\n name: 'smartPaste',\n\n addOptions() {\n return {\n enabled: true,\n };\n },\n\n addProseMirrorPlugins() {\n if (this.options.enabled === false) return [];\n return [\n new Plugin({\n props: {\n handlePaste: (view, _event, slice) => handleSmartPaste(view, slice),\n },\n }),\n ];\n },\n});\n\n/**\n * Returns `true` when this plugin handled the paste (PM should skip its\n * default), `false` otherwise.\n */\nfunction handleSmartPaste(view: EditorView, slice: Slice): boolean {\n const { state } = view;\n const { selection } = state;\n const $from = selection.$from;\n\n // Cursor must be at an inline position (inside a textblock). Otherwise\n // PM's default block-paste already does the right thing.\n if (!$from.parent.isTextblock) return false;\n\n // Bail when slice has no non-paragraph block at its top level - PM's\n // default merges plain inline content cleanly.\n if (!sliceHasNonParagraphBlock(slice)) return false;\n\n // Bail when the slice is a single block of the SAME TYPE as the\n // destination textblock (e.g. <h1> pasted inside an <h1>). Splitting\n // the parent block to \"preserve\" the same wrapper would visibly\n // shred the user's heading into three pieces - the inline merge that\n // PM's default does here is what the user actually wants.\n if (sliceIsSingleSameTypeAsParent(slice, $from.parent.type.name)) return false;\n\n // Strategy 1: list-slice into list ancestor - merge as siblings.\n if (tryPasteListSliceIntoList(view, slice)) return true;\n\n // Strategies 2-7: collapse range, then route by parent state + offset.\n const tr = state.tr;\n if (!selection.empty) tr.deleteSelection();\n\n const $pos = tr.selection.$from;\n const parent = $pos.parent;\n const parentStart = $pos.before($pos.depth);\n const parentEnd = $pos.after($pos.depth);\n const offset = $pos.parentOffset;\n const parentSize = parent.content.size;\n\n if (hasTrailingHardBreakAtCursor(parent, offset, parentSize)) {\n // Shift+Enter case: trim the trailing hardBreak and insert the\n // slice AS A SIBLING after the parent textblock. Preserves any\n // text that came before the break (e.g. \"Existing<br>|\" stays as\n // a paragraph \"Existing\", the heading lands as the next sibling).\n // Empty-shift+enter case: \"<p><br></p>\" becomes \"<p></p>\" + slice,\n // i.e. one empty row + the heading below it.\n const hbStart = parentEnd - 2; // hardBreak occupies 1 position before parent close\n const hbEnd = parentEnd - 1;\n tr.delete(hbStart, hbEnd);\n const adjustedParentEnd = parentEnd - 1;\n tr.insert(adjustedParentEnd, slice.content);\n setCaretAtEndOfInserted(tr, adjustedParentEnd, slice.content);\n } else if (parentSize === 0) {\n // Truly-empty parent (no Shift+Enter break either). Default: replace\n // the parent with the slice content so we don't leave a stray empty\n // p before/after the inserted block.\n //\n // Notion-strict carve-out: when the empty paragraph is the LABEL\n // slot of a listItem/taskItem (the schema-required first child of\n // `paragraph block*`), replacing it would either be schema-invalid\n // or trigger PM's content fitter to inject a fresh empty paragraph.\n // Insert the slice AFTER the label instead so the new content\n // attaches as a nested child below the (still empty) label.\n const isListItemLabel = $pos.depth >= 2\n && LIST_ITEM_TYPES.has($pos.node($pos.depth - 1).type.name)\n && $pos.index($pos.depth - 1) === 0;\n if (isListItemLabel) {\n tr.insert(parentEnd, slice.content);\n setCaretAtEndOfInserted(tr, parentEnd, slice.content);\n } else {\n tr.replaceWith(parentStart, parentEnd, slice.content);\n setCaretAtEndOfInserted(tr, parentStart, slice.content);\n }\n } else if (offset === 0) {\n tr.insert(parentStart, slice.content);\n setCaretAtEndOfInserted(tr, parentStart, slice.content);\n } else if (offset === parentSize) {\n tr.insert(parentEnd, slice.content);\n setCaretAtEndOfInserted(tr, parentEnd, slice.content);\n } else {\n // Caret in the middle. Split the textblock at the cursor, then\n // insert the slice content at the BOUNDARY between the two new\n // halves. After split, the cursor's original pos sits at the END\n // of the first half (just before its close marker); the boundary\n // we want is one past that - `cursorPos + 1` (between the close\n // of the first half and the open of the second).\n const cursorPos = $pos.pos;\n tr.split(cursorPos);\n const insertAt = cursorPos + 1;\n tr.insert(insertAt, slice.content);\n setCaretAtEndOfInserted(tr, insertAt, slice.content);\n }\n\n view.dispatch(tr.scrollIntoView());\n return true;\n}\n\n/** True if any top-level slice child is a block other than `paragraph`. */\nfunction sliceHasNonParagraphBlock(slice: Slice): boolean {\n let result = false;\n slice.content.forEach((child) => {\n if (child.isBlock && child.type.name !== 'paragraph') result = true;\n });\n return result;\n}\n\n/**\n * True when the slice contains exactly one top-level block whose type\n * name matches the destination textblock's parent. This is the\n * heading-pasted-inside-heading (and analogous) case where SmartPaste\n * would otherwise split the parent into pieces around the inserted\n * block. PM's default does the right thing here: it strips the\n * matching wrapper and inline-merges the slice content into the\n * existing parent.\n */\nfunction sliceIsSingleSameTypeAsParent(slice: Slice, parentTypeName: string): boolean {\n if (slice.content.childCount !== 1) return false;\n return slice.content.firstChild?.type.name === parentTypeName;\n}\n\n/**\n * Cursor sits at the very end of the parent textblock AND the parent's\n * last child is a `hardBreak`. The Shift+Enter row trigger.\n */\nfunction hasTrailingHardBreakAtCursor(parent: PMNode, offset: number, parentSize: number): boolean {\n if (offset !== parentSize) return false;\n return parent.lastChild?.type.name === 'hardBreak';\n}\n\n/**\n * Slice top-level is a single list (bulletList / orderedList / taskList)\n * AND the caret has a list ancestor. Adapts the slice's items to the\n * ancestor list's expected item type (via `convertListItemForParent`)\n * and merges them as siblings of the current `listItem` / `taskItem`.\n * Returns false (caller falls through) when this case doesn't apply.\n */\nfunction tryPasteListSliceIntoList(view: EditorView, slice: Slice): boolean {\n const { state } = view;\n const { selection, schema } = state;\n\n // Slice must be exactly one top-level list node.\n if (slice.content.childCount !== 1) return false;\n const sliceTop = slice.content.firstChild;\n if (!sliceTop || !LIST_TYPES.has(sliceTop.type.name)) return false;\n\n // Find nearest list-wrapper ancestor of the caret.\n const $from = selection.$from;\n let listDepth = -1;\n for (let d = $from.depth; d > 0; d--) {\n if (LIST_TYPES.has($from.node(d).type.name)) { listDepth = d; break; }\n }\n if (listDepth === -1) return false;\n\n // The corresponding listItem (one level inside the list).\n const listItemDepth = listDepth + 1;\n if ($from.depth < listItemDepth) return false;\n\n const listParent = $from.node(listDepth);\n const adapted = convertListItemForParent(schema, sliceTop.content, listParent.type);\n if (adapted.childCount === 0) return false;\n\n const tr = state.tr;\n if (!selection.empty) tr.deleteSelection();\n\n // Re-resolve after potential range delete. Bail if we lost the list\n // ancestor (selection straddled out - let the fallback paths run).\n const $pos = tr.selection.$from;\n if ($pos.depth < listItemDepth) return false;\n if (!LIST_TYPES.has($pos.node(listDepth).type.name)) return false;\n\n const parent = $pos.parent;\n const parentEnd = $pos.after($pos.depth);\n const offset = $pos.parentOffset;\n const parentSize = parent.content.size;\n const liStart = $pos.before(listItemDepth);\n const liEnd = $pos.after(listItemDepth);\n const itemHasOnlyOneChild = $pos.node(listItemDepth).childCount === 1;\n\n let insertAt: number;\n if (hasTrailingHardBreakAtCursor(parent, offset, parentSize)) {\n // Shift+Enter inside a listItem with a list-slice paste. Trim the\n // trailing hardBreak and insert the (adapted) items as siblings\n // AFTER the current listItem. Empty-row stays where the break was;\n // pasted items appear in subsequent rows.\n const hbStart = parentEnd - 2;\n const hbEnd = parentEnd - 1;\n tr.delete(hbStart, hbEnd);\n const adjustedLiEnd = liEnd - 1;\n tr.insert(adjustedLiEnd, adapted);\n insertAt = adjustedLiEnd;\n } else if (parentSize === 0 && itemHasOnlyOneChild) {\n // Truly-empty listItem: replace it with the slice's items so we\n // don't leave a leading / trailing empty item next to the merge.\n tr.replaceWith(liStart, liEnd, adapted);\n insertAt = liStart;\n } else if (offset === 0) {\n tr.insert(liStart, adapted);\n insertAt = liStart;\n } else if (offset === parentSize) {\n tr.insert(liEnd, adapted);\n insertAt = liEnd;\n } else {\n // Caret in middle of the textblock inside the listItem. Split the\n // listItem at the cursor, then insert items between the two halves.\n // `tr.split(pos, depth)` doubles close+open at each level. For\n // depth=2 (textblock + listItem) the boundary \"between the two new\n // listItems\" is at pos + 2 (after both close tokens).\n const cursorPos = $pos.pos;\n tr.split(cursorPos, 2);\n insertAt = cursorPos + 2;\n tr.insert(insertAt, adapted);\n }\n\n setCaretAtEndOfInserted(tr, insertAt, adapted);\n view.dispatch(tr.scrollIntoView());\n return true;\n}\n\n/**\n * Place the cursor at the END of the LAST inserted block. For text-bearing\n * blocks (paragraph, heading, list-item-with-p), this lands at the end of\n * the deepest textblock. For atom blocks (hr, image), Selection.near picks\n * the closest valid selection.\n *\n * Position math: the fragment occupies `[insertAt, insertAt + content.size)`\n * in the new doc. `insertAt + content.size - 1` is the position right\n * before the outermost close-token of the last inserted top-level child -\n * i.e., the END of its content.\n */\nfunction setCaretAtEndOfInserted(tr: Transaction, insertAt: number, content: Fragment): void {\n if (content.childCount === 0) return;\n const target = Math.max(0, Math.min(tr.doc.content.size, insertAt + content.size - 1));\n const $target = tr.doc.resolve(target);\n if ($target.parent.isTextblock) {\n tr.setSelection(TextSelection.create(tr.doc, target));\n } else {\n tr.setSelection(Selection.near($target, -1));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/FloatingMenu.ts","../src/helpers/findTopLevelBlock.ts","../src/helpers/expandToEmptyWrappers.ts","../src/helpers/convertListItemForParent.ts","../src/helpers/moveBlock.ts","../src/helpers/moveBlockAsNestedChild.ts","../src/helpers/dragGhost.ts","../src/helpers/clampCoords.ts","../src/helpers/gutterBias.ts","../src/helpers/defaultMatchers.ts","../src/helpers/resolveDragTarget.ts","../src/BlockHandle.ts","../src/KeyboardReorder.ts","../src/helpers/blockOperations.ts","../src/helpers/turnIntoWrapper.ts","../src/BlockContextMenu.ts","../src/createSlashSuggestionRenderer.ts","../src/SlashCommand.ts","../src/SmartPaste.ts"],"names":["node","content","Fragment","LIST_ITEM_TYPES","PluginKey","midY","Plugin","Extension","TextSelection","defaultIcons","positionFloatingOnce","DecorationSet","Decoration"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Block-insert menu shown when the cursor sits at the start of an empty\n * paragraph. Items collected via `addFloatingMenuItems()`. This file owns\n * visibility, positioning, dismiss, and keyboard entry; framework wrappers\n * render the UI.\n */\nimport { Extension, positionFloatingOnce } from '@domternal/core';\nimport type { Editor, FloatingMenuItemsOverride } from '@domternal/core';\nimport { Plugin, PluginKey } from '@domternal/pm/state';\nimport type { EditorView } from '@domternal/pm/view';\nimport type { EditorState } from '@domternal/pm/state';\n\nexport const floatingMenuPluginKey = new PluginKey('floatingMenu');\n\n/**\n * Default visibility predicate. Shows the menu when the cursor is at the\n * very start of an empty `paragraph` in an editable editor.\n */\nfunction defaultShouldShow({\n editor,\n state,\n}: {\n editor: Editor;\n view: EditorView;\n state: EditorState;\n}): boolean {\n if (!editor.isEditable) return false;\n const { selection } = state;\n const { $from, empty } = selection;\n if (!empty) return false;\n if ($from.parent.type.name !== 'paragraph') return false;\n if ($from.parent.content.size !== 0) return false;\n if ($from.parentOffset !== 0) return false;\n return true;\n}\n\n/**\n * Keyboard shortcuts that move focus from the editor into the menu.\n * Defaults combine the WAI-ARIA recommendation (`Alt-F10`) with a\n * modern slash-command-friendly shortcut (`Mod-/`). Set to an empty\n * array to disable keyboard entry entirely.\n */\nexport interface FloatingMenuKeymap {\n /** Shortcuts that focus the first menu item when the menu is visible. */\n enterMenu?: string[];\n}\n\nconst DEFAULT_ENTER_MENU_SHORTCUTS: string[] = ['Alt-F10', 'Mod-/'];\n\nexport interface FloatingMenuOptions {\n /**\n * The HTML element that contains the menu. Required when used directly;\n * framework wrappers create this element and pass it in.\n */\n element: HTMLElement | null;\n\n /**\n * Visibility predicate. Defaults to `defaultShouldShow` (empty paragraph\n * at cursor start).\n */\n shouldShow: (props: {\n editor: Editor;\n view: EditorView;\n state: EditorState;\n }) => boolean;\n\n /**\n * Pixel offset from the anchor. @default 0\n */\n offset: number;\n\n /**\n * Items override. Array replaces defaults entirely; function receives\n * the collected defaults and returns a new list (filter/reorder/extend).\n * Consumed by the controller; the plugin itself only reads it when the\n * wrapper does not construct its own controller.\n */\n items?: FloatingMenuItemsOverride;\n\n /** Keyboard shortcuts for entering the menu via keyboard. */\n keymap?: FloatingMenuKeymap;\n\n /**\n * When `true`, the menu only appears when EXPLICITLY triggered via\n * `showFloatingMenu(view)` (typically from BlockHandle's `+` button).\n * Pressing `Enter` to create a new empty paragraph no longer auto-shows\n * the menu. Mirrors Notion's behaviour: empty rows display a placeholder\n * hint, the slash command (`/`) is the keyboard trigger, and the menu\n * opens via the gutter `+` button only.\n *\n * @default false (auto-shows on every empty paragraph - backward compat)\n */\n requireExplicitTrigger?: boolean;\n}\n\nexport interface CreateFloatingMenuPluginOptions {\n pluginKey: PluginKey;\n editor: Editor;\n element: HTMLElement;\n shouldShow?: FloatingMenuOptions['shouldShow'];\n offset?: number;\n keymap?: FloatingMenuKeymap | undefined;\n requireExplicitTrigger?: boolean;\n}\n\n/** Internal plugin state - tracks whether `+` button explicitly triggered the menu. */\ninterface FloatingMenuPluginState {\n triggered: boolean;\n}\n\n/**\n * String meta key used by `showFloatingMenu` / `hideFloatingMenu`. We\n * use a STRING (not a PluginKey) so callers don't need a reference to\n * the specific plugin instance - framework wrappers (angular, react,\n * vue) create their own per-instance PluginKey via random suffix to\n * disambiguate menus across editors, but they all read this shared\n * string meta. The plugin's `state.apply` listens for it.\n */\nexport const FLOATING_MENU_META = 'dm:floatingMenuTrigger';\n\n/**\n * Programmatically show the FloatingMenu - used by BlockHandle's `+`\n * button after it inserts a fresh empty paragraph. When the plugin is\n * configured with `requireExplicitTrigger: true`, this is the ONLY way\n * the menu opens (besides the existing `Mod-/` keyboard shortcut, which\n * is unaffected and continues to focus an already-visible menu).\n */\nexport function showFloatingMenu(view: EditorView): void {\n view.dispatch(view.state.tr.setMeta(FLOATING_MENU_META, 'show'));\n}\n\n/** Programmatically hide the FloatingMenu (clears the explicit-trigger flag). */\nexport function hideFloatingMenu(view: EditorView): void {\n view.dispatch(view.state.tr.setMeta(FLOATING_MENU_META, 'hide'));\n}\n\n// Cache platform check at module load rather than per-keystroke.\nconst IS_MAC = typeof navigator !== 'undefined'\n && /Mac|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n/**\n * Parses a shortcut string (e.g. `Alt-F10`, `Mod-/`, `Shift-Ctrl-Enter`)\n * against a KeyboardEvent. Matches prosemirror-keymap's grammar:\n *\n * - Modifiers can appear in any order and separated by `-`.\n * - `Mod` maps to Cmd on macOS, Ctrl elsewhere.\n * - Aliases: `Cmd` / `m` / `Meta`, `Ctrl` / `c` / `Control`, `Alt` / `a`,\n * `Shift` / `s`.\n * - Named keys use `KeyEvent.key` values directly (e.g. `F10`, `Enter`,\n * `ArrowUp`). Letters are case-insensitive; `Shift-` prefix is implied\n * for shifted-character keys.\n *\n * @returns true if the event matches the shortcut exactly (all and only\n * the listed modifiers, same key).\n */\nfunction matchShortcut(event: KeyboardEvent, shortcut: string): boolean {\n const parts = shortcut.split('-');\n let keyPart = parts.pop();\n if (!keyPart) return false;\n // prosemirror-keymap convention: `Space` is an alias for ' ' since the\n // literal character is awkward to type in a shortcut string.\n if (keyPart === 'Space') keyPart = ' ';\n\n let needCtrl = false;\n let needMeta = false;\n let needAlt = false;\n let needShift = false;\n\n for (const mod of parts) {\n switch (mod) {\n case 'Mod':\n case 'mod':\n if (IS_MAC) needMeta = true;\n else needCtrl = true;\n break;\n case 'Cmd':\n case 'cmd':\n case 'Meta':\n case 'meta':\n case 'm':\n needMeta = true;\n break;\n case 'Ctrl':\n case 'ctrl':\n case 'Control':\n case 'control':\n case 'c':\n needCtrl = true;\n break;\n case 'Alt':\n case 'alt':\n case 'a':\n needAlt = true;\n break;\n case 'Shift':\n case 'shift':\n case 's':\n needShift = true;\n break;\n default:\n return false;\n }\n }\n\n if (event.altKey !== needAlt) return false;\n if (event.ctrlKey !== needCtrl) return false;\n if (event.metaKey !== needMeta) return false;\n // For single-character keys, ignore Shift (since Shift is part of the\n // character itself, e.g. Shift+/ produces `?`). For named keys (F10,\n // ArrowUp, Enter, etc.), require Shift match exactly.\n if (keyPart.length > 1 && event.shiftKey !== needShift) return false;\n\n return event.key === keyPart || event.key.toLowerCase() === keyPart.toLowerCase();\n}\n\n/**\n * Creates a standalone FloatingMenu ProseMirror plugin. Framework wrappers\n * call this directly so they can own element creation and rendering.\n */\nexport function createFloatingMenuPlugin(options: CreateFloatingMenuPluginOptions): Plugin {\n const {\n pluginKey,\n editor,\n element,\n shouldShow = defaultShouldShow,\n offset = 0,\n keymap,\n requireExplicitTrigger = false,\n } = options;\n\n const enterShortcuts = keymap?.enterMenu ?? DEFAULT_ENTER_MENU_SHORTCUTS;\n\n // Semantic defaults: `menu` is the right WAI-ARIA role for a transient\n // list of single-action choices (unlike `toolbar` which implies a\n // persistent set of controls).\n if (!element.getAttribute('role')) {\n element.setAttribute('role', 'menu');\n element.setAttribute('aria-label', 'Insert block');\n }\n\n let cleanupFloating: (() => void) | null = null;\n let editorEl: Element | null = null;\n let clickOutsideHandler: ((e: Event) => void) | null = null;\n let dismissOverlayHandler: (() => void) | null = null;\n\n const isVisible = (): boolean => element.hasAttribute('data-show');\n\n const updatePosition = (view: EditorView): void => {\n const { selection } = view.state;\n const { $from } = selection;\n const depth = $from.depth;\n const startPos = $from.start(depth);\n const domNode = view.nodeDOM(startPos - 1);\n if (domNode instanceof HTMLElement) {\n cleanupFloating?.();\n cleanupFloating = positionFloatingOnce(domNode, element, {\n placement: 'bottom-start',\n offsetValue: offset,\n });\n element.setAttribute('data-show', '');\n }\n };\n\n const hideMenu = (): void => {\n cleanupFloating?.();\n cleanupFloating = null;\n element.removeAttribute('data-show');\n };\n\n // Clear the explicit-trigger flag if it's set. No-op when\n // `requireExplicitTrigger` is off (no flag exists to clear).\n const clearTriggeredFlag = (view: EditorView): void => {\n if (!requireExplicitTrigger) return;\n const triggered = (pluginKey.getState(view.state) as FloatingMenuPluginState | undefined)?.triggered ?? false;\n if (triggered) view.dispatch(view.state.tr.setMeta(FLOATING_MENU_META, 'hide'));\n };\n\n // Focus first menuitem. Wrappers mark each item with\n // `data-floating-menu-item`; falls back to any focusable descendant.\n const focusFirstItem = (): boolean => {\n const first =\n element.querySelector<HTMLElement>('[data-floating-menu-item]:not([aria-disabled=\"true\"])')\n ?? element.querySelector<HTMLElement>('button, [tabindex]:not([tabindex=\"-1\"])');\n if (!first) return false;\n first.focus();\n return true;\n };\n\n // Hide initially (wrappers may render the element before the plugin runs).\n hideMenu();\n\n // Compute final visibility: when `requireExplicitTrigger` is on, both\n // the explicit-trigger flag AND the user-supplied shouldShow predicate\n // must be true. Otherwise (default), only shouldShow gates visibility.\n const isVisibleNow = (view: EditorView): boolean => {\n const wantsShow = shouldShow({ editor, view, state: view.state });\n if (!requireExplicitTrigger) return wantsShow;\n const triggered = (pluginKey.getState(view.state) as FloatingMenuPluginState | undefined)?.triggered ?? false;\n return triggered && wantsShow;\n };\n\n return new Plugin<FloatingMenuPluginState>({\n key: pluginKey,\n\n state: {\n init: (): FloatingMenuPluginState => ({ triggered: false }),\n apply: (tr, prev): FloatingMenuPluginState => {\n const meta = tr.getMeta(FLOATING_MENU_META) as unknown;\n if (meta === 'show') return { triggered: true };\n if (meta === 'hide') return { triggered: false };\n return prev;\n },\n },\n\n props: {\n // Keyboard entry from the editor. ProseMirror's handleKeyDown fires\n // before browser defaults, so we can intercept without risking\n // interference with typing. We only act while the menu is visible.\n handleKeyDown(_view, event): boolean {\n if (!isVisible()) return false;\n for (const shortcut of enterShortcuts) {\n if (matchShortcut(event, shortcut)) {\n if (focusFirstItem()) {\n event.preventDefault();\n return true;\n }\n return false;\n }\n }\n return false;\n },\n },\n\n view: (editorView) => {\n // Move the menu into `.dm-editor` so `position:absolute` resolves\n // against the scrollable editor container - zero jitter on scroll.\n editorEl = editorView.dom.closest('.dm-editor');\n if (editorEl && element.parentElement !== editorEl) {\n editorEl.appendChild(element);\n }\n\n // Hide the menu AND clear the explicit-trigger flag so a stale\n // `triggered=true` doesn't survive across an unrelated dismissal.\n const dismiss = (): void => {\n hideMenu();\n clearTriggeredFlag(editor.view);\n };\n\n const onFocus = (): void => {\n if (isVisibleNow(editor.view)) updatePosition(editor.view);\n else dismiss();\n };\n\n const onBlur = ({ event }: { event: FocusEvent }): void => {\n // Keep the menu visible if focus moved into it - users can\n // interact with menu items without the menu vanishing.\n // `relatedTarget` is `EventTarget | null`, not `Node` - guard with\n // an `instanceof Node` check so `.contains()` receives a valid arg\n // even for exotic focus targets (e.g. AbortSignal-based targets\n // never raise a focus event in practice, but the cast is unsound).\n const related = event.relatedTarget;\n if (related instanceof Node && element.contains(related)) return;\n dismiss();\n };\n\n // Click-outside dismissal. Capture phase ensures we fire before\n // other UI (dropdowns, popovers) handles the same click.\n clickOutsideHandler = (e: Event): void => {\n if (!isVisible()) return;\n const target = e.target;\n if (!(target instanceof Node)) return;\n if (element.contains(target)) return;\n if (editor.view.dom.contains(target)) return;\n dismiss();\n };\n document.addEventListener('mousedown', clickOutsideHandler, true);\n\n // Cooperative dismissal: other overlays (toolbar dropdowns,\n // popovers) broadcast this event to close any open chrome.\n if (editorEl) {\n dismissOverlayHandler = (): void => { dismiss(); };\n editorEl.addEventListener('dm:dismiss-overlays', dismissOverlayHandler);\n }\n\n editor.on('focus', onFocus);\n editor.on('blur', onBlur);\n\n return {\n update: (view) => {\n if (isVisibleNow(view)) updatePosition(view);\n else {\n hideMenu();\n // Auto-clear stale `triggered` state when the user navigates\n // away from the empty paragraph (e.g. types a character or\n // moves the cursor) - otherwise the next empty paragraph\n // they enter would silently re-show the menu.\n clearTriggeredFlag(view);\n }\n },\n\n destroy: () => {\n hideMenu();\n editor.off('focus', onFocus);\n editor.off('blur', onBlur);\n if (clickOutsideHandler) {\n document.removeEventListener('mousedown', clickOutsideHandler, true);\n clickOutsideHandler = null;\n }\n if (dismissOverlayHandler && editorEl) {\n editorEl.removeEventListener('dm:dismiss-overlays', dismissOverlayHandler);\n dismissOverlayHandler = null;\n }\n editorEl = null;\n },\n };\n },\n });\n}\n\nexport const FloatingMenu = Extension.create<FloatingMenuOptions>({\n name: 'floatingMenu',\n\n addOptions() {\n return {\n element: null,\n shouldShow: defaultShouldShow,\n offset: 0,\n requireExplicitTrigger: false,\n };\n },\n\n addProseMirrorPlugins() {\n const { element, shouldShow, offset, keymap, requireExplicitTrigger } = this.options;\n if (!element) return [];\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n\n return [\n createFloatingMenuPlugin({\n pluginKey: floatingMenuPluginKey,\n editor,\n element,\n shouldShow,\n offset,\n keymap,\n ...(requireExplicitTrigger !== undefined && { requireExplicitTrigger }),\n }),\n ];\n },\n});\n","import type { Node } from '@domternal/pm/model';\nimport type { EditorView } from '@domternal/pm/view';\n\nimport type { BlockCandidate, BlockMatcher } from './blockMatcher.js';\n\n/**\n * Information about a top-level block in the document.\n */\nexport interface TopLevelBlock {\n /** The block node. */\n node: Node;\n /** Absolute position of the block (its start). */\n pos: number;\n /** Absolute position one past the block end (= pos + node.nodeSize). */\n end: number;\n /** Zero-based index among doc children. */\n index: number;\n}\n\n/**\n * Resolves the top-level block (direct child of the document) that contains\n * a given absolute position. Returns `null` when `pos` resolves to the\n * document itself (depth 0) or is out of bounds.\n */\nexport function findTopLevelBlock(doc: Node, pos: number): TopLevelBlock | null {\n if (pos < 0 || pos > doc.content.size) return null;\n const $pos = doc.resolve(pos);\n\n // Position exactly at a top-level boundary (between blocks, or at doc\n // start). `doc.nodeAt(pos)` returns the node that starts at this position.\n if ($pos.depth === 0) {\n const node = doc.nodeAt(pos);\n if (!node) return null;\n return {\n node,\n pos,\n end: pos + node.nodeSize,\n index: $pos.index(0),\n };\n }\n\n const node = $pos.node(1);\n const blockPos = $pos.before(1);\n const index = $pos.index(0);\n return {\n node,\n pos: blockPos,\n end: blockPos + node.nodeSize,\n index,\n };\n}\n\n/**\n * Resolves the deepest ancestor whose node type name appears in\n * `draggableTypes`. Falls back to `findTopLevelBlock` (depth-1 walk) if no\n * ancestor in the list matches.\n *\n * Used by `BlockHandle` when the `nested` option is active: the plugin\n * hovers over list items / task items individually instead of always\n * anchoring on the whole list.\n *\n * Walking is deepest-first so nested lists resolve to the innermost\n * matching item (the one the cursor is actually inside).\n */\nexport function findDraggableBlock(\n doc: Node,\n pos: number,\n draggableTypes: string[],\n): TopLevelBlock | null {\n if (pos < 0 || pos > doc.content.size) return null;\n if (draggableTypes.length === 0) return findTopLevelBlock(doc, pos);\n const $pos = doc.resolve(pos);\n\n // Walk ancestors from deepest to shallowest (skip depth 0 = doc itself).\n for (let depth = $pos.depth; depth >= 1; depth--) {\n const node = $pos.node(depth);\n if (draggableTypes.includes(node.type.name)) {\n const blockPos = $pos.before(depth);\n // The \"index\" for a nested draggable is its index within its direct\n // parent - consistent with what the block's drag logic expects when\n // reordering siblings.\n const index = $pos.index(depth - 1);\n return {\n node,\n pos: blockPos,\n end: blockPos + node.nodeSize,\n index,\n };\n }\n }\n\n // No allowed-node ancestor found - fall back to the top-level block so\n // hover/drag still works for plain paragraphs outside any container.\n return findTopLevelBlock(doc, pos);\n}\n\n/**\n * Spatial result returned by {@link findDeepestBlockAtY}.\n */\nexport interface DeepestBlockMatch {\n node: Node;\n pos: number;\n dom: HTMLElement;\n rect: DOMRect;\n}\n\n/**\n * Finds the **deepest (innermost)** block at a given client Y coordinate\n * by walking the doc tree and comparing each node's DOM rect against\n * `clientY`. Among all blocks whose vertical rect contains `clientY`\n * AND whose type appears in `allowedTypes`, the one with the **smallest\n * height** wins (innermost in a vertical block layout).\n *\n * X is intentionally ignored - the gutter where the BlockHandle visually\n * lives sits to the left of `.ProseMirror`, so any X-based resolution\n * (`posAtCoords`, point-in-rect tests) would resolve to whatever happens\n * to be at the editor's left edge, which is the OUTER block when nested\n * lists are indented further right. This is the deepest-match behaviour:\n * the handle anchors on the row the cursor is actually in, regardless of\n * how far left the cursor strayed.\n *\n * The opposite policy - gutter bias (penalise depth near the left edge so\n * shallower ancestors win) - is exposed here as Mode C (`promoteOnEdge`)\n * and uses {@link ./resolveDragTarget resolveDragTarget} instead.\n *\n * `matchers` (default `[]`) shares the same `BlockMatcher[]` contract Mode C\n * applies; here only the `'reject'` verdict matters (a rejected candidate is\n * skipped, the walker continues). This keeps exclusion behaviour (e.g.\n * `firstChildOfListItem`) consistent between modes B and C: when a host\n * extends `allowedTypes` to include `paragraph`, the label paragraph of a\n * list item is automatically excluded so the handle still resolves to the\n * list item itself.\n *\n * Returns `null` when no allowed block contains `clientY` (e.g. cursor is\n * above the first block, below the last, or hovering a top-level node not\n * in `allowedTypes`). Callers should treat `null` as \"fall through to\n * top-level resolution\".\n */\nexport function findDeepestBlockAtY(\n view: EditorView,\n clientY: number,\n allowedTypes: string[],\n matchers: readonly BlockMatcher[] = [],\n): DeepestBlockMatch | null {\n if (allowedTypes.length === 0) return null;\n let best: DeepestBlockMatch | null = null;\n view.state.doc.descendants((node, pos, parent, index) => {\n const dom = view.nodeDOM(pos);\n if (!(dom instanceof HTMLElement)) return true;\n const rect = dom.getBoundingClientRect();\n // Skip the entire subtree when the cursor isn't vertically inside this\n // node - children of a non-containing parent can't contain the cursor\n // either, so pruning here is what keeps the walk O(depth) instead of\n // O(doc).\n if (clientY < rect.top || clientY > rect.bottom) return false;\n if (allowedTypes.includes(node.type.name)) {\n if (matchers.length > 0 && isRejectedByMatchers(view, node, pos, parent, index, matchers)) {\n return true;\n }\n if (best === null || rect.height < best.rect.height) {\n best = { node, pos, dom, rect };\n }\n }\n return true;\n });\n return best;\n}\n\nfunction isRejectedByMatchers(\n view: EditorView,\n node: Node,\n pos: number,\n parent: Node | null,\n index: number,\n matchers: readonly BlockMatcher[],\n): boolean {\n const $pos = view.state.doc.resolve(pos);\n const candidate: BlockCandidate = {\n block: node,\n documentPos: pos,\n // `pos` sits right BEFORE `node`, so $pos.depth is the parent's depth\n // and `node` itself lives one level deeper.\n treeDepth: $pos.depth + 1,\n container: parent,\n positionInContainer: index,\n isFirstChild: index === 0,\n isLastChild: parent !== null ? index === parent.childCount - 1 : true,\n resolvedPos: $pos,\n editorView: view,\n };\n for (const matcher of matchers) {\n if (matcher.test(candidate) === 'reject') return true;\n }\n return false;\n}\n","import type { Node } from '@domternal/pm/model';\n\n/**\n * Walks up from `[from, to]` widening the range as long as removing the\n * source from each ancestor would leave that ancestor effectively empty.\n * Stops at the first ancestor with meaningful sibling content (or at the\n * doc root).\n *\n * Shared by `moveBlock` and `deleteBlock`. Without it:\n *\n * - Move: dragging the only `<li>` out of a nested `<ul>` would force\n * PM's content fitter to retain an empty `<li>` placeholder to satisfy\n * `bulletList → listItem+`.\n * - Delete: deleting the only listItem inside a UL would either leave\n * that empty placeholder OR (worse, depending on schema fitter\n * behaviour) silently delete the whole list because PM tries to\n * replace the LI with the next-best fit and may unwrap the wrapper.\n *\n * Two collapse cases are handled:\n *\n * 1. **Single-child wrapper** (`block+` schema, classic case): the\n * parent contains only the source. Walking up removes the empty\n * wrapper outright.\n * 2. **Single-meaningful-child wrapper** (Notion-strict `paragraph\n * block*` schema for list items): the parent contains the source\n * plus one auto-injected empty filler paragraph (PM's content\n * fitter prepends an empty paragraph so the list item is schema\n * valid). Treating that filler as discardable keeps the wrapper\n * chain collapsing all the way up, preserving the same behaviour\n * we have under `block+`.\n */\nexport function expandToEmptyWrappers(\n doc: Node,\n from: number,\n to: number,\n): { from: number; to: number } {\n let curFrom = from;\n let curTo = to;\n let $pos = doc.resolve(curFrom);\n while ($pos.depth > 0 && isCollapsibleParent($pos.node($pos.depth), $pos.index($pos.depth))) {\n curFrom = $pos.before($pos.depth);\n curTo = $pos.after($pos.depth);\n $pos = doc.resolve(curFrom);\n }\n return { from: curFrom, to: curTo };\n}\n\n/**\n * Parent collapses if removing the source leaves no meaningful content.\n * `sourceIndex` is the position the source occupies among the parent's\n * children (so we can identify the OTHER children when checking for\n * filler paragraphs).\n */\nfunction isCollapsibleParent(parent: Node, sourceIndex: number): boolean {\n if (parent.childCount === 1) return true;\n if (parent.childCount !== 2) return false;\n const otherIndex = sourceIndex === 0 ? 1 : 0;\n const other = parent.child(otherIndex);\n return other.type.name === 'paragraph' && other.content.size === 0;\n}\n","import { Fragment } from '@domternal/pm/model';\nimport type { Node, NodeType, Schema } from '@domternal/pm/model';\n\nconst TASK_LIST_TYPE = 'taskList';\nconst BULLET_LIST_TYPES = new Set(['bulletList', 'orderedList']);\n\nconst TASK_ITEM_TYPE = 'taskItem';\nconst LIST_ITEM_TYPE = 'listItem';\n\n/**\n * Adapts the IMMEDIATE children of a slice so they satisfy the target\n * parent's content rule when dropping into a list-wrapper container\n * (`bulletList` / `orderedList` / `taskList`).\n *\n * Three behaviours:\n *\n * 1. **Item already matches the target list.** No-op (e.g. dragging a\n * `listItem` into another `bulletList` keeps it a `listItem`).\n *\n * 2. **Cross-list-type conversion.** Source is a list item of the OTHER\n * type (e.g. `taskItem` → bulletList parent). Wrapper type swaps\n * while preserving inner content. For listItem→taskItem we set\n * `checked: false`; for taskItem→listItem the `checked` attr is\n * dropped (PM ignores attrs not declared by the target schema).\n *\n * 3. **Arbitrary-block wrap.** Source is something else (heading,\n * paragraph, codeBlock, blockquote, hr, image, etc.). We wrap the\n * dragged block in a fresh `listItem` (or `taskItem`) so the drop\n * lands INSIDE the list, mirroring Notion's behaviour.\n *\n * Notion-strict listItem content (`paragraph block*`) requires the\n * first child to be a paragraph (the \"label\" line aligned with the\n * bullet/checkbox). For non-paragraph blocks we prepend an empty\n * label paragraph so the block attaches as a nested child below\n * it; for paragraphs we use them directly as the label.\n *\n * Without this wrap, PM's content fitter would silently promote\n * the dragged block to the next valid position (a sibling AFTER\n * the list), which contradicts the visual drop indicator and\n * surprises the user.\n *\n * Scope: only IMMEDIATE children of the slice are adapted. Nested\n * lists inside the dragged content keep their original type - drag a\n * bullet item that contains a nested task list, and the outer wrapper\n * adapts to the new parent while the nested task list is preserved.\n *\n * Returns the original Fragment unchanged when target parent isn't a\n * list wrapper, or when every child already matches the target item\n * type.\n */\nexport function convertListItemForParent(\n schema: Schema,\n content: Fragment,\n parentType: NodeType,\n): Fragment {\n const expectsTaskItem = parentType.name === TASK_LIST_TYPE;\n const expectsListItem = BULLET_LIST_TYPES.has(parentType.name);\n if (!expectsTaskItem && !expectsListItem) return content;\n\n const targetTypeName = expectsTaskItem ? TASK_ITEM_TYPE : LIST_ITEM_TYPE;\n const oppositeTypeName = expectsTaskItem ? LIST_ITEM_TYPE : TASK_ITEM_TYPE;\n const targetItemType = schema.nodes[targetTypeName];\n if (!targetItemType) return content;\n\n // Snapshot children so we can short-circuit when nothing needs\n // adapting - every direct child is already the matching item type.\n const children: Node[] = [];\n content.forEach((child) => { children.push(child); });\n const allMatch = children.every((c) => c.type.name === targetTypeName);\n if (allMatch) return content;\n\n const replaced = children.map((child) => {\n // (1) Already the right type - keep as-is.\n if (child.type.name === targetTypeName) return child;\n\n // (2) Opposite list-item type - convert by reusing inner content.\n if (child.type.name === oppositeTypeName) {\n const newAttrs = expectsTaskItem\n ? { ...child.attrs, checked: false }\n : { ...child.attrs };\n return targetItemType.create(newAttrs, child.content, child.marks);\n }\n\n // (3) Arbitrary block (heading, paragraph, codeBlock, …) - wrap it\n // in a fresh item. Notion-strict listItem requires `paragraph\n // block*` content, so for non-paragraph children we prepend an\n // empty label paragraph (the bullet/checkbox-aligned line) and\n // attach the dragged block below it as a nested child.\n const wrapperAttrs: Record<string, unknown> = expectsTaskItem\n ? { checked: false }\n : {};\n if (child.type.name === 'paragraph') {\n return targetItemType.create(wrapperAttrs, [child]);\n }\n const paragraphType = schema.nodes['paragraph'];\n const labelParagraph = paragraphType?.createAndFill();\n const content = labelParagraph ? [labelParagraph, child] : [child];\n return targetItemType.create(wrapperAttrs, content);\n });\n\n return Fragment.from(replaced);\n}\n","import type { Transaction } from '@domternal/pm/state';\nimport { expandToEmptyWrappers } from './expandToEmptyWrappers.js';\nimport { convertListItemForParent } from './convertListItemForParent.js';\n\n/**\n * Move a top-level block from `sourcePos` to `targetPos` in-place. Single\n * source of truth for block reorder position math, used by BlockHandle\n * drag-drop and KeyboardReorder.\n *\n * Notable steps: deletion range expands outward to swallow single-child\n * wrapper ancestors (else PM's fitter leaves an empty `<li>` placeholder);\n * the slice is adapted to the target parent's content rule (listItem ↔\n * taskItem auto-conversion when dropping across list types). Self-drops\n * (target inside the expanded deletion range) return the transaction\n * unchanged.\n */\nexport function moveBlock(\n tr: Transaction,\n sourcePos: number,\n targetPos: number,\n): Transaction {\n if (sourcePos < 0 || sourcePos >= tr.doc.content.size) return tr;\n const sourceNode = tr.doc.nodeAt(sourcePos);\n if (!sourceNode) return tr;\n const sourceEnd = sourcePos + sourceNode.nodeSize;\n\n const { from, to } = expandToEmptyWrappers(tr.doc, sourcePos, sourceEnd);\n if (targetPos >= from && targetPos <= to) return tr;\n\n // Slice ONLY the source node (not the wrappers we're about to remove -\n // they exist purely as redundant single-child containers and should not\n // travel with the source to its new location).\n const slice = tr.doc.slice(sourcePos, sourceEnd);\n tr.delete(from, to);\n const adjustedTarget = targetPos > from\n ? targetPos - (to - from)\n : targetPos;\n\n // Auto-convert listItem ↔ taskItem when crossing list types, matching\n // Notion's \"drop adapts to context\" UX. When the target's parent isn't\n // a list wrapper (top-level drops, paragraph parents, etc.) the helper\n // returns the slice content unchanged.\n const targetParent = tr.doc.resolve(adjustedTarget).parent;\n const adaptedContent = convertListItemForParent(\n tr.doc.type.schema,\n slice.content,\n targetParent.type,\n );\n\n tr.insert(adjustedTarget, adaptedContent);\n return tr;\n}\n\n","import { Fragment } from '@domternal/pm/model';\nimport type { Node as PMNode } from '@domternal/pm/model';\nimport type { Transaction } from '@domternal/pm/state';\nimport { insertAsListItemChild } from '@domternal/core';\nimport { expandToEmptyWrappers } from './expandToEmptyWrappers.js';\nimport { convertListItemForParent } from './convertListItemForParent.js';\n\nconst LIST_ITEM_TYPES = new Set(['listItem', 'taskItem']);\n\n/**\n * Moves a block from `sourcePos` and inserts it as the LAST child of\n * the list item at `targetItemPos` inside the wrapper at `wrapperPos`.\n * Shared drop-indent path used by `BlockHandle.performBlockDrop` when\n * `computeDropPlacement` returns `mode: 'nested'`.\n *\n * Behaviour matrix:\n *\n * - **Non-list source** (paragraph, heading, codeBlock, blockquote,\n * horizontalRule, image, etc.) - inserted directly as last child of\n * the target item. Schema (`paragraph block*`) accepts any block in\n * the trailing slot.\n * - **List item source** (listItem / taskItem) - wrapped in a fresh\n * list wrapper of the SAME TYPE as the target's wrapper, with the\n * source's item type adapted (via `convertListItemForParent`) so a\n * bulletList listItem dropped into a taskList nested zone becomes a\n * fresh taskList with a taskItem inside. Result: the dragged item\n * appears as a nested sublist below the target item's label.\n *\n * Position math is delegated to `insertAsListItemChild` which handles\n * source-before-vs-after-target ordering automatically. Source range\n * is widened via `expandToEmptyWrappers` so single-child containers\n * don't leave empty placeholders behind (matches `moveBlock` semantics).\n *\n * Returns `false` (no mutation) when:\n * - source position is invalid / no node\n * - target position falls inside the source range (self-drop)\n * - schema rejects the resulting structure (caller falls through to\n * a sibling-style fallback or no-op)\n */\nexport function moveBlockAsNestedChild(\n tr: Transaction,\n sourcePos: number,\n wrapperPos: number,\n targetItemPos: number,\n): boolean {\n if (sourcePos < 0 || sourcePos >= tr.doc.content.size) return false;\n const sourceNode = tr.doc.nodeAt(sourcePos);\n if (!sourceNode) return false;\n const sourceEnd = sourcePos + sourceNode.nodeSize;\n\n // Self-drop guard: target item or its wrapper sits inside the source\n // range. Prevents \"move A into A's own subtree\" - an invalid op that\n // would otherwise corrupt the document.\n if (targetItemPos >= sourcePos && targetItemPos < sourceEnd) return false;\n if (wrapperPos >= sourcePos && wrapperPos < sourceEnd) return false;\n\n // Widen the deletion range so a single-child wrapper around the\n // source (e.g., a nested ul whose only li is the source) collapses\n // along with the source, instead of being left as an empty placeholder.\n const { from: expandedFrom, to: expandedTo } = expandToEmptyWrappers(tr.doc, sourcePos, sourceEnd);\n\n // Pick the block to insert. For a list-item source we wrap it in a\n // fresh list wrapper so the trailing block-slot of the target item\n // (which expects a block, not a bare listItem) accepts the insertion\n // and the result reads as a nested sublist below the target's label.\n let blockNode: PMNode;\n if (LIST_ITEM_TYPES.has(sourceNode.type.name)) {\n const wrapperNode = tr.doc.nodeAt(wrapperPos);\n if (!wrapperNode) return false;\n const adaptedFragment = convertListItemForParent(\n tr.doc.type.schema,\n Fragment.from(sourceNode),\n wrapperNode.type,\n );\n if (adaptedFragment.childCount === 0) return false;\n blockNode = wrapperNode.type.create(null, adaptedFragment);\n } else {\n blockNode = sourceNode;\n }\n\n const result = insertAsListItemChild({\n tr,\n wrapperPos,\n targetItemPos,\n blockNode,\n sourceRange: { from: expandedFrom, to: expandedTo },\n });\n return result.ok;\n}\n","/**\n * Build an off-screen \"ghost\" of a block suitable for HTML5\n * `dataTransfer.setDragImage`.\n *\n * The browser snapshots whatever element you pass to `setDragImage` at\n * call time, with ambient transforms, scroll offsets, and ancestor\n * clipping applied. Pseudo-class styles and effects inherited from\n * ancestors that don't survive in a detached clone are also lost.\n *\n * The workaround: deep-clone the node, then walk both trees in parallel\n * and copy the resolved `cssText` from `getComputedStyle` onto each\n * cloned element's inline `style`. The result paints identically to the\n * original even when detached. The clone goes into an absolutely\n * positioned wrapper far above the viewport so it is invisible during\n * the snapshot, and the wrapper is removed on dragend/drop.\n */\n\nexport interface DragGhost {\n /** Wrapper element to pass to `setDragImage`. */\n wrapper: HTMLElement;\n}\n\n/**\n * Create a styled ghost of `source` and append the wrapper to\n * `document.body`. Caller must remove the wrapper when the drag ends.\n */\nexport function createDragGhost(source: HTMLElement): DragGhost {\n const wrapper = makeWrapper(source);\n const clone = deepCloneWithStyles(source);\n wrapper.appendChild(clone);\n document.body.appendChild(wrapper);\n return { wrapper };\n}\n\nfunction makeWrapper(source: HTMLElement): HTMLElement {\n const w = document.createElement('div');\n w.setAttribute('aria-hidden', 'true');\n Object.assign(w.style, {\n position: 'absolute',\n top: '-10000px',\n left: '-10000px',\n pointerEvents: 'none',\n width: `${String(source.getBoundingClientRect().width)}px`,\n });\n return w;\n}\n\nfunction deepCloneWithStyles(source: HTMLElement): HTMLElement {\n const clone = source.cloneNode(true) as HTMLElement;\n freezeStylesIntoClone(source, clone);\n return clone;\n}\n\nfunction freezeStylesIntoClone(src: Element, dst: Element): void {\n if (src instanceof HTMLElement && dst instanceof HTMLElement) {\n dst.style.cssText = getComputedStyle(src).cssText;\n }\n const srcKids = src.children;\n const dstKids = dst.children;\n const n = Math.min(srcKids.length, dstKids.length);\n for (let i = 0; i < n; i++) {\n const s = srcKids.item(i);\n const d = dstKids.item(i);\n if (s !== null && d !== null) freezeStylesIntoClone(s, d);\n }\n}\n","/**\n * Clamp a (clientX, clientY) pair into the editor's content rectangle\n * so position resolution still works when the cursor is in the side\n * gutter (where the block handle visually lives) or above/below the\n * first/last block.\n *\n * The clamp targets `view.dom.firstElementChild`'s left/right edges\n * (the actual content rect) rather than `view.dom`'s padded box, so\n * a wide editor with `padding-left: 4rem` still anchors X clamps to\n * where text actually lives.\n *\n * Y is only clamped when the cursor is OUTSIDE the editor's vertical\n * span (above the first block or below the last block). When the cursor\n * is INSIDE the editor's span, Y passes through unchanged - clipping the\n * edges (e.g. 5px off the bottom) would otherwise hide thin nested blocks\n * like a 2px-tall horizontal rule that sits at the very bottom of the\n * last top-level container. The `inset` only applies when the cursor is\n * out-of-bounds, snapping it just-inside the content edge.\n *\n * Returns `null` for an empty document - caller should bail out and\n * keep the handle hidden.\n */\nimport type { EditorView } from '@domternal/pm/view';\n\nconst DEFAULT_INSET_PX = 5;\n\nexport function clampToContent(\n view: EditorView,\n clientX: number,\n clientY: number,\n inset: number = DEFAULT_INSET_PX,\n): { x: number; y: number } | null {\n const first = view.dom.firstElementChild;\n const last = view.dom.lastElementChild;\n if (!first || !last) return null;\n\n const topRect = first.getBoundingClientRect();\n const bottomRect = last.getBoundingClientRect();\n\n // Out-of-bounds clamp ONLY: cursor inside the editor's vertical span\n // keeps its exact Y so nested elements at the very edge are reachable.\n let clampedY = clientY;\n if (clientY < topRect.top) clampedY = topRect.top + inset;\n else if (clientY > bottomRect.bottom) clampedY = bottomRect.bottom - inset;\n\n // Use the first block's horizontal extent as the \"content row\" to clamp\n // X into. Multi-column layouts where blocks have wildly different widths\n // are not supported here; for our schema (linear blocks of uniform width)\n // this is sufficient.\n const minX = topRect.left + inset;\n const maxX = topRect.right - inset;\n const clampedX = Math.max(minX, Math.min(clientX, maxX));\n\n return { x: clampedX, y: clampedY };\n}\n","/**\n * Gutter-bias resolution for nested drag-target selection.\n *\n * When the cursor sits near a configured edge of a candidate's rect, the\n * candidate is treated as \"in the gutter\" and its rank weight is reduced\n * proportionally to its tree depth. Shallower (outer) ancestors therefore\n * win against deeply-nested descendants in the gutter zone.\n *\n * The \"deepest-match\" mode skips this bias entirely and always returns the\n * innermost allowed block under the cursor.\n */\n\n/** Cardinal edge of a candidate's bounding rect. */\nexport type GutterEdge = 'left' | 'right' | 'top' | 'bottom';\n\n/**\n * Named presets for the bias config:\n * - `'left'` → ['left', 'top'] (left gutter, default)\n * - `'right'` → ['right', 'top'] (right gutter, RTL-friendly)\n * - `'both'` → ['left', 'right', 'top']\n * - `'none'` → no gutter bias (deepest match wins)\n */\nexport type GutterBiasPreset = 'left' | 'right' | 'both' | 'none';\n\nexport interface GutterBiasConfig {\n /** Edges that constitute the \"gutter\" zone. */\n edges: GutterEdge[];\n /** Pixel distance from the edge at which the bias activates. */\n threshold: number;\n /** Bias factor applied per depth level when in the gutter. */\n strength: number;\n}\n\nconst PRESET_DEFAULT: GutterBiasConfig = {\n edges: ['left', 'top'],\n threshold: 12,\n strength: 500,\n};\n\nconst PRESET_RIGHT: GutterBiasConfig = { ...PRESET_DEFAULT, edges: ['right', 'top'] };\nconst PRESET_BOTH: GutterBiasConfig = { ...PRESET_DEFAULT, edges: ['left', 'right', 'top'] };\n\n/**\n * Resolve the user-facing `promoteOnEdge` input into a concrete bias\n * configuration, or `null` when bias is disabled.\n *\n * Returns `null` for `undefined`, `false`, or `'none'` (deepest-match wins).\n */\nexport function resolveGutterBias(\n input: boolean | GutterBiasPreset | Partial<GutterBiasConfig> | undefined,\n): GutterBiasConfig | null {\n switch (input) {\n case undefined:\n case false:\n case 'none':\n return null;\n case true:\n case 'left':\n return { ...PRESET_DEFAULT };\n case 'right':\n return { ...PRESET_RIGHT };\n case 'both':\n return { ...PRESET_BOTH };\n default:\n return {\n edges: input.edges ?? PRESET_DEFAULT.edges,\n threshold: input.threshold ?? PRESET_DEFAULT.threshold,\n strength: input.strength ?? PRESET_DEFAULT.strength,\n };\n }\n}\n\n/**\n * True when `(x, y)` falls inside the gutter zone defined by `config`.\n * The zone is the union of strips `threshold` px wide along each\n * configured edge of `rect`.\n */\nexport function isInGutter(\n x: number,\n y: number,\n rect: DOMRect,\n config: GutterBiasConfig,\n): boolean {\n const t = config.threshold;\n for (const edge of config.edges) {\n if (edge === 'left' && x - rect.left <= t) return true;\n if (edge === 'right' && rect.right - x <= t) return true;\n if (edge === 'top' && y - rect.top <= t) return true;\n if (edge === 'bottom' && rect.bottom - y <= t) return true;\n }\n return false;\n}\n\n/**\n * Compute the rank-weight penalty for a candidate at `depth` whose rect\n * is in the gutter zone. Returns 0 when the candidate is outside the\n * gutter (no penalty applied).\n */\nexport function gutterBiasWeight(\n x: number,\n y: number,\n rect: DOMRect,\n depth: number,\n config: GutterBiasConfig,\n): number {\n return isInGutter(x, y, rect, config) ? config.strength * depth : 0;\n}\n","/**\n * Built-in eligibility matchers. Together they constrain the drag\n * resolver to \"user-visible block units\" (paragraphs, headings, list\n * items, task items, images, etc.) and exclude structural plumbing\n * (table cells, inline text, list containers whose items are draggable\n * individually).\n *\n * Hosts can disable the bundled set with `defaultMatchers: false` and\n * supply their own matcher list via `matchers`.\n */\nimport type { BlockMatcher } from './blockMatcher.js';\n\nconst LIST_ITEM_NODE_TYPES = new Set(['listItem', 'taskItem']);\nconst TABLE_PLUMBING_TYPES = new Set(['tableRow', 'tableCell', 'tableHeader']);\n\n/**\n * Reject a paragraph that is the first child of a list/task item.\n * Dragging that paragraph alone would split the item; promoting the\n * matcher to \"reject\" sends the resolver up to the list item itself.\n */\nconst firstChildOfListItem: BlockMatcher = {\n name: 'firstChildOfListItem',\n test(candidate) {\n if (!candidate.isFirstChild) return 'allow';\n const parent = candidate.container;\n if (parent === null) return 'allow';\n return LIST_ITEM_NODE_TYPES.has(parent.type.name) ? 'reject' : 'allow';\n },\n};\n\n/**\n * Reject a list/task container when its direct children are list items.\n * Without this the resolver would lock onto the wrapping list near the\n * top edge of the first item.\n */\nconst listContainerSkip: BlockMatcher = {\n name: 'listContainerSkip',\n test(candidate) {\n const firstChild = candidate.block.firstChild;\n if (firstChild === null) return 'allow';\n return LIST_ITEM_NODE_TYPES.has(firstChild.type.name) ? 'reject' : 'allow';\n },\n};\n\n/**\n * Reject table-internal nodes. Table rows, cells, and headers are\n * managed by the Table extension's own UI - the block handle is for\n * top-level blocks only.\n */\nconst tableInternals: BlockMatcher = {\n name: 'tableInternals',\n test(candidate) {\n if (TABLE_PLUMBING_TYPES.has(candidate.block.type.name)) return 'reject';\n if (candidate.container?.type.name === 'tableHeader') return 'reject';\n return 'allow';\n },\n};\n\n/**\n * Reject inline-level nodes (text, marks-bearing inline). The handle\n * targets block-level content only.\n */\nconst inlineNodes: BlockMatcher = {\n name: 'inlineNodes',\n test(candidate) {\n const { block } = candidate;\n return block.isText || block.isInline ? 'reject' : 'allow';\n },\n};\n\nexport const DEFAULT_BLOCK_MATCHERS: readonly BlockMatcher[] = Object.freeze([\n firstChildOfListItem,\n listContainerSkip,\n tableInternals,\n inlineNodes,\n]);\n","/**\n * Two-stage drag target resolver: filter eligible candidates by matcher\n * verdicts, then rank survivors by depth (and optional gutter bias).\n *\n * Algorithm:\n * 1. Resolve cursor to a doc position via `posAtCoords`.\n * 2. Walk ancestors from the deepest (innermost) outward.\n * 3. Each ancestor is checked against type/container constraints, then\n * against every matcher's `test()`. Any 'reject' verdict drops it.\n * 4. Atom leaves (image, horizontal rule, etc.) are not ancestors of\n * the resolved position - they live at `$pos.nodeAfter`. A separate\n * pass adds them as candidates at depth + 1.\n * 5. The survivor list is ranked: when no gutter bias is configured,\n * depth alone decides (deepest wins). When bias is configured, each\n * candidate's effective rank is `treeDepth - gutterPenalty`, where\n * `gutterPenalty = strength * depth` for in-gutter rects and 0\n * otherwise.\n * 6. Highest effective rank wins; ties break by deeper depth.\n */\nimport type { Node, ResolvedPos } from '@domternal/pm/model';\nimport type { EditorView } from '@domternal/pm/view';\n\nimport type { BlockCandidate, BlockMatcher, MatchVerdict } from './blockMatcher.js';\nimport { gutterBiasWeight } from './gutterBias.js';\nimport type { GutterBiasConfig } from './gutterBias.js';\n\nexport interface ResolveDragTargetOptions {\n /** Matchers applied to every candidate. Empty array = no filtering. */\n matchers: readonly BlockMatcher[];\n /** Active gutter-bias config, or `null` to disable. */\n gutterBias: GutterBiasConfig | null;\n /**\n * Allow-list of PM node type names. When non-empty, only nodes whose\n * type name appears here can become the drag target.\n */\n allowedTypes?: readonly string[];\n /**\n * Required ancestor types. When non-empty, the candidate's chain must\n * contain at least one ancestor whose type name appears here.\n */\n requiredAncestorTypes?: readonly string[];\n}\n\nexport interface DragTarget {\n pos: number;\n rect: DOMRect;\n dom: HTMLElement;\n /** Tree depth at which the target sits. */\n depth: number;\n /** Effective rank used to pick this candidate. Exposed for tests. */\n rank: number;\n /** The PM node at `pos`. */\n node: Node;\n}\n\ninterface RankedCandidate extends DragTarget {}\n\n/**\n * Find the best drag target for cursor `(x, y)`, or `null` when no\n * candidate survives the matcher pass.\n */\nexport function resolveDragTarget(\n view: EditorView,\n x: number,\n y: number,\n options: ResolveDragTargetOptions,\n): DragTarget | null {\n const coord = view.posAtCoords({ left: x, top: y });\n if (coord === null) return null;\n\n const $pos = view.state.doc.resolve(coord.pos);\n const survivors: RankedCandidate[] = [];\n\n collectAncestors($pos, view, options, survivors);\n collectAtomLeaf($pos, view, options, survivors);\n\n if (survivors.length === 0) return null;\n applyGutterBias(survivors, x, y, options.gutterBias);\n return chooseWinner(survivors);\n}\n\nfunction collectAncestors(\n $pos: ResolvedPos,\n view: EditorView,\n options: ResolveDragTargetOptions,\n out: RankedCandidate[],\n): void {\n for (let depth = $pos.depth; depth >= 1; depth--) {\n const block = $pos.node(depth);\n const documentPos = $pos.before(depth);\n const container = depth > 0 ? $pos.node(depth - 1) : null;\n const positionInContainer = depth > 0 ? $pos.index(depth - 1) : 0;\n const containerSize = container?.childCount ?? 1;\n\n if (!passesScopeFilters(block, $pos, depth, options)) continue;\n\n const candidate: BlockCandidate = {\n block,\n documentPos,\n treeDepth: depth,\n container,\n positionInContainer,\n isFirstChild: positionInContainer === 0,\n isLastChild: positionInContainer === containerSize - 1,\n resolvedPos: $pos,\n editorView: view,\n };\n\n if (rejectedByMatchers(candidate, options.matchers)) continue;\n\n const dom = view.nodeDOM(documentPos);\n if (!(dom instanceof HTMLElement)) continue;\n\n out.push({\n pos: documentPos,\n rect: dom.getBoundingClientRect(),\n dom,\n depth,\n rank: depth,\n node: block,\n });\n }\n}\n\nfunction collectAtomLeaf(\n $pos: ResolvedPos,\n view: EditorView,\n options: ResolveDragTargetOptions,\n out: RankedCandidate[],\n): void {\n const leaf = $pos.nodeAfter;\n if (leaf === null) return;\n if (!leaf.isAtom || leaf.isInline) return;\n\n const synthDepth = $pos.depth + 1;\n if (!passesScopeFilters(leaf, $pos, synthDepth, options)) return;\n\n const parent = $pos.parent;\n const positionInContainer = $pos.index();\n const containerSize = parent.childCount;\n\n const candidate: BlockCandidate = {\n block: leaf,\n documentPos: $pos.pos,\n treeDepth: synthDepth,\n container: parent,\n positionInContainer,\n isFirstChild: positionInContainer === 0,\n isLastChild: positionInContainer === containerSize - 1,\n resolvedPos: $pos,\n editorView: view,\n };\n\n if (rejectedByMatchers(candidate, options.matchers)) return;\n\n const dom = view.nodeDOM($pos.pos);\n if (!(dom instanceof HTMLElement)) return;\n\n out.push({\n pos: $pos.pos,\n rect: dom.getBoundingClientRect(),\n dom,\n depth: synthDepth,\n rank: synthDepth,\n node: leaf,\n });\n}\n\nfunction passesScopeFilters(\n block: Node,\n $pos: ResolvedPos,\n depth: number,\n options: ResolveDragTargetOptions,\n): boolean {\n const { allowedTypes, requiredAncestorTypes } = options;\n\n if (allowedTypes !== undefined && allowedTypes.length > 0) {\n if (!allowedTypes.includes(block.type.name)) return false;\n }\n\n if (requiredAncestorTypes !== undefined && requiredAncestorTypes.length > 0) {\n if (!hasMatchingAncestor($pos, depth, requiredAncestorTypes)) return false;\n }\n\n return true;\n}\n\nfunction hasMatchingAncestor(\n $pos: ResolvedPos,\n depth: number,\n acceptableTypes: readonly string[],\n): boolean {\n for (let d = depth - 1; d >= 1; d--) {\n const ancestor = $pos.node(d);\n if (acceptableTypes.includes(ancestor.type.name)) return true;\n }\n return false;\n}\n\nfunction rejectedByMatchers(\n candidate: BlockCandidate,\n matchers: readonly BlockMatcher[],\n): boolean {\n for (const matcher of matchers) {\n const verdict: MatchVerdict = matcher.test(candidate);\n if (verdict === 'reject') return true;\n }\n return false;\n}\n\nfunction applyGutterBias(\n candidates: RankedCandidate[],\n x: number,\n y: number,\n config: GutterBiasConfig | null,\n): void {\n if (config === null) return;\n for (const c of candidates) {\n const penalty = gutterBiasWeight(x, y, c.rect, c.depth, config);\n c.rank = c.depth - penalty;\n }\n}\n\nfunction chooseWinner(candidates: readonly RankedCandidate[]): DragTarget {\n // Caller guarantees `candidates.length > 0`; the `reduce` keeps the\n // type narrowing happy without non-null assertions on indexed access.\n return candidates.reduce((best, c) => {\n if (c.rank > best.rank) return c;\n if (c.rank === best.rank && c.depth > best.depth) return c;\n return best;\n });\n}\n","/**\n * BlockHandle Extension\n *\n * Renders a Notion-style gutter handle on the left side of each top-level\n * block when the user hovers over the editor. The handle exposes two\n * buttons:\n *\n * 1. `⋮⋮` drag handle (click → opens BlockContextMenu, drag → reorder)\n * 2. `+` insert button (inserts an empty paragraph below the block; the\n * FloatingMenu extension picks up the empty-line state and auto-shows\n * its insert menu)\n *\n * Visibility + drag + context-menu trigger are fully owned by this plugin;\n * the context menu UI itself lives in `BlockContextMenu.ts` and listens for\n * the `dm:block-context-menu-open` custom event that this plugin dispatches.\n *\n * Styles ship via `@domternal/theme` (`_block-handle.scss`). The plugin\n * adds a `dm-editor--has-block-handle` class to the `.dm-editor` container\n * so the theme stylesheet can widen `.ProseMirror` padding-left to create\n * gutter space inside the `overflow:hidden` editor wrapper.\n */\nimport { Extension, defaultIcons } from '@domternal/core';\nimport type { Editor } from '@domternal/core';\nimport { NodeSelection, Plugin, PluginKey, TextSelection } from '@domternal/pm/state';\nimport type { EditorView } from '@domternal/pm/view';\nimport type { Slice } from '@domternal/pm/model';\nimport { findDeepestBlockAtY } from './helpers/findTopLevelBlock.js';\nimport { moveBlock } from './helpers/moveBlock.js';\nimport { moveBlockAsNestedChild } from './helpers/moveBlockAsNestedChild.js';\nimport { createDragGhost } from './helpers/dragGhost.js';\nimport { clampToContent } from './helpers/clampCoords.js';\nimport { resolveGutterBias } from './helpers/gutterBias.js';\nimport type { GutterBiasConfig, GutterBiasPreset } from './helpers/gutterBias.js';\nimport { DEFAULT_BLOCK_MATCHERS } from './helpers/defaultMatchers.js';\nimport { resolveDragTarget } from './helpers/resolveDragTarget.js';\nimport type { BlockMatcher } from './helpers/blockMatcher.js';\nimport { showFloatingMenu } from './FloatingMenu.js';\n\n/** Default list of nodes treated as drag-targetable when `nested: true`. */\nexport const DEFAULT_NESTED_NODES: string[] = ['listItem', 'taskItem'];\n\n/**\n * Node types that accept a nested-child drop in MVP. When the resolver\n * lands on one of these AND `clientX` exceeds `nestThreshold` from the\n * left edge, `computeDropPlacement` returns `mode: 'nested'`. Other\n * containers (blockquote, codeBlock, details) have their own content\n * rules and remain sibling-only until explicit support lands.\n */\nconst LIST_ITEM_TYPES = new Set(['listItem', 'taskItem']);\n\n/**\n * Default pixel threshold from the left edge of a list item beyond\n * which drop commits to nested-child mode. Roughly the width of a\n * bullet/checkbox marker (~24px) + a small buffer so the boundary\n * sits just past where the marker visually ends.\n */\nexport const DEFAULT_NEST_THRESHOLD = 28;\n\n/**\n * Pixel inset of the nested-mode drop indicator from the resolved\n * block's left edge. Mirrors `--dm-block-children-indent` (1.5rem ≈\n * 24px) so the dashed line lands exactly where a nested child block\n * would render inside the list item.\n */\nconst NESTED_INDICATOR_INDENT_PX = 24;\n\n/**\n * Drop-zone tolerance in CSS pixels. The handle's drop zone extends\n * `DROP_ZONE_TOL_LEFT` past the editor's left edge (so the gutter where\n * the handle visually lives counts as a valid drop area) and `DROP_ZONE_TOL`\n * on every other edge (subpixel jitter + small margins outside `.dm-editor`).\n * Hardcoded so the gate stays predictable regardless of how callers style\n * the wrapper. Override behaviour by setting `dropIndicator: false` and\n * rendering your own visual.\n */\nconst DROP_ZONE_TOL_LEFT = 80;\nconst DROP_ZONE_TOL = 16;\n\nexport const blockHandlePluginKey = new PluginKey<BlockHandlePluginState>('blockHandle');\n\nexport interface BlockHandleOptions {\n /**\n * Milliseconds to wait before hiding the handle after the mouse leaves\n * the editor. Gives users time to move into the handle without it\n * disappearing.\n * @default 200\n */\n hideDelay?: number;\n /**\n * Disable drag-to-reorder while still showing the plus/drag buttons\n * (drag becomes a no-op, click opens context menu only).\n * @default false\n */\n disableDrag?: boolean;\n /**\n * Auto-scroll the nearest scrollable ancestor when the user drags near\n * the top/bottom edge of the viewport. Disable if the host app manages\n * its own drag scroll behaviour.\n * @default true\n */\n autoScroll?: boolean;\n /**\n * Distance in CSS pixels from the top/bottom edge that triggers\n * auto-scroll. Larger values start scrolling sooner.\n * @default 48\n */\n autoScrollThreshold?: number;\n /**\n * Peak scroll speed in CSS pixels per animation frame. Speed ramps\n * linearly from 0 at the threshold to this value at the edge.\n * @default 18\n */\n autoScrollMaxSpeed?: number;\n /**\n * Whether the handle should resolve to nested block containers (list\n * items, task items, and optionally others) instead of always the\n * top-level block.\n *\n * - `false` - only top-level blocks are hoverable / draggable (default).\n * - `true` - list items and task items resolve individually (Notion behaviour).\n * - object - fine-grained config; see `NestedConfig`.\n *\n * @default false\n */\n nested?: boolean | NestedConfig;\n /**\n * Pixel threshold from the LEFT edge of a list item beyond which a\n * drop commits to nested-child mode (the dragged block becomes the\n * last child of that item) instead of sibling mode (a new list item\n * created next to it). Mirrors Notion's \"drop indented = nested,\n * drop on the marker = sibling\" UX.\n *\n * Set to `0` to disable nested-drop entirely (every drop is sibling).\n *\n * The X-detection only fires when nested mode is on AND the resolved\n * target is a `listItem` / `taskItem`. Other containers stay sibling-\n * only until explicit support lands.\n *\n * @default 28\n */\n nestThreshold?: number;\n /**\n * Custom drop indicator that mirrors exactly where a handle-drag will\n * land. Replaces `prosemirror-dropcursor` for handle drags (PM's\n * `posAtCoords` can disagree with our resolver in the side gutter /\n * inter-block gap). While dragging, the editor gets a\n * `dm-block-handle-dragging` class so the theme can hide the native\n * `.prosemirror-dropcursor-block`/`-inline` for this drag only;\n * non-handle drags (text selection, external file drops) keep the\n * native cursor. Set to `false` to use the native dropcursor instead.\n * @default true\n */\n dropIndicator?: boolean;\n}\n\n/**\n * Configuration for nested resolution. Backwards-compatible with the\n * earlier `{ allowedNodes }` literal - every field is optional.\n */\nexport interface NestedConfig {\n /**\n * Node type names treated as drag targets when nested mode is on.\n * @default ['listItem', 'taskItem']\n */\n allowedNodes?: string[];\n /**\n * Restrict resolution to nodes that have at least one ancestor of one\n * of these type names. Use to scope nested mode to specific structures\n * (e.g. only inside `table`). Empty / omitted → no restriction.\n */\n allowedContainers?: string[];\n /**\n * \"Promote to parent at the gutter\" behaviour. When the cursor is\n * within `threshold` px of a configured edge, the candidate's score\n * is reduced by `strength * depth` - deeper nodes are penalised\n * more, so a shallower ancestor (e.g. the wrapping list) wins near\n * the boundary.\n *\n * - `false` / `undefined` / `'none'` → deepest match wins.\n * - `true` / `'left'` → defaults: edges `['left','top']`, threshold 12, strength 500.\n * - `'right'` / `'both'` → preset variants.\n * - object → custom config (any field optional, merged over defaults).\n *\n * @default false\n */\n promoteOnEdge?: boolean | GutterBiasPreset | Partial<GutterBiasConfig>;\n /**\n * Append custom block matchers. Default matchers still apply unless\n * `defaultMatchers: false` is also set.\n */\n matchers?: BlockMatcher[];\n /**\n * Set to `false` to disable the four built-in matchers\n * (firstChildOfListItem, listContainerSkip, tableInternals,\n * inlineNodes). Almost always wanted; opt-out only for testing or\n * specialised host editors.\n * @default true\n */\n defaultMatchers?: boolean;\n}\n\nexport interface BlockHandlePluginState {\n /** Absolute position of the top-level block currently under the cursor, or null. */\n hoveredPos: number | null;\n /**\n * Source position of the block currently being dragged (set on\n * dragstart, cleared on dragend). Used by `handleDrop` to determine\n * whether the drop originated from our handle.\n */\n draggedFrom: number | null;\n}\n\n/**\n * Minimal shape for ProseMirror's internal `view.dragging` property.\n * Assigning to it tells PM that a drag is in progress and which slice is\n * being moved; PM's default drop handler reads this to finalise the move.\n *\n * `node` is an undocumented but critical field - when present, PM's drop\n * handler treats it as the authoritative source selection to delete from\n * the old location, rather than relying on `view.state.selection`. The\n * browser may shift the selection mid-drag (e.g. when the user clicks\n * somewhere else during the drag), which without `node` causes the\n * original block to survive the drop. Setting it explicitly from the\n * `NodeSelection` we created on dragstart prevents this family of bugs.\n */\ninterface PMViewWithDragging {\n dragging: { slice: Slice; move: boolean; node?: NodeSelection } | null;\n}\n\n/** Casts `EditorView` to expose PM's internal `dragging` field. */\nfunction asDragView(view: EditorView): PMViewWithDragging {\n return view as unknown as PMViewWithDragging;\n}\n\n/**\n * Internal, fully-resolved view of `NestedConfig`. Plain string arrays\n * + an optional edge config so the resolver doesn't have to interpret\n * presets at hover time.\n */\nexport interface NestedResolution {\n /** Allowed drag targets. Empty array → top-level-only mode. */\n allowedNodes: string[];\n /** Optional ancestor whitelist; empty array → no restriction. */\n allowedContainers: string[];\n /** Gutter bias config; `null` → deepest match wins. */\n gutterBias: GutterBiasConfig | null;\n /** Effective matcher list (defaults + user, or just user when defaults off). */\n matchers: BlockMatcher[];\n}\n\nexport interface CreateBlockHandlePluginOptions {\n pluginKey: PluginKey<BlockHandlePluginState>;\n editor: Editor;\n hideDelay: number;\n disableDrag: boolean;\n autoScroll: boolean;\n autoScrollThreshold: number;\n autoScrollMaxSpeed: number;\n nested: NestedResolution;\n dropIndicator: boolean;\n /**\n * Pixel threshold for nested-drop X-detection (see `BlockHandleOptions.nestThreshold`).\n * `0` disables nested-drop.\n */\n nestThreshold: number;\n}\n\n/**\n * Walks up from `el` to the nearest ancestor that actually scrolls\n * vertically. Returns `null` when no bounded scrollable ancestor exists -\n * the caller should then skip its custom scroll loop and let the browser's\n * native drag-edge autoscroll handle page-level scrolling. Running both\n * our RAF scrollBy AND the browser's native scroll at the same time\n * double-scrolls and feels janky.\n */\nfunction findScrollableAncestor(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el;\n while (cur) {\n const style = getComputedStyle(cur);\n const overflowY = style.overflowY;\n if ((overflowY === 'auto' || overflowY === 'scroll') && cur.scrollHeight > cur.clientHeight) {\n return cur;\n }\n cur = cur.parentElement;\n }\n return null;\n}\n\n/**\n * Finds the block under the given client coordinates.\n *\n * When `nestedNodes` is non-empty, the plugin is in \"nested mode\":\n * resolves the deepest allowed block (list item, task item, etc.) at\n * the cursor row so users drag individual list items instead of always\n * the whole list.\n *\n * - Mode B (deepest-match, default): spatial Y-walk via `findDeepestBlockAtY`.\n * `posAtCoords` would resolve to whatever sits at the cursor's X,\n * which in the gutter is OUTER content (the inner items are indented\n * further right). The spatial walk anchors the handle on the row the\n * cursor is in, regardless of X.\n * - Mode C (gutter-bias ranking): uses `resolveDragTarget` with\n * gutter bias. By design, gutter-X promotes to OUTER (different\n * UX choice). Opt in via `promoteOnEdge`.\n *\n * When `nestedNodes` is empty, classic behavior: walk doc children and\n * compare Y against each top-level block's DOM rect, with a `posAtCoords`\n * fallback for positions in between blocks.\n */\nfunction resolveBlockAtCoords(\n view: EditorView,\n clientX: number,\n clientY: number,\n nested: NestedResolution,\n): { pos: number; rect: DOMRect; dom: HTMLElement } | null {\n // Mode A - top-level only (classic). Walk doc children by Y range; X\n // is intentionally ignored so the handle still surfaces when the\n // cursor is in the side gutter.\n if (nested.allowedNodes.length === 0) {\n return resolveTopLevelByY(view, clientY);\n }\n\n // Common to nested modes: clamp coords into the editor's content\n // rectangle so resolution survives cursor-in-gutter and above/below\n // edge cases (where `posAtCoords` would otherwise return null).\n const clamped = clampToContent(view, clientX, clientY);\n if (!clamped) return null;\n\n // Mode C - gutter-bias ranking.\n if (nested.gutterBias) {\n const target = resolveDragTarget(view, clamped.x, clamped.y, {\n matchers: nested.matchers,\n gutterBias: nested.gutterBias,\n allowedTypes: nested.allowedNodes,\n requiredAncestorTypes: nested.allowedContainers,\n });\n if (target) {\n return { pos: target.pos, rect: target.rect, dom: target.dom };\n }\n // Ranking picked nothing - fall through to top-level so the handle\n // still surfaces on the doc's outer block.\n return resolveTopLevelByY(view, clamped.y);\n }\n\n // Mode B - deepest allowed block at the cursor row.\n // X is intentionally ignored; see `findDeepestBlockAtY` rationale.\n // `nested.matchers` is forwarded so rejection logic (e.g.\n // firstChildOfListItem) applies consistently with Mode C - hosts\n // extending allowedNodes to include `paragraph` get label-paragraph\n // rejection for free.\n const found = findDeepestBlockAtY(view, clamped.y, nested.allowedNodes, nested.matchers);\n if (found) {\n return { pos: found.pos, rect: found.rect, dom: found.dom };\n }\n return resolveTopLevelByY(view, clamped.y);\n}\n\n/**\n * Top-level fallback used by every mode: walk the doc's direct children\n * and return the one whose vertical range contains `clientY`. X is\n * ignored so the handle resolves correctly even when the cursor sits\n * outside the editor's horizontal bounds.\n *\n * When no top-level block strictly contains `clientY` (cursor sits in\n * the inter-block gap, above the first block, or below the last), this\n * falls back to the **closest** top-level block by vertical distance.\n * The previous fallback used `posAtCoords({ left: 0, top: clientY })`\n * which returned `null` when X=0 was outside the editor's content area -\n * leading to silent drop-in-gap failures (the user sees a hover that\n * anchors but the drop does nothing). Closest-by-Y is robust regardless\n * of horizontal layout and matches Notion's \"drop sticks to the nearest\n * block\" UX.\n */\nfunction resolveTopLevelByY(\n view: EditorView,\n clientY: number,\n): { pos: number; rect: DOMRect; dom: HTMLElement } | null {\n const doc = view.state.doc;\n let offset = 0;\n let closest: { pos: number; rect: DOMRect; dom: HTMLElement; dist: number } | null = null;\n for (let i = 0; i < doc.childCount; i++) {\n const child = doc.child(i);\n const dom = view.nodeDOM(offset);\n if (dom instanceof HTMLElement) {\n const rect = dom.getBoundingClientRect();\n if (clientY >= rect.top && clientY <= rect.bottom) {\n return { pos: offset, rect, dom };\n }\n const dist = clientY < rect.top ? rect.top - clientY : clientY - rect.bottom;\n if (closest === null || dist < closest.dist) {\n closest = { pos: offset, rect, dom, dist };\n }\n }\n offset += child.nodeSize;\n }\n if (closest) return { pos: closest.pos, rect: closest.rect, dom: closest.dom };\n return null;\n}\n\nconst LIST_WRAPPER_TYPE_NAMES = new Set(['bulletList', 'orderedList', 'taskList']);\n\n/**\n * Notion-style \"drop sticks to the list\" semantics. When the resolved\n * drop target is a list-wrapper container (bulletList / orderedList /\n * taskList) and the cursor sits ABOVE its top edge or BELOW its bottom\n * edge, descend into the wrapper and pick the FIRST or LAST listItem\n * (respectively) so the drop lands inside the list rather than creating\n * a sibling list of one item.\n *\n * Without this, a drop in the small gap between a list bottom and the\n * next block would be processed against the wrapper UL - and PM's\n * subsequent insert at the wrapper's end position would auto-wrap the\n * dragged listItem in a brand-new bulletList sibling, which is rarely\n * what users intend (most lists were the user's grouping; they want the\n * drag to keep things in the same list).\n *\n * Returns `resolved` unchanged when:\n * - The resolved node isn't a list wrapper.\n * - The wrapper has no children (e.g. mid-edit transient state).\n * - The cursor is INSIDE the wrapper's vertical extent (the resolver\n * would have already returned a child via `findDeepestBlockAtY` in\n * that case; if we got the wrapper despite being inside, the caller's\n * default targeting is already correct).\n */\nfunction adjustDropTargetForListWrapper(\n view: EditorView,\n resolved: { pos: number; rect: DOMRect; dom: HTMLElement },\n clientY: number,\n): { pos: number; rect: DOMRect; dom: HTMLElement } {\n const node = view.state.doc.nodeAt(resolved.pos);\n if (!node) return resolved;\n if (!LIST_WRAPPER_TYPE_NAMES.has(node.type.name)) return resolved;\n if (node.childCount === 0) return resolved;\n\n const isAbove = clientY < resolved.rect.top;\n const isBelow = clientY > resolved.rect.bottom;\n if (!isAbove && !isBelow) return resolved;\n\n // Find absolute pos of the first or last child relative to the wrapper.\n // Wrapper opens at `resolved.pos`, so its first child starts at\n // `resolved.pos + 1` (one past the open token).\n const targetIndex = isBelow ? node.childCount - 1 : 0;\n let childPos = resolved.pos + 1;\n for (let i = 0; i < targetIndex; i++) {\n childPos += node.child(i).nodeSize;\n }\n const childDom = view.nodeDOM(childPos);\n if (!(childDom instanceof HTMLElement)) return resolved;\n return { pos: childPos, rect: childDom.getBoundingClientRect(), dom: childDom };\n}\n\n/**\n * Resolved drop target shared by `handleDrop` and `updateDropIndicator`\n * so the indicator draws exactly where the drop lands (no\n * \"indicator says X, item drops Y\" mismatch).\n *\n * `mode` distinguishes the two ways a block can be dropped over a list\n * item: `'sibling'` (the existing behaviour, drop position becomes a\n * new sibling of the target via the standard `moveBlock` flow) and\n * `'nested'` (drop becomes a nested child of `targetItemPos` inside\n * `wrapperPos`, applied via `insertAsListItemChild`). Today every\n * placement is `'sibling'`; the `'nested'` branch activates in a\n * follow-up that adds X-threshold detection.\n */\nexport interface DropPlacement {\n /** Position right BEFORE the resolved block (same convention as `nodeAt`). */\n pos: number;\n /** Bounding rect of the resolved block, used to draw the indicator line. */\n rect: DOMRect;\n /**\n * `true` -> drop lands AFTER the resolved block; `false` -> BEFORE.\n * Computed from cursor Y vs the resolved block's mid-line. Read by the\n * sibling-style drop pipeline; ignored when `mode === 'nested'` (the\n * nested branch dispatches via `insertAsListItemChild`).\n */\n insertAfter: boolean;\n /** Sibling drop (current behaviour) vs nested-child drop (drop-indent). */\n mode: 'sibling' | 'nested';\n /** Position of the target list item when `mode === 'nested'`. */\n targetItemPos?: number;\n /** Position of the containing list wrapper when `mode === 'nested'`. */\n wrapperPos?: number;\n}\n\n/**\n * Computes the FINAL drop placement using the same logic `handleDrop`\n * uses. Returned by both the actual drop handler AND the visual drop\n * indicator so the line draws exactly where the drop will land - no\n * \"indicator says one place, item drops elsewhere\" mismatch (the classic\n * dropcursor pain point with custom drop handlers).\n *\n * - `rect` is the resolved target block's rect (for drawing the line)\n * - `insertAfter` decides whether the line sits above or below the rect\n * AND whether the drop pos becomes `pos + nodeSize` or `pos`\n *\n * Returns `null` when the resolver finds no candidate (e.g. empty doc).\n *\n * **Inter-block gap normalization.** When the cursor sits in the gap\n * between two siblings, `resolveBlockAtCoords` flips between them based\n * on Y proximity. Without normalization the indicator would draw at two\n * different rect edges (upper.bottom vs lower.top) - visually two lines\n * for what is the SAME logical drop slot (PM treats `endOf(upper)` and\n * `startOf(lower)` as one position in the parent's content array). To\n * unify the visual we canonicalise `insertAfter=false` to \"after the\n * previous sibling\" whenever a previous sibling exists at the same depth.\n * Net effect: one gap → one line, anchored at the bottom edge of the\n * upper block, with the upper block's width (which equals the lower's\n * for prose at the same depth, so the line spans the content column).\n */\nexport function computeDropPlacement(\n view: EditorView,\n clientX: number,\n clientY: number,\n nested: NestedResolution,\n nestThreshold: number = DEFAULT_NEST_THRESHOLD,\n): DropPlacement | null {\n const initial = resolveBlockAtCoords(view, clientX, clientY, nested);\n if (!initial) return null;\n const resolved = adjustDropTargetForListWrapper(view, initial, clientY);\n\n // X-threshold detection: when the resolved target is a list item and\n // the cursor sits >= nestThreshold px from its left edge (inside the\n // rect's vertical span), commit to nested mode (drop becomes the\n // target item's LAST child). `nestThreshold === 0` disables the branch.\n if (nestThreshold > 0) {\n const targetNode = view.state.doc.nodeAt(resolved.pos);\n if (targetNode && LIST_ITEM_TYPES.has(targetNode.type.name)) {\n const targetRect = resolved.rect;\n const xInTarget = clientX - targetRect.left;\n const isInsideX = xInTarget >= 0 && xInTarget <= targetRect.width;\n const isInNestZone = xInTarget >= nestThreshold;\n const isInsideY = clientY >= targetRect.top && clientY <= targetRect.bottom;\n if (isInsideX && isInNestZone && isInsideY) {\n // Walk up to the wrapping list. `$resolved.before()` is the\n // position right before the parent at $resolved.depth, which for\n // a position between siblings is the wrapper itself.\n const $resolved = view.state.doc.resolve(resolved.pos);\n const wrapperPos = $resolved.before();\n // `insertAfter` mirrors the sibling-mode Y-mid calculation so the\n // field stays semantically meaningful when consumers (the nested\n // branch ignores it).\n const midY = targetRect.top + targetRect.height / 2;\n return {\n pos: resolved.pos,\n rect: targetRect,\n insertAfter: clientY > midY,\n mode: 'nested',\n targetItemPos: resolved.pos,\n wrapperPos,\n };\n }\n }\n }\n\n const rect = resolved.rect;\n const midY = rect.top + rect.height / 2;\n const insertAfter = clientY > midY;\n\n if (!insertAfter) {\n const prev = findPreviousSiblingAtSameDepth(view, resolved.pos);\n if (prev) {\n return { pos: prev.pos, rect: prev.rect, insertAfter: true, mode: 'sibling' };\n }\n }\n return { pos: resolved.pos, rect, insertAfter, mode: 'sibling' };\n}\n\n/**\n * Returns the previous sibling at the same parent depth as `pos` (which\n * must be the position immediately BEFORE a node - same convention as\n * `nodeAt`). Returns `null` when the node has no previous sibling (it's\n * the first child of its parent) or when the previous sibling has no DOM\n * representation.\n *\n * Works for any depth: top-level blocks resolve against `doc`; nested\n * blocks (list items, table cells) resolve against their immediate\n * container - so the canonical \"between\" position is always the upper\n * sibling within the SAME container, never crossing container boundaries.\n */\nfunction findPreviousSiblingAtSameDepth(\n view: EditorView,\n pos: number,\n): { pos: number; rect: DOMRect } | null {\n const doc = view.state.doc;\n if (pos <= 0) return null;\n const $pos = doc.resolve(pos);\n if ($pos.index() === 0) return null;\n const prevNode = $pos.parent.child($pos.index() - 1);\n const prevPos = pos - prevNode.nodeSize;\n const prevDom = view.nodeDOM(prevPos);\n if (!(prevDom instanceof HTMLElement)) return null;\n return { pos: prevPos, rect: prevDom.getBoundingClientRect() };\n}\n\n/**\n * Creates a standalone BlockHandle ProseMirror plugin. Exported so\n * framework wrappers can build on top without going through the Extension\n * factory.\n */\nexport function createBlockHandlePlugin(\n options: CreateBlockHandlePluginOptions,\n): Plugin<BlockHandlePluginState> {\n const { pluginKey, editor, hideDelay, disableDrag, autoScroll, autoScrollThreshold, autoScrollMaxSpeed, nested, dropIndicator, nestThreshold } = options;\n\n // --- Build DOM once. Buttons rendered with the shared Phosphor icons.\n const root = document.createElement('div');\n root.className = 'dm-block-handle';\n root.setAttribute('data-dm-editor-ui', '');\n\n const dragBtn = document.createElement('button');\n dragBtn.type = 'button';\n dragBtn.className = 'dm-block-handle-btn dm-block-handle-drag';\n dragBtn.setAttribute('aria-label', 'Drag to reorder, click for options');\n dragBtn.setAttribute('draggable', 'true');\n dragBtn.innerHTML = defaultIcons['dotsSixVertical'] ?? '';\n\n const plusBtn = document.createElement('button');\n plusBtn.type = 'button';\n plusBtn.className = 'dm-block-handle-btn dm-block-handle-plus';\n plusBtn.setAttribute('aria-label', 'Add block below');\n plusBtn.innerHTML = defaultIcons['plus'] ?? '';\n\n root.appendChild(dragBtn);\n root.appendChild(plusBtn);\n\n // --- Drop indicator: a thin horizontal line drawn at the resolved\n // drop target during an active drag. Built once, hidden by default,\n // appended into `.dm-editor` alongside the handle.\n const indicator = document.createElement('div');\n indicator.className = 'dm-block-drop-indicator';\n indicator.setAttribute('data-dm-editor-ui', '');\n\n let editorEl: HTMLElement | null = null;\n // Element that captures hover events. Usually `editorEl.parentElement`\n // so the listener catches mouse moves in the side gutter (where the\n // BlockHandle sits visually when the editor is centered narrower than\n // the page). Falls back to `editorEl` if no parent exists.\n let hoverEl: HTMLElement | null = null;\n let hideTimer: number | null = null;\n\n // Hover-tick state - rAF-coalesced to keep the handle glide-smooth even\n // when mousemove fires ~240Hz on high-refresh pointers. Only one rAF is\n // registered at a time; latest coords win. `currentHoveredPos` is the\n // identity gate: we only repaint when the ProseMirror position under\n // the cursor *changes*, not on every micro-move within the same block.\n let hoverRaf: number | null = null;\n let pendingHoverCoords: { x: number; y: number } | null = null;\n let currentHoveredPos: number | null = null;\n // Set on `mousedown` on the drag button, cleared on `mouseup` / `dragend`.\n // While truthy, hover updates are paused so the handle does NOT jump to\n // a neighbouring block during the browser's drag-initiation window\n // (the ~3-5px mousedown+move that decides click-vs-drag). Without this\n // lock, the handle slides out from under the user's cursor before the\n // browser has decided the interaction is a drag, and `dragstart` never\n // fires - feels like \"click and hold does nothing\".\n let dragPressActive = false;\n\n // Active drag preview wrapper - built on dragstart via `createDragGhost`,\n // removed on drop/dragend.\n let dragPreview: HTMLElement | null = null;\n\n // SYNC source position captured in `onDragStart`. Required because PM's\n // internal drop handler clears `view.dragging` BEFORE the `handleDrop`\n // plugin hook fires, AND the plugin-state `draggedFrom` is committed via\n // a deferred `setTimeout(0)` (see comment on the dispatch in `onDragStart`)\n // that may not have run by drop time on very fast drags. Closure scope is\n // independent of both, so reading from here is reliable. Cleared on\n // dragend, so it never lingers across drags.\n let pendingDraggedFrom: number | null = null;\n\n // Auto-scroll state machine (populated during an active drag, reset by\n // `resetAutoScroll`). Grouped into one object so every reset clears every\n // field - prevents the \"I forgot to reset X\" class of bug.\n //\n // `lastDragoverAt` is a `performance.now()` timestamp used by the RAF\n // loop as a dead-man switch: if no dragover arrived for `DRAGOVER_SILENCE_MS`,\n // we assume the drag was cancelled (browser ate dragend, OS-level abort)\n // and stop the loop to avoid leaking frames. 1.5s is generous enough to\n // tolerate users holding cursor still mid-drag, tight enough to recover\n // quickly when the browser drops events.\n const DRAGOVER_SILENCE_MS = 1500;\n const autoScrollState: {\n raf: number | null;\n target: HTMLElement | null;\n lastClientY: number | null;\n lastAt: number;\n } = { raf: null, target: null, lastClientY: null, lastAt: 0 };\n\n const resetAutoScroll = (): void => {\n if (autoScrollState.raf !== null) {\n cancelAnimationFrame(autoScrollState.raf);\n }\n autoScrollState.raf = null;\n autoScrollState.target = null;\n autoScrollState.lastClientY = null;\n autoScrollState.lastAt = 0;\n };\n\n const clearHideTimer = (): void => {\n if (hideTimer !== null) {\n window.clearTimeout(hideTimer);\n hideTimer = null;\n }\n };\n\n const hide = (): void => {\n root.removeAttribute('data-show');\n currentHoveredPos = null;\n };\n\n const scheduleHide = (): void => {\n // Context-menu pin: same gate as `onMouseMove`.\n if (editorEl?.hasAttribute('data-block-context-menu-open')) return;\n clearHideTimer();\n hideTimer = window.setTimeout(() => {\n hide();\n hideTimer = null;\n }, hideDelay);\n };\n\n const show = (blockEl: HTMLElement, blockRect: DOMRect, editorRect: DOMRect): void => {\n // Vertically center the handle on the FIRST LINE of the block, not on\n // the block's top edge. For tall blocks (e.g., H1 with line-height\n // 2.8rem) the top edge sits well above the visible text, leaving the\n // handle floating above the title. Aligning to the first line's\n // center matches Notion's positioning regardless of font size.\n const cs = getComputedStyle(blockEl);\n let lineHeight = parseFloat(cs.lineHeight);\n if (!Number.isFinite(lineHeight)) {\n // `line-height: normal` returns a non-numeric string - fall back to\n // ~1.2× the font size (browser default for `normal`).\n const fontSize = parseFloat(cs.fontSize) || 16;\n lineHeight = fontSize * 1.2;\n }\n const handleHeight = root.offsetHeight || 24;\n const offsetIntoBlock = Math.max(0, (lineHeight - handleHeight) / 2);\n const top = blockRect.top - editorRect.top + offsetIntoBlock;\n root.style.top = `${String(top)}px`;\n root.setAttribute('data-show', '');\n };\n\n const updateHoverState = (view: EditorView, pos: number | null): void => {\n const current = pluginKey.getState(view.state)?.hoveredPos ?? null;\n if (current === pos) return;\n view.dispatch(view.state.tr.setMeta(pluginKey, { hoveredPos: pos }));\n };\n\n const setDraggedFrom = (view: EditorView, pos: number | null): void => {\n view.dispatch(view.state.tr.setMeta(pluginKey, { draggedFrom: pos }));\n };\n\n // mousemove is the single hottest event on the editor - high-refresh\n // pointers fire it at 240+Hz. Running `posAtCoords` + `getBoundingClientRect`\n // + `style.top` writes on every tick causes visible wobble because each\n // layout read forces sync layout and each write flips the visibility of\n // the handle one frame at a time. Coalescing to one rAF per frame and\n // gating reposition on ProseMirror-position identity eliminates both.\n const onMouseMove = (event: MouseEvent): void => {\n if (!editorEl) return;\n // Freeze the handle in place while the user is pressing the drag\n // button. Moving it here would slide the button out from under the\n // cursor before the browser decides the interaction is a drag.\n if (dragPressActive) return;\n // Pin the handle to the source block while the BlockContextMenu\n // is open - it serves as the menu's visual anchor.\n if (editorEl.hasAttribute('data-block-context-menu-open')) return;\n pendingHoverCoords = { x: event.clientX, y: event.clientY };\n if (hoverRaf !== null) return;\n hoverRaf = requestAnimationFrame(() => {\n hoverRaf = null;\n const coords = pendingHoverCoords;\n pendingHoverCoords = null;\n if (!coords || !editorEl) return;\n // Re-check the pin gate: a mousemove queued pre-open can fire\n // after `open()` and otherwise reposition the handle.\n if (editorEl.hasAttribute('data-block-context-menu-open')) return;\n const resolved = resolveBlockAtCoords(editor.view, coords.x, coords.y, nested);\n if (!resolved) {\n scheduleHide();\n return;\n }\n clearHideTimer();\n // `updateHoverState` is a no-op when PM plugin state already matches\n // - keep it unconditional so that if a prior docChanged transaction\n // cleared `state.hoveredPos` (forward-assoc mapping can still miss\n // the edge cases around setNodeMarkup), the next hover tick\n // re-asserts it. Skipping this led to \"click on drag handle does\n // nothing\" after a color-swatch change, since the subsequent click\n // would bail with `hoveredPos === null`.\n updateHoverState(editor.view, resolved.pos);\n // Identity gate for the visual reposition only: don't rewrite\n // style.top + data-show if the cursor is still over the same block.\n // That's where the measurable smoothness win lives.\n if (resolved.pos === currentHoveredPos && root.hasAttribute('data-show')) {\n return;\n }\n currentHoveredPos = resolved.pos;\n const editorRect = editorEl.getBoundingClientRect();\n show(resolved.dom, resolved.rect, editorRect);\n });\n };\n\n const onMouseLeave = (): void => {\n scheduleHide();\n };\n\n const onMouseEnter = (): void => {\n clearHideTimer();\n };\n\n const onDismissOverlays = (): void => {\n // BlockContextMenu fires this event while opening to close other\n // overlays; keep the handle visible because it anchors the menu.\n // The attribute is set by `BlockContextMenu.open()` before the\n // dispatch, so its presence means \"context menu opening, not\n // dismissing me\".\n if (editorEl?.hasAttribute('data-block-context-menu-open')) return;\n hide();\n updateHoverState(editor.view, null);\n };\n\n // --- Plus button: dismiss other overlays, insert empty paragraph\n // after the hovered block, focus, then EXPLICITLY trigger the\n // FloatingMenu. Order matters:\n //\n // 1. Dispatch `dm:dismiss-overlays` FIRST - closes BubbleMenu /\n // ContextMenu / SlashCommand and any opt-in FloatingMenu that's\n // already open elsewhere. We do this before flipping our own\n // explicit-trigger flag so the dismissal can't accidentally\n // clear it.\n // 2. Insert the paragraph + move the caret + focus.\n // 3. Call `showFloatingMenu(view)` - required for FloatingMenu\n // instances configured with `requireExplicitTrigger: true`\n // (Notion-style; no auto-show on plain Enter). Default instances\n // ignore the meta and auto-show on the empty paragraph anyway.\n const onPlusClick = (event: MouseEvent): void => {\n event.preventDefault();\n event.stopPropagation();\n if (!editor.isEditable) return;\n const state = pluginKey.getState(editor.view.state);\n const pos = state?.hoveredPos ?? null;\n if (pos === null) return;\n const node = editor.view.state.doc.nodeAt(pos);\n if (!node) return;\n\n const paragraphType = editor.view.state.schema.nodes['paragraph'];\n if (!paragraphType) return;\n\n // (1) Close anything else that might be open.\n editorEl?.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n\n // (2) Insert the new paragraph + park the caret inside it.\n const blockEnd = pos + node.nodeSize;\n const tr = editor.view.state.tr;\n tr.insert(blockEnd, paragraphType.create());\n const sel = TextSelection.near(tr.doc.resolve(blockEnd + 1));\n tr.setSelection(sel);\n editor.view.dispatch(tr.scrollIntoView());\n editor.view.focus();\n\n // (3) Mark this insert as an explicit \"user wants the menu\" gesture.\n showFloatingMenu(editor.view);\n };\n\n // Plus button: keep editor focus during click so the FloatingMenu that\n // auto-appears after insert can read the correct state. `preventDefault`\n // on mousedown stops the button from grabbing focus.\n //\n // Drag button: must NOT call `preventDefault` on mousedown - for a\n // `draggable=\"true\"` element, the browser requires the default mousedown\n // action to initiate a drag. Cancelling it silently kills drag-to-reorder\n // in Chrome/Safari. Focus is restored explicitly after context-menu\n // actions via `editor.view.focus()`.\n const onPlusBtnMouseDown = (event: MouseEvent): void => {\n event.preventDefault();\n };\n\n // Lock the handle in place from mousedown through dragend (or mouseup\n // without drag). Prevents the rAF hover loop from repositioning the\n // handle out from under the cursor during the click-vs-drag window.\n //\n // Mouseup is attached lazily as a one-shot ONLY for the click-without-\n // drag path: the user pressed the drag button but never crossed the\n // browser's drag-init threshold. The dragend path calls `releaseDragPress`\n // directly. Keeping the listener attached for the editor's lifetime\n // (the previous design) leaked a global handler that fired on every\n // click anywhere in the document.\n const onDragBtnMouseDown = (): void => {\n dragPressActive = true;\n document.addEventListener('mouseup', releaseDragPress, { once: true });\n };\n const releaseDragPress = (): void => {\n dragPressActive = false;\n // Defensive: dragend may fire BEFORE mouseup (the common drag-success\n // path). Remove the once-listener so the next stray mouseup anywhere\n // in the page doesn't fire into an already-released lock.\n document.removeEventListener('mouseup', releaseDragPress);\n };\n\n // --- Drag handle: click opens context menu, drag reorders the block.\n //\n // Browser semantics we rely on: when `draggable=\"true\"` and the user\n // presses and releases without moving more than ~3px (browser threshold),\n // a `click` event fires and no `dragstart` is dispatched. Conversely, if\n // the user moves past that threshold, `dragstart` fires and `click` does\n // NOT. This gives us a free, reliable click-vs-drag split - no custom\n // threshold tracking needed.\n\n const onDragBtnClick = (event: MouseEvent): void => {\n event.preventDefault();\n event.stopPropagation();\n if (!editor.isEditable) return;\n const state = pluginKey.getState(editor.view.state);\n const pos = state?.hoveredPos ?? null;\n if (pos === null) return;\n // Dispatch custom event for BlockContextMenu plugin to pick up. Using\n // a CustomEvent with detail preserves both the source block and the\n // anchor element for positioning.\n editorEl?.dispatchEvent(new CustomEvent('dm:block-context-menu-open', {\n bubbles: false,\n detail: { blockPos: pos, anchorElement: dragBtn },\n }));\n };\n\n // --- Auto-scroll during drag.\n //\n // A single RAF loop runs for the whole drag. Each frame reads the last\n // known dragover Y and, if it's within `autoScrollThreshold` of the top\n // or bottom edge of the scrollable target, nudges scroll by a ramped\n // speed (linear from 0 at the threshold to `autoScrollMaxSpeed` at the\n // edge). The loop self-terminates if dragover has been silent for longer\n // than `DRAGOVER_SILENCE_MS` - a cheap failsafe against the browser\n // skipping the `dragend` event (it happens on some OS/browser combos).\n\n const onDocumentDragover = (event: DragEvent): void => {\n autoScrollState.lastClientY = event.clientY;\n autoScrollState.lastAt = performance.now();\n const inZone = isCursorOverDropZone(event.clientX, event.clientY);\n // CRITICAL: when the cursor is in our drop zone (incl. the gutter\n // outside `.ProseMirror`'s padding box), we MUST call preventDefault\n // on dragover. Without it, the browser refuses to fire the subsequent\n // `drop` event on non-PM targets (notion-page, body, etc.) - the\n // user's release becomes a silent no-op. With it, drop fires on\n // whatever element is under the cursor; bubbles up to our document\n // drop listener, which performs the move.\n if (inZone) event.preventDefault();\n if (dropIndicator) {\n if (!inZone) {\n indicator.removeAttribute('data-show');\n return;\n }\n updateDropIndicator(event.clientX, event.clientY);\n }\n };\n\n /**\n * Document-level drop listener. Catches drops that happened OUTSIDE\n * `.ProseMirror` (handle gutter, notion-page padding) but INSIDE our\n * indicator zone - places where the user just saw a \"drop will land\n * here\" line and reasonably expects the release to take effect.\n *\n * Bubbles after PM's own handler (registered on `view.dom`); when PM\n * handled the drop already we see `event.defaultPrevented === true`\n * and bail to avoid double-processing. When PM didn't see the drop\n * (cursor was in the gutter, target is `.notion-page` or similar)\n * `defaultPrevented` is false and we run the same drop logic ourselves.\n */\n const onDocumentDrop = (event: DragEvent): void => {\n if (event.defaultPrevented) return;\n const view = editor.view;\n const dragging = asDragView(view).dragging;\n if (!dragging) return;\n if (!isCursorOverDropZone(event.clientX, event.clientY)) return;\n if (performBlockDrop(event.clientX, event.clientY)) {\n event.preventDefault();\n }\n };\n\n /**\n * Shared drop logic - runs from both PM's `handleDrop` (when cursor\n * is over `.ProseMirror`) and our document-level drop listener (when\n * cursor is in the gutter/margin area but still inside the indicator\n * zone). Returns `true` when a move was dispatched, so callers can\n * decide whether to `preventDefault()` on the source event.\n */\n const performBlockDrop = (clientX: number, clientY: number): boolean => {\n const view = editor.view;\n const state = pluginKey.getState(view.state);\n // Read the source position with a tiered fallback:\n // 1. Plugin state `draggedFrom` - the canonical source. Set via the\n // deferred dispatch in `onDragStart` (Chrome microtask-window\n // workaround) so it MAY still be null on very fast drags where\n // drop fires before the timer has run.\n // 2. Closure-scoped `pendingDraggedFrom` - set SYNCHRONOUSLY in\n // `onDragStart`. Independent of both the deferred dispatch AND of\n // PM's `view.dragging`, which PM's internal drop handler clears\n // BEFORE invoking the plugin `handleDrop` hook (so reading\n // `view.dragging.node.from` here would already see null).\n // 3. `view.dragging.node.from` - last-ditch resort for callers that\n // might fire `drop` directly without ever invoking our\n // `onDragStart` (synthetic e2e events bypass the handle).\n const draggedFrom = state?.draggedFrom\n ?? pendingDraggedFrom\n ?? asDragView(view).dragging?.node?.from\n ?? null;\n if (draggedFrom === null) return false;\n const sourceNode = view.state.doc.nodeAt(draggedFrom);\n if (!sourceNode) return false;\n const placement = computeDropPlacement(view, clientX, clientY, nested, nestThreshold);\n if (!placement) return false;\n const tr = view.state.tr;\n\n if (\n placement.mode === 'nested'\n && placement.targetItemPos !== undefined\n && placement.wrapperPos !== undefined\n ) {\n // Drop-indent path: append source as the last child of the target\n // list item via `insertAsListItemChild`. On schema reject the\n // helper leaves `tr` untouched and returns false; we fall back to\n // the sibling-style move so the user's drag still produces a\n // sensible result.\n const ok = moveBlockAsNestedChild(tr, draggedFrom, placement.wrapperPos, placement.targetItemPos);\n if (ok) {\n view.dispatch(tr.scrollIntoView());\n return true;\n }\n }\n\n const targetNode = view.state.doc.nodeAt(placement.pos);\n const targetEnd = targetNode ? placement.pos + targetNode.nodeSize : placement.pos;\n const targetPos = placement.insertAfter ? targetEnd : placement.pos;\n moveBlock(tr, draggedFrom, targetPos);\n view.dispatch(tr.scrollIntoView());\n return true;\n };\n\n /**\n * Defines the rectangle in which a drop on the editor will succeed.\n * Equals `.dm-editor`'s bounding box extended by `DROP_ZONE_TOL_LEFT`\n * on the left (gutter where the BlockHandle visually sits) and\n * `DROP_ZONE_TOL` on every other edge. See the constant declarations\n * at the top of the file for rationale.\n */\n const isCursorOverDropZone = (clientX: number, clientY: number): boolean => {\n if (!editorEl) return false;\n const rect = editorEl.getBoundingClientRect();\n return clientX >= rect.left - DROP_ZONE_TOL_LEFT\n && clientX <= rect.right + DROP_ZONE_TOL\n && clientY >= rect.top - DROP_ZONE_TOL\n && clientY <= rect.bottom + DROP_ZONE_TOL;\n };\n\n /**\n * Reposition the drop-indicator line at the same target `handleDrop`\n * would land at for these coordinates. Called from the document-level\n * `dragover` listener while a drag is in progress.\n *\n * Hides the indicator when the resolver finds nothing (e.g. cursor\n * outside the editor's content range during a no-op drag-out).\n *\n * Two visual modes:\n *\n * - **Sibling** - solid line at the rect's top OR bottom edge\n * (decided by `insertAfter`), spanning the full block width. The\n * line lives in the gap BETWEEN sibling blocks.\n * - **Nested** - dashed line at the rect's BOTTOM edge, indented to\n * where children render (matching `--dm-block-children-indent`,\n * nominally 24px). Communicates \"this drop becomes a nested child\n * appended at the end\" via `insertAsListItemChild`.\n *\n * The `data-mode` attribute carries the placement mode so theme CSS\n * can swap solid for dashed via `&[data-mode='nested']`.\n */\n const updateDropIndicator = (clientX: number, clientY: number): void => {\n if (!editorEl) return;\n const placement = computeDropPlacement(editor.view, clientX, clientY, nested, nestThreshold);\n if (!placement) {\n indicator.removeAttribute('data-show');\n return;\n }\n const editorRect = editorEl.getBoundingClientRect();\n\n let lineY: number;\n let left: number;\n let width: number;\n if (placement.mode === 'nested') {\n // Indicator sits AT the bottom of the target list item, indented\n // to the children-zone start. `NESTED_INDICATOR_INDENT_PX` mirrors\n // the default `--dm-block-children-indent` CSS variable (1.5rem ≈\n // 24px); custom themes that override the variable can override\n // the indicator indent through the same CSS hook (see theme).\n const indent = NESTED_INDICATOR_INDENT_PX;\n lineY = placement.rect.bottom - editorRect.top;\n left = placement.rect.left - editorRect.left + indent;\n width = Math.max(0, placement.rect.width - indent);\n } else {\n // Sibling line: ABOVE rect when inserting before, BELOW when\n // inserting after. Spans the full resolved block width.\n lineY = (placement.insertAfter ? placement.rect.bottom : placement.rect.top) - editorRect.top;\n left = placement.rect.left - editorRect.left;\n width = placement.rect.width;\n }\n indicator.style.top = `${String(lineY)}px`;\n indicator.style.left = `${String(left)}px`;\n indicator.style.width = `${String(width)}px`;\n indicator.setAttribute('data-show', '');\n indicator.setAttribute('data-mode', placement.mode);\n };\n\n const stopAutoScroll = (): void => {\n resetAutoScroll();\n };\n\n const hideDropIndicator = (): void => {\n indicator.removeAttribute('data-show');\n };\n\n let dragoverAttached = false;\n /** Register document-level dragover + drop listeners for the active\n * drag. Shared by auto-scroll AND drop-indicator AND the\n * gutter-area drop handling so they stay in lockstep without\n * double-listening. */\n const startDragListeners = (): void => {\n if (dragoverAttached) return;\n document.addEventListener('dragover', onDocumentDragover);\n document.addEventListener('drop', onDocumentDrop);\n dragoverAttached = true;\n };\n const stopDragListeners = (): void => {\n if (!dragoverAttached) return;\n document.removeEventListener('dragover', onDocumentDragover);\n document.removeEventListener('drop', onDocumentDrop);\n dragoverAttached = false;\n };\n\n const autoScrollTick = (): void => {\n const target = autoScrollState.target;\n if (target === null) {\n autoScrollState.raf = null;\n return;\n }\n // Dead-man switch: if the browser stopped sending dragover events, the\n // drag is effectively over (some OS/browser combos eat `dragend`).\n // Tear down the same things `onDragEnd` would so we don't leak the\n // document-level listeners or leave a stale drop indicator visible.\n if (autoScrollState.lastAt > 0 && performance.now() - autoScrollState.lastAt > DRAGOVER_SILENCE_MS) {\n stopAutoScroll();\n stopDragListeners();\n hideDropIndicator();\n return;\n }\n if (autoScrollState.lastClientY !== null) {\n // `findScrollableAncestor` only returns bounded elements now, so we\n // measure against the scrollable rect directly. Page-level scroll\n // is handled by the browser's own drag-edge autoscroll (running\n // both would double-scroll and visibly jank).\n const rect = target.getBoundingClientRect();\n const distFromTop = autoScrollState.lastClientY - rect.top;\n const distFromBottom = rect.bottom - autoScrollState.lastClientY;\n let delta = 0;\n if (distFromTop < autoScrollThreshold && distFromTop >= 0) {\n // Ramp: at the edge (dist=0) speed is maxSpeed; at threshold speed is 0.\n delta = -Math.round(autoScrollMaxSpeed * (1 - distFromTop / autoScrollThreshold));\n } else if (distFromBottom < autoScrollThreshold && distFromBottom >= 0) {\n delta = Math.round(autoScrollMaxSpeed * (1 - distFromBottom / autoScrollThreshold));\n }\n if (delta !== 0) {\n target.scrollBy(0, delta);\n }\n }\n autoScrollState.raf = requestAnimationFrame(autoScrollTick);\n };\n\n const startAutoScroll = (): void => {\n if (!autoScroll) return;\n if (!editorEl) return;\n const target = findScrollableAncestor(editorEl);\n if (!target) return;\n autoScrollState.target = target;\n autoScrollState.lastClientY = null;\n autoScrollState.lastAt = performance.now();\n autoScrollState.raf = requestAnimationFrame(autoScrollTick);\n };\n\n const onDragStart = (event: DragEvent): void => {\n if (disableDrag || !editor.isEditable) {\n event.preventDefault();\n return;\n }\n const state = pluginKey.getState(editor.view.state);\n const pos = state?.hoveredPos ?? null;\n if (pos === null) {\n event.preventDefault();\n return;\n }\n // Capture source pos SYNCHRONOUSLY for `performBlockDrop`, which needs\n // it before the deferred plugin-state commit (setTimeout(0) below) and\n // works even after PM has cleared `view.dragging` in its drop handler.\n pendingDraggedFrom = pos;\n const node = editor.view.state.doc.nodeAt(pos);\n if (!node) {\n event.preventDefault();\n return;\n }\n\n const sourceEnd = pos + node.nodeSize;\n const slice = editor.view.state.doc.slice(pos, sourceEnd);\n const nodeSelection = NodeSelection.create(editor.view.state.doc, pos);\n\n // Set the drag preview BEFORE any PM dispatch: the browser only honours\n // `setDragImage` during the initial dragstart tick. If we dispatch a\n // transaction first, PM re-renders and the nodeDOM we captured may be\n // replaced before we set the image.\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n // `text/plain` fallback - Firefox cancels the drag if no data is set.\n event.dataTransfer.setData('text/plain', node.textContent);\n const dom = editor.view.nodeDOM(pos);\n if (dom instanceof HTMLElement) {\n // Build a styled, off-screen clone as the drag preview. Passing\n // the live DOM to setDragImage captures ambient transforms, clip,\n // and scroll offsets from ancestors - the clone is always crisp.\n const ghost = createDragGhost(dom);\n dragPreview = ghost.wrapper;\n event.dataTransfer.setDragImage(ghost.wrapper, 10, 10);\n }\n }\n\n // Inform ProseMirror that a drag is in progress. Including `node` is\n // critical: PM's built-in drop handler deletes the source using this\n // NodeSelection rather than the current view selection, which may\n // shift unexpectedly mid-drag. Without it, the block occasionally\n // survives the drop (the classic \"phantom source\" bug).\n //\n // This assignment is sync-only and doesn't mutate the DOM; it's safe\n // to do inside the dragstart tick.\n asDragView(editor.view).dragging = {\n slice,\n move: true,\n node: nodeSelection,\n };\n\n // CRITICAL - do not move this work back into the sync dragstart tick.\n //\n // Chrome's HTML5 drag machinery commits the drag in the microtask\n // immediately after the `dragstart` handler returns. If the drag\n // source's DOM mutates in any way between dragstart and that commit,\n // Chrome aborts the drag and fires `dragend` INSTANTLY - the user\n // sees \"click and hold does absolutely nothing\" (crbug/168544,\n // react-dnd #1085).\n //\n // Concrete failure we observed: dispatching\n // `setSelection(NodeSelection) + setMeta(draggedFrom)` synchronously\n // caused PM to add the `.ProseMirror-selectednode` class to the\n // dragged block's DOM. That class mutation was enough for Chrome\n // to kill the drag before a single `drag` or `dragover` event fired.\n //\n // Deferring to `setTimeout(..., 0)` runs after the browser has\n // already committed; the subsequent mutations are safe.\n //\n // Skip the dispatch entirely if the drag has already ended by the\n // time this fires - happens on extremely fast drags where dragstart\n // → drop → dragend all complete in a single JS task before the timer\n // gets a chance to run. `onDragEnd` clears `pendingDraggedFrom` to\n // null, so we use that as the \"is drag still alive?\" signal. Without\n // this guard, the post-drag dispatch would attempt to apply a stale\n // `nodeSelection` against a doc whose positions changed during the\n // already-completed drop - PM throws \"Selection passed to\n // setSelection must point at the current document\".\n window.setTimeout(() => {\n if (pendingDraggedFrom === null) return;\n editor.view.dispatch(\n editor.view.state.tr\n .setSelection(nodeSelection)\n .setMeta(pluginKey, { draggedFrom: pos }),\n );\n editorEl?.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n hide();\n }, 0);\n\n // Begin tracking dragover Y and ramping scroll as the cursor nears\n // viewport edges. No-op when `autoScroll: false` or no scroll ancestor.\n startAutoScroll();\n // The shared document-level dragover listener powers BOTH auto-scroll\n // and the drop-indicator. Attached once per drag, removed in dragend.\n startDragListeners();\n\n // Theme hides native `.prosemirror-dropcursor-*` while this class is set.\n if (dropIndicator) editorEl?.classList.add('dm-block-handle-dragging');\n };\n\n const teardownDragPreview = (): void => {\n if (dragPreview) {\n dragPreview.remove();\n dragPreview = null;\n }\n };\n\n const onDragEnd = (): void => {\n asDragView(editor.view).dragging = null;\n setDraggedFrom(editor.view, null);\n pendingDraggedFrom = null;\n stopAutoScroll();\n stopDragListeners();\n hideDropIndicator();\n teardownDragPreview();\n releaseDragPress();\n editorEl?.classList.remove('dm-block-handle-dragging');\n };\n\n return new Plugin<BlockHandlePluginState>({\n key: pluginKey,\n\n state: {\n init: (): BlockHandlePluginState => ({ hoveredPos: null, draggedFrom: null }),\n apply(tr, prev): BlockHandlePluginState {\n const meta = tr.getMeta(pluginKey) as Partial<BlockHandlePluginState> | undefined;\n let next = prev;\n if (meta) {\n if ('hoveredPos' in meta) {\n next = { ...next, hoveredPos: meta.hoveredPos ?? null };\n }\n if ('draggedFrom' in meta) {\n next = { ...next, draggedFrom: meta.draggedFrom ?? null };\n }\n }\n // Map positions through doc changes so collaborative / programmatic\n // transactions that happen while hovering or dragging don't leave\n // us pointing at the wrong block. Use assoc=1 (forward bias) so\n // `setNodeMarkup` on the hovered block - which replaces the node\n // with the same type but new attrs - does NOT treat the left\n // boundary as deleted. Without the forward bias, BlockColor's\n // swatch click would wipe `hoveredPos`, causing the next click\n // on the handle to bail silently.\n if (tr.docChanged) {\n if (next.hoveredPos !== null) {\n const mapped = tr.mapping.mapResult(next.hoveredPos, 1);\n next = { ...next, hoveredPos: mapped.deleted ? null : mapped.pos };\n }\n if (next.draggedFrom !== null) {\n const mapped = tr.mapping.mapResult(next.draggedFrom, 1);\n next = { ...next, draggedFrom: mapped.deleted ? null : mapped.pos };\n }\n }\n return next;\n },\n },\n\n props: {\n // Custom drop handler - gives Notion-like \"above-mid → insert before,\n // below-mid → insert after\" block-level semantics instead of PM's\n // default `posAtCoords + dropPoint` which for short paragraphs\n // rounds to an arbitrary neighbour boundary and surprises users.\n // The `moveBlock` helper handles the delete+insert + position\n // adjustment so the block keeps its attrs (UniqueID, colors) and\n // the doc ends up in a predictable state.\n handleDrop(_view, event, _slice, moved): boolean {\n if (!moved) return false;\n // Delegates to the shared `performBlockDrop`, which is also used\n // by the document-level drop listener so the same move logic runs\n // whether the drop fired on `.ProseMirror` (this path) or on\n // surrounding chrome inside our indicator zone (doc listener).\n if (performBlockDrop(event.clientX, event.clientY)) {\n event.preventDefault();\n return true;\n }\n // Source node missing, no resolved placement - still consume\n // the event so PM doesn't fall back to its default drop logic.\n event.preventDefault();\n return true;\n },\n },\n\n view: (editorView) => {\n editorEl = editorView.dom.closest('.dm-editor');\n if (!editorEl) {\n // No `.dm-editor` container → plugin inert.\n return { destroy: () => { /* noop */ } };\n }\n\n editorEl.classList.add('dm-editor--has-block-handle');\n editorEl.appendChild(root);\n if (dropIndicator) {\n editorEl.appendChild(indicator);\n }\n hide();\n hideDropIndicator();\n\n // Hover detection lives on `.dm-editor`'s parent (typically the page\n // wrapper, e.g. `.notion-page`'s framework-host child) so the listener\n // also catches mouse movement in the side gutter - the area where the\n // BlockHandle visually lives when the editor is centered narrower than\n // the page. `resolveBlockAtCoords` falls back to a Y-range walk when\n // the cursor's X is outside `.ProseMirror`, so the block under the\n // cursor still resolves correctly.\n hoverEl = editorEl.parentElement ?? editorEl;\n hoverEl.addEventListener('mousemove', onMouseMove);\n hoverEl.addEventListener('mouseleave', onMouseLeave);\n hoverEl.addEventListener('mouseenter', onMouseEnter);\n editorEl.addEventListener('dm:dismiss-overlays', onDismissOverlays);\n\n plusBtn.addEventListener('mousedown', onPlusBtnMouseDown);\n plusBtn.addEventListener('click', onPlusClick);\n // dragBtn mousedown is a no-preventDefault listener - we rely on\n // the browser's native drag initiation (`draggable=\"true\"`) and\n // only use mousedown to set a hover-freeze lock so the handle\n // doesn't slide away before the drag threshold is crossed.\n dragBtn.addEventListener('mousedown', onDragBtnMouseDown);\n // (mouseup is attached lazily inside `onDragBtnMouseDown` as a\n // one-shot - see its comment for the click-vs-drag rationale.)\n dragBtn.addEventListener('click', onDragBtnClick);\n dragBtn.addEventListener('dragstart', onDragStart);\n dragBtn.addEventListener('dragend', onDragEnd);\n\n return {\n destroy: () => {\n clearHideTimer();\n // If the editor is destroyed mid-drag, stop the RAF loop and\n // drop the document-level dragover listener immediately.\n stopAutoScroll();\n stopDragListeners();\n hideDropIndicator();\n indicator.remove();\n teardownDragPreview();\n if (hoverRaf !== null) {\n cancelAnimationFrame(hoverRaf);\n hoverRaf = null;\n }\n hoverEl?.removeEventListener('mousemove', onMouseMove);\n hoverEl?.removeEventListener('mouseleave', onMouseLeave);\n hoverEl?.removeEventListener('mouseenter', onMouseEnter);\n editorEl?.removeEventListener('dm:dismiss-overlays', onDismissOverlays);\n plusBtn.removeEventListener('mousedown', onPlusBtnMouseDown);\n plusBtn.removeEventListener('click', onPlusClick);\n dragBtn.removeEventListener('mousedown', onDragBtnMouseDown);\n document.removeEventListener('mouseup', releaseDragPress);\n dragBtn.removeEventListener('click', onDragBtnClick);\n dragBtn.removeEventListener('dragstart', onDragStart);\n dragBtn.removeEventListener('dragend', onDragEnd);\n editorEl?.classList.remove('dm-editor--has-block-handle');\n editorEl?.classList.remove('dm-block-handle-dragging');\n root.remove();\n editorEl = null;\n hoverEl = null;\n },\n };\n },\n });\n}\n\nexport const BlockHandle = Extension.create<BlockHandleOptions>({\n name: 'blockHandle',\n\n addOptions() {\n return {\n hideDelay: 200,\n disableDrag: false,\n autoScroll: true,\n autoScrollThreshold: 48,\n autoScrollMaxSpeed: 18,\n nested: false,\n dropIndicator: true,\n nestThreshold: DEFAULT_NEST_THRESHOLD,\n };\n },\n\n addProseMirrorPlugins() {\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n return [\n createBlockHandlePlugin({\n pluginKey: blockHandlePluginKey,\n editor,\n hideDelay: this.options.hideDelay ?? 200,\n disableDrag: this.options.disableDrag ?? false,\n autoScroll: this.options.autoScroll ?? true,\n autoScrollThreshold: this.options.autoScrollThreshold ?? 48,\n autoScrollMaxSpeed: this.options.autoScrollMaxSpeed ?? 18,\n nested: resolveNestedConfig(this.options.nested),\n dropIndicator: this.options.dropIndicator ?? true,\n nestThreshold: this.options.nestThreshold ?? DEFAULT_NEST_THRESHOLD,\n }),\n ];\n },\n});\n\n/**\n * Normalises the user-facing `nested` option (boolean | config object)\n * into the resolver-friendly `NestedResolution`:\n *\n * - `false` / `undefined` → top-level-only (mode A).\n * - `true` → default list (list item, task item), Notion-style (mode B).\n * - object → explicit config; defaults fill in for missing fields.\n */\nexport function resolveNestedConfig(nested: BlockHandleOptions['nested']): NestedResolution {\n if (nested === true) {\n return {\n allowedNodes: [...DEFAULT_NESTED_NODES],\n allowedContainers: [],\n gutterBias: null,\n matchers: [...DEFAULT_BLOCK_MATCHERS],\n };\n }\n if (nested && typeof nested === 'object') {\n const allowedNodes = nested.allowedNodes ?? DEFAULT_NESTED_NODES;\n if (allowedNodes.length === 0) {\n return { allowedNodes: [], allowedContainers: [], gutterBias: null, matchers: [] };\n }\n const useDefaults = nested.defaultMatchers ?? true;\n const matchers: BlockMatcher[] = [];\n if (useDefaults) matchers.push(...DEFAULT_BLOCK_MATCHERS);\n if (nested.matchers) matchers.push(...nested.matchers);\n return {\n allowedNodes: [...allowedNodes],\n allowedContainers: nested.allowedContainers ? [...nested.allowedContainers] : [],\n gutterBias: resolveGutterBias(nested.promoteOnEdge),\n matchers,\n };\n }\n return { allowedNodes: [], allowedContainers: [], gutterBias: null, matchers: [] };\n}\n","/**\n * `Mod-Shift-ArrowUp` / `Mod-Shift-ArrowDown` move the top-level block\n * containing the selection. Accessibility companion to BlockHandle drag.\n * Shares `moveBlock` so position math and self-move rejection match.\n */\nimport { Extension } from '@domternal/core';\nimport type { Editor } from '@domternal/core';\nimport { TextSelection } from '@domternal/pm/state';\nimport { findTopLevelBlock } from './helpers/findTopLevelBlock.js';\nimport { moveBlock } from './helpers/moveBlock.js';\n\nexport const KeyboardReorder = Extension.create({\n name: 'keyboardReorder',\n\n addKeyboardShortcuts() {\n const { editor } = this;\n return {\n 'Mod-Shift-ArrowUp': () => moveCurrentBlock(editor as Editor | null, 'up'),\n 'Mod-Shift-ArrowDown': () => moveCurrentBlock(editor as Editor | null, 'down'),\n };\n },\n});\n\n/**\n * Moves the top-level block containing the current selection up or down.\n * Returns `true` when a move happened, `false` otherwise (lets the browser\n * handle the shortcut if we don't consume it).\n */\nfunction moveCurrentBlock(editor: Editor | null, direction: 'up' | 'down'): boolean {\n if (!editor || editor.isDestroyed) return false;\n if (!editor.isEditable) return false;\n const { state, view } = editor;\n const { $from } = state.selection;\n\n const topLevel = findTopLevelBlock(state.doc, $from.pos);\n if (!topLevel) return false;\n\n if (direction === 'up' && topLevel.index === 0) return false;\n if (direction === 'down' && topLevel.index >= state.doc.childCount - 1) return false;\n\n // Relative offset of the selection WITHIN the source block (survives\n // nested containers like list-item/details-content because we work with\n // absolute positions inside the block, not depth-based math).\n const selectionOffsetInBlock = Math.max(\n 0,\n Math.min($from.pos - topLevel.pos, topLevel.node.nodeSize - 1),\n );\n\n let targetPos: number;\n if (direction === 'up') {\n targetPos = state.doc.resolve(topLevel.pos).posAtIndex(topLevel.index - 1, 0);\n } else {\n const nextSibling = state.doc.child(topLevel.index + 1);\n const nextStart = state.doc.resolve(topLevel.pos).posAtIndex(topLevel.index + 1, 0);\n targetPos = nextStart + nextSibling.nodeSize;\n }\n\n const tr = state.tr;\n moveBlock(tr, topLevel.pos, targetPos);\n\n // Restore selection inside the moved block. `moveBlock` deletes then\n // inserts; the block's new start position is `adjustedTarget`, which\n // equals `targetPos` when moving up and `targetPos - source.nodeSize`\n // when moving down.\n const newBlockPos = direction === 'up'\n ? targetPos\n : targetPos - topLevel.node.nodeSize;\n const selectionPos = Math.min(\n newBlockPos + selectionOffsetInBlock,\n Math.max(0, tr.doc.content.size - 1),\n );\n tr.setSelection(TextSelection.near(tr.doc.resolve(selectionPos)));\n\n view.dispatch(tr.scrollIntoView());\n return true;\n}\n","import type { Attrs, NodeType } from '@domternal/pm/model';\nimport type { Transaction } from '@domternal/pm/state';\nimport { TextSelection } from '@domternal/pm/state';\nimport { expandToEmptyWrappers } from './expandToEmptyWrappers.js';\n\n/**\n * Block-level transaction helpers shared between BlockContextMenu commands\n * (Delete, Duplicate, Turn into) and other feature implementations that\n * need to operate on a top-level block.\n *\n * All helpers mutate and return the given transaction (chainable) rather\n * than creating a new one.\n */\n\n/**\n * Removes the block at `blockPos` entirely.\n *\n * Two correctness properties:\n *\n * 1. **Single-child wrapper expansion.** Deleting an inner block whose\n * parent only had that block as its single child would leave PM\n * fitting an empty placeholder (e.g. a `<ul>` with one `<li>` whose\n * paragraph is blank) to satisfy schemas like `bulletList → listItem+`.\n * Worse: in some schemas the fitter unwraps the parent and the\n * user perceives \"delete killed the whole list\". We expand the\n * deletion range outward through such wrappers (same logic as\n * `moveBlock`) so the entire orphan chain is removed atomically.\n *\n * 2. **Doc-empty fallback.** If the expanded range covers the entire\n * doc (e.g. doc had `[ul[only-li]]` and we expand to remove ul +\n * li), the delete would leave an empty doc and violate `block+`\n * on the doc itself. We replace with a fresh paragraph instead so\n * the editor stays usable (matches Notion).\n */\nexport function deleteBlock(tr: Transaction, blockPos: number): Transaction {\n if (blockPos < 0 || blockPos >= tr.doc.content.size) return tr;\n const node = tr.doc.nodeAt(blockPos);\n if (!node) return tr;\n const blockEnd = blockPos + node.nodeSize;\n\n const { from, to } = expandToEmptyWrappers(tr.doc, blockPos, blockEnd);\n\n // After expansion, would the doc be left empty? Compare the expanded\n // range to the doc's full content range - equality means we covered\n // every top-level child via single-child wrapper chains.\n const wouldEmptyDoc = from === 0 && to === tr.doc.content.size;\n if (wouldEmptyDoc) {\n const paragraphType = tr.doc.type.schema.nodes['paragraph'];\n if (!paragraphType) {\n // Schema has no `paragraph` type - bail rather than risk an\n // invalid replacement.\n return tr;\n }\n const replacement = paragraphType.createAndFill();\n if (!replacement) return tr;\n tr.replaceWith(from, to, replacement);\n tr.setSelection(TextSelection.near(tr.doc.resolve(from + 1)));\n return tr;\n }\n\n tr.delete(from, to);\n return tr;\n}\n\n/**\n * Duplicates the block at `blockPos` by inserting a copy immediately after\n * it. The copy preserves content, attrs, AND node-level marks (important\n * for annotation / comment extensions that attach marks to blocks).\n *\n * @param transformAttrs Optional mapper invoked on the source attrs to\n * produce the copy's attrs. Use this to regenerate unique IDs so the\n * duplicate doesn't collide with the original (e.g. `{ ...attrs, id: uuid() }`).\n */\nexport function duplicateBlock(\n tr: Transaction,\n blockPos: number,\n transformAttrs?: (attrs: Attrs) => Attrs,\n): Transaction {\n if (blockPos < 0 || blockPos >= tr.doc.content.size) return tr;\n const node = tr.doc.nodeAt(blockPos);\n if (!node) return tr;\n const blockEnd = blockPos + node.nodeSize;\n const attrs = transformAttrs ? transformAttrs(node.attrs) : node.attrs;\n // `type.create(attrs, content, marks)` preserves all three; plain\n // `node.copy(content)` drops the node's marks which breaks use cases\n // like block-level annotations.\n const copy = node.type.create(attrs, node.content, node.marks);\n tr.insert(blockEnd, copy);\n return tr;\n}\n\n/**\n * Transforms the block at `blockPos` into a different textblock type while\n * preserving its inline content AND any attributes that are valid on the\n * target type. Without this, `setBlockType` would reset global attrs\n * (bgColor, textColor, id, etc.) to their defaults - surprising users who\n * expect \"Turn into\" to keep a block's color and identity.\n *\n * Which attrs carry over is decided by the target type's schema: attrs that\n * exist on BOTH source and target flow through; attrs specific to the\n * source type (e.g., `level` on a Heading when turning into Paragraph) are\n * dropped naturally because the target doesn't declare them.\n *\n * The explicit `attrs` argument (e.g., `{ level: 2 }` for Heading 2) takes\n * precedence over source attrs with the same key.\n *\n * Returns the transaction unchanged if the target type is not a textblock\n * or if the node at `blockPos` can't be transformed.\n */\nexport function turnIntoBlock(\n tr: Transaction,\n blockPos: number,\n targetType: NodeType,\n attrs?: Attrs,\n): Transaction {\n if (blockPos < 0 || blockPos >= tr.doc.content.size) return tr;\n const node = tr.doc.nodeAt(blockPos);\n if (!node) return tr;\n // `setBlockType` requires the target to be a textblock; if it isn't, bail.\n if (!targetType.isTextblock) return tr;\n const blockEnd = blockPos + node.nodeSize;\n\n // Preserve source attrs that the target type also declares, then overlay\n // caller-provided attrs on top. `targetType.spec.attrs` is the schema\n // truth about which attrs are valid on the new type.\n const validKeys = Object.keys(targetType.spec.attrs ?? {});\n const preserved: Record<string, unknown> = {};\n const sourceAttrs = node.attrs as Record<string, unknown>;\n for (const key of validKeys) {\n if (key in sourceAttrs) preserved[key] = sourceAttrs[key];\n }\n const mergedAttrs = attrs ? { ...preserved, ...attrs } : preserved;\n\n tr.setBlockType(blockPos, blockEnd, targetType, mergedAttrs);\n return tr;\n}\n","import { TextSelection } from '@domternal/pm/state';\nimport type { Editor } from '@domternal/core';\n\n/**\n * Editor commands the menu can route to for wrapper-style \"Turn into\".\n * Each maps to a command from the corresponding node extension.\n */\nexport type WrapperCommand =\n | 'toggleBulletList'\n | 'toggleOrderedList'\n | 'toggleTaskList'\n | 'toggleBlockquote';\n\n/**\n * Wrap-style \"Turn into\" for non-textblock targets (lists, blockquote).\n *\n * The textblock targets (paragraph, heading, codeBlock) are handled by\n * `turnIntoBlock` via `setBlockType`. Wrappers can't go through that\n * path - the inner block stays put, only its parent changes. So this\n * helper:\n *\n * 1. (Optionally) downgrades the source block to paragraph. ListItem\n * and TaskItem both declare `content: 'paragraph block*'`, meaning\n * the FIRST child of a list item must be a paragraph. A bare\n * heading or codeBlock would be rejected by the schema during the\n * wrap step. Blockquote has `content: 'block+'` and accepts any\n * block, so step-down only applies to list targets.\n * 2. Moves the selection into the (now-paragraph) block.\n * 3. Dispatches the wrapper command. `toggleList` / `toggleBlockquote`\n * operate on `state.selection`, so the selection-set must land\n * before the command runs.\n *\n * Note: the step-down dispatch and the wrapper command produce two\n * undo steps. Composing them into a single transaction would require\n * re-implementing the toggleList Command's body inline; the two-step\n * undo is an acceptable tradeoff for the (rare) heading/codeBlock →\n * list path.\n */\nexport function turnIntoWrapper(\n editor: Editor,\n blockPos: number,\n command: WrapperCommand,\n): boolean {\n const { state } = editor.view;\n if (blockPos < 0 || blockPos >= state.doc.content.size) return false;\n const node = state.doc.nodeAt(blockPos);\n if (!node?.type.isTextblock) return false;\n\n const isListTarget = command !== 'toggleBlockquote';\n const needsStepDown = isListTarget && node.type.name !== 'paragraph';\n\n const tr = state.tr;\n if (needsStepDown) {\n const paragraphType = state.schema.nodes['paragraph'];\n if (!paragraphType) return false;\n tr.setBlockType(blockPos, blockPos + node.nodeSize, paragraphType);\n }\n // blockPos points at the OPENING token of the block; +1 lands inside\n // its inline content (or at the empty cursor position for an empty\n // textblock).\n tr.setSelection(TextSelection.create(tr.doc, blockPos + 1));\n editor.view.dispatch(tr);\n\n // Dispatch the wrapper command via the editor's commands map. The\n // map is typed `Record<string, (...) => boolean>` so switch on the\n // discriminant to keep type-safety without a wide cast.\n switch (command) {\n case 'toggleBulletList':\n return editor.commands.toggleBulletList();\n case 'toggleOrderedList':\n return editor.commands.toggleOrderedList();\n case 'toggleTaskList':\n return editor.commands.toggleTaskList();\n case 'toggleBlockquote':\n return editor.commands.toggleBlockquote();\n }\n}\n","/**\n * BlockContextMenu Extension\n *\n * Popup menu that opens when the user clicks the BlockHandle `⋮⋮` drag\n * handle without dragging. Offers block-level operations for the target:\n *\n * - **Delete** - remove the block\n * - **Duplicate** - insert an identical copy below\n * - **Turn into** - change the block type (paragraph, heading, quote, etc.)\n *\n * Triggered by the `dm:block-context-menu-open` custom event dispatched\n * from BlockHandle; payload carries `{ blockPos, anchorElement }`.\n *\n * Implementation mirrors FloatingMenu / SlashCommand styling conventions\n * so theming is consistent: `role=\"menu\"` container, `role=\"menuitem\"`\n * buttons, `data-show` for visibility, positioned via `positionFloatingOnce`.\n */\nimport { Extension, defaultIcons, positionFloatingOnce, stripInlineColorConflicts, writeToClipboard } from '@domternal/core';\nimport type { Editor } from '@domternal/core';\nimport { Plugin, PluginKey } from '@domternal/pm/state';\nimport type { Transaction } from '@domternal/pm/state';\nimport type { Attrs } from '@domternal/pm/model';\nimport { Decoration, DecorationSet } from '@domternal/pm/view';\nimport {\n deleteBlock,\n duplicateBlock,\n turnIntoBlock,\n} from './helpers/blockOperations.js';\nimport { turnIntoWrapper, type WrapperCommand } from './helpers/turnIntoWrapper.js';\n\n/**\n * Shape of the `uniqueID` extension's options. We only read the two fields\n * we care about; duplicating the full `UniqueIDOptions` type here avoids\n * importing it from core (which would couple an otherwise-optional feature).\n */\ninterface UniqueIDOptionsShape {\n attributeName?: string;\n generateID?: () => string;\n}\n\n/**\n * Same pattern for `blockColor` - we peek at the palette + types list but\n * don't import `BlockColorOptions` directly because the Colors UI degrades\n * gracefully when the extension isn't loaded.\n */\ninterface BlockColorOptionsShape {\n types?: string[];\n bgColors?: string[];\n textColors?: string[];\n}\n\n/**\n * `props.decorations` reads `activeBlockPos` and applies the\n * `dm-block-context-active` class via a PM Decoration. Decoration\n * survives view rerenders that other transactions trigger (e.g.\n * UniqueID stamping `id` via setNodeMarkup); inline classList\n * mutation does not.\n */\nexport interface BlockContextMenuPluginState {\n activeBlockPos: number | null;\n}\n\nexport const blockContextMenuPluginKey = new PluginKey<BlockContextMenuPluginState>('blockContextMenu');\n\n/**\n * A target type the user can convert the current block into via the\n * \"Turn into\" submenu.\n */\nexport interface TurnIntoTarget {\n /** Display label, e.g. \"Heading 1\". */\n label: string;\n /** Icon key resolved against `defaultIcons`. */\n icon: string;\n /** Schema node name, e.g. \"heading\", \"paragraph\", \"blockquote\". */\n nodeType: string;\n /** Optional node attributes (e.g. `{ level: 1 }` for Heading 1). */\n attrs?: Attrs;\n /**\n * Editor command to invoke for non-textblock (wrapper) targets like\n * lists and blockquote. When set, runTurnInto routes through\n * `turnIntoWrapper` which sets selection then dispatches the\n * command, instead of calling `setBlockType`. Leave undefined for\n * textblock targets (paragraph, heading, codeBlock).\n */\n command?: WrapperCommand;\n}\n\nconst DEFAULT_TURN_INTO: TurnIntoTarget[] = [\n { label: 'Paragraph', icon: 'textT', nodeType: 'paragraph' },\n { label: 'Heading 1', icon: 'textHOne', nodeType: 'heading', attrs: { level: 1 } },\n { label: 'Heading 2', icon: 'textHTwo', nodeType: 'heading', attrs: { level: 2 } },\n { label: 'Heading 3', icon: 'textHThree', nodeType: 'heading', attrs: { level: 3 } },\n { label: 'Bullet list', icon: 'listBullets', nodeType: 'bulletList', command: 'toggleBulletList' },\n { label: 'Ordered list', icon: 'listNumbers', nodeType: 'orderedList', command: 'toggleOrderedList' },\n { label: 'To-do list', icon: 'listChecks', nodeType: 'taskList', command: 'toggleTaskList' },\n { label: 'Quote', icon: 'quotes', nodeType: 'blockquote', command: 'toggleBlockquote' },\n { label: 'Code block', icon: 'codeBlock', nodeType: 'codeBlock' },\n];\n\nexport interface BlockContextMenuOptions {\n /**\n * Show the \"Turn into\" section of the menu. Disable to limit operations\n * to Delete + Duplicate.\n * @default true\n */\n turnIntoEnabled?: boolean;\n /**\n * Block types offered by \"Turn into\". Override to curate the list or\n * add project-specific block types.\n * @default DEFAULT_TURN_INTO\n */\n turnIntoTargets?: TurnIntoTarget[];\n /**\n * Show \"Copy link\" when the target block has an id attribute AND the\n * `UniqueID` extension is loaded in the editor. Without UniqueID this\n * option has no effect - the item never appears regardless of value.\n * @default true\n */\n copyLinkEnabled?: boolean;\n /**\n * Build the URL written to the clipboard when the user clicks \"Copy link\".\n * Receives the block's id and the editor; returns a full URL. Default\n * appends `#<id>` to the current pathname+search, which works for static\n * pages. Frameworks with client-side routing should provide a callback\n * matching their URL scheme.\n */\n onCopyLink?: (blockId: string, editor: Editor) => string;\n /**\n * Show the Colors section (text color + background) when the `BlockColor`\n * extension is loaded and the target block is in its `types` list.\n * Without BlockColor this option has no effect.\n * @default true\n */\n blockColorEnabled?: boolean;\n}\n\nexport interface CreateBlockContextMenuPluginOptions {\n pluginKey: PluginKey<BlockContextMenuPluginState>;\n editor: Editor;\n turnIntoEnabled: boolean;\n turnIntoTargets: TurnIntoTarget[];\n copyLinkEnabled: boolean;\n onCopyLink: (blockId: string, editor: Editor) => string;\n blockColorEnabled: boolean;\n}\n\n/**\n * Default URL template for \"Copy link to block\" - appends `#<blockId>` to\n * the current pathname+search. Works for static sites; SPA hosts should\n * override via the `onCopyLink` option.\n */\nfunction defaultCopyLinkUrl(blockId: string): string {\n if (typeof window === 'undefined') return `#${blockId}`;\n const { pathname, search } = window.location;\n return `${pathname}${search}#${blockId}`;\n}\n\n/**\n * Shape of the custom event dispatched by BlockHandle when the user\n * clicks the drag handle without starting a drag.\n */\ninterface BlockContextMenuOpenDetail {\n blockPos: number;\n anchorElement: HTMLElement;\n}\n\n/**\n * Derive a selector that can re-locate an anchor button if its DOM identity\n * changes (e.g. the vanilla bubble menu rebuilding its trailing buttons via\n * `replaceChildren`). Returns `null` for anchors we cannot reliably re-resolve\n * (e.g. the BlockHandle drag button, which lives outside any bubble menu and\n * is keyed by absolute position, not class).\n */\nfunction matchingSelectorFor(anchor: HTMLElement): string | null {\n const ariaLabel = anchor.getAttribute('aria-label');\n if (ariaLabel) {\n const escaped = ariaLabel.replace(/\"/g, '\\\\\"');\n return `button[aria-label=\"${escaped}\"]`;\n }\n return null;\n}\n\n/**\n * Creates the BlockContextMenu ProseMirror plugin. Builds an absolutely\n * positioned popup DOM, listens for `dm:block-context-menu-open` on the\n * `.dm-editor` container, and executes block operations via the shared\n * helpers in `helpers/blockOperations.ts`.\n */\nexport function createBlockContextMenuPlugin(\n options: CreateBlockContextMenuPluginOptions,\n): Plugin {\n const { pluginKey, editor, turnIntoEnabled, turnIntoTargets, copyLinkEnabled, onCopyLink, blockColorEnabled } = options;\n\n // Cache optional-extension detection once at plugin construction. With\n // the standard `Extension.configure(...)` setup the extension list AND\n // its options are immutable for the editor's lifetime, so there's no\n // need to re-check on every menu open. `null` for each means the paired\n // extension isn't loaded (and the matching menu section is hidden).\n //\n // CONSTRAINT: hosts that re-register `uniqueID` / `blockColor` at\n // runtime (or live-mutate their options) won't see the change reflected\n // here - the menu would still read the values it captured at construction.\n // We don't support that flow today; if it becomes a need, move these\n // reads inside `renderItems()` so each open re-resolves fresh state.\n const uniqueIDExt = editor.extensionManager.extensions.find((ext) => ext.name === 'uniqueID');\n const uniqueIDAttrName: string | null = uniqueIDExt\n ? ((uniqueIDExt.options as UniqueIDOptionsShape).attributeName ?? 'id')\n : null;\n const uniqueIDGenerate: (() => string) | null = uniqueIDExt\n ? ((uniqueIDExt.options as UniqueIDOptionsShape).generateID ?? null)\n : null;\n\n const blockColorExt = editor.extensionManager.extensions.find((ext) => ext.name === 'blockColor');\n const blockColorOpts = blockColorExt\n ? (blockColorExt.options as BlockColorOptionsShape)\n : null;\n const blockColorTypes: string[] | null = blockColorOpts?.types ?? null;\n const blockBgPalette: string[] = blockColorOpts?.bgColors ?? [];\n const blockTextPalette: string[] = blockColorOpts?.textColors ?? [];\n\n // --- Build popup DOM once.\n const root = document.createElement('div');\n root.className = 'dm-block-context-menu';\n root.setAttribute('role', 'menu');\n root.setAttribute('aria-label', 'Block options');\n root.setAttribute('data-dm-editor-ui', '');\n\n let editorEl: HTMLElement | null = null;\n let cleanupFloating: (() => void) | null = null;\n let currentBlockPos: number | null = null;\n // Roving tabindex: which menuitem is currently focused. Initialised to 0\n // because the menu auto-focuses the first item on open.\n let focusedIndex = 0;\n let menuItemButtons: HTMLButtonElement[] = [];\n // Tracks the rAF id scheduled by `open()` for the initial focus so we\n // can cancel it if the menu closes before the frame fires (otherwise the\n // callback races with teardown and may focus a stale button).\n let initialFocusRaf: number | null = null;\n // Idempotency guard for the document-level wheel/touchmove listeners\n // that block page scroll while the menu is open.\n let scrollLocked = false;\n\n const isOpen = (): boolean => root.hasAttribute('data-show');\n\n /**\n * Suppresses page scroll while the menu is open. Native scroll\n * INSIDE the menu is allowed only when the menu actually has\n * scrollable overflow; without that check a short menu would let\n * wheel events bubble through and scroll the page.\n * `overscroll-behavior: contain` in the theme stops chaining at\n * the menu's scroll edges.\n */\n const onBlockScroll = (event: Event): void => {\n const target = event.target;\n if (target instanceof Node && root.contains(target)) {\n const hasOverflow = root.scrollHeight > root.clientHeight;\n if (hasOverflow) return;\n }\n event.preventDefault();\n };\n\n const lockScroll = (): void => {\n if (scrollLocked) return;\n scrollLocked = true;\n // `passive: false` is required so preventDefault() takes effect:\n // browsers default wheel/touchmove to passive for scroll perf.\n document.addEventListener('wheel', onBlockScroll, { passive: false });\n document.addEventListener('touchmove', onBlockScroll, { passive: false });\n };\n\n const unlockScroll = (): void => {\n if (!scrollLocked) return;\n scrollLocked = false;\n document.removeEventListener('wheel', onBlockScroll);\n document.removeEventListener('touchmove', onBlockScroll);\n };\n\n const hide = (): void => {\n if (initialFocusRaf !== null) {\n cancelAnimationFrame(initialFocusRaf);\n initialFocusRaf = null;\n }\n cleanupFloating?.();\n cleanupFloating = null;\n unlockScroll();\n editorEl?.removeAttribute('data-block-context-menu-open');\n // `editor.view` is undefined during the first `hide()` triggered\n // by plugin init - skip the dispatch in that case.\n const view = editor.view as typeof editor.view | undefined;\n if (view) {\n const tr = view.state.tr.setMeta(pluginKey, { activeBlockPos: null });\n tr.setMeta('addToHistory', false);\n view.dispatch(tr);\n }\n root.removeAttribute('data-show');\n currentBlockPos = null;\n menuItemButtons = [];\n focusedIndex = 0;\n };\n\n const focusItem = (index: number): void => {\n if (menuItemButtons.length === 0) return;\n const clamped = Math.max(0, Math.min(index, menuItemButtons.length - 1));\n // Roving tabindex: only the currently-focused item is in the Tab order.\n // Without this, Tab-away-and-back lands on the wrong item (WAI-ARIA menu pattern).\n for (let i = 0; i < menuItemButtons.length; i++) {\n const btn = menuItemButtons[i];\n if (btn) btn.tabIndex = i === clamped ? 0 : -1;\n }\n focusedIndex = clamped;\n menuItemButtons[clamped]?.focus();\n };\n\n /**\n * Executes a block operation, then closes the menu and returns focus to\n * the editor so the user can continue typing.\n */\n const runAndClose = (apply: (tr: Transaction) => void): void => {\n const tr = editor.view.state.tr;\n try {\n apply(tr);\n editor.view.dispatch(tr.scrollIntoView());\n } finally {\n hide();\n editor.view.focus();\n }\n };\n\n const runDelete = (): void => {\n if (currentBlockPos === null) return;\n const pos = currentBlockPos;\n runAndClose((tr) => { deleteBlock(tr, pos); });\n };\n\n const runDuplicate = (): void => {\n if (currentBlockPos === null) return;\n const pos = currentBlockPos;\n // When UniqueID is loaded, regenerate the id on the copy so it doesn't\n // collide with the source. All other attrs (colors, levels, etc.) are\n // preserved by spreading.\n const transformAttrs = uniqueIDAttrName && uniqueIDGenerate\n ? (attrs: Attrs): Attrs => ({ ...attrs, [uniqueIDAttrName]: uniqueIDGenerate() })\n : undefined;\n runAndClose((tr) => { duplicateBlock(tr, pos, transformAttrs); });\n };\n\n const runCopyLink = (blockId: string): void => {\n const url = onCopyLink(blockId, editor);\n void writeToClipboard(url).then((ok: boolean) => {\n // Semantic event split: `success` fires only when the write actually\n // succeeded, `error` fires otherwise. Host apps listen to one or both.\n // Detail carries the URL and id so the host can format its own message.\n const name = ok ? 'dm:copy-link-success' : 'dm:copy-link-error';\n editorEl?.dispatchEvent(new CustomEvent(name, {\n bubbles: false,\n detail: { url, blockId },\n }));\n });\n hide();\n editor.view.focus();\n };\n\n const runTurnInto = (target: TurnIntoTarget): void => {\n if (currentBlockPos === null) return;\n const sourceNode = editor.view.state.doc.nodeAt(currentBlockPos);\n if (!sourceNode) return;\n\n // When the targeted block is a wrapper (listItem / taskItem /\n // blockquote), descend to its inner first textblock so the wrapper\n // command operates on a valid textblock source. The filter in\n // renderItems guarantees we only reach here for wrapper targets\n // when source is a wrapper - textblock targets on wrapper sources\n // are filtered out upstream.\n const pos = sourceNode.type.isTextblock ? currentBlockPos : currentBlockPos + 1;\n\n // Wrapper targets (lists, blockquote) use the helper which routes\n // through the corresponding editor command. The command dispatches\n // its own transaction (with scrollIntoView), so we only need to\n // close the menu and restore focus afterwards.\n if (target.command) {\n turnIntoWrapper(editor, pos, target.command);\n hide();\n editor.view.focus();\n return;\n }\n // Textblock targets: position-precise setBlockType via the existing\n // pure helper. runAndClose handles dispatch + scrollIntoView + hide.\n const targetType = editor.view.state.schema.nodes[target.nodeType];\n if (!targetType) return;\n runAndClose((tr) => { turnIntoBlock(tr, pos, targetType, target.attrs); });\n };\n\n /**\n * Sets `bgColor` or `textColor` directly on the block at `currentBlockPos`\n * via `setNodeMarkup`. Bypasses the BlockColor command's ancestor walk\n * because the menu already knows which block was targeted. Inline color\n * marks of the same kind inside the block are stripped so the new block\n * tint wins (\"last action wins\"); see `stripInlineColorConflicts`.\n */\n const runSetColor = (attr: 'bgColor' | 'textColor', color: string | null): void => {\n if (currentBlockPos === null) return;\n const pos = currentBlockPos;\n runAndClose((tr) => {\n const n = tr.doc.nodeAt(pos);\n if (!n) return;\n tr.setNodeMarkup(pos, undefined, { ...n.attrs, [attr]: color });\n stripInlineColorConflicts(\n tr,\n editor.view.state,\n pos,\n pos + n.nodeSize,\n attr === 'textColor' ? 'text' : 'bg',\n );\n });\n };\n\n /**\n * Re-renders menu items based on the current target block. Hides \"Turn\n * into\" targets that match the current block's type (no-op conversions)\n * and filters \"Turn into\" entirely when the target type is not a textblock.\n */\n const renderItems = (blockPos: number): void => {\n root.innerHTML = '';\n menuItemButtons = [];\n\n const node = editor.view.state.doc.nodeAt(blockPos);\n if (!node) return;\n\n // --- Primary actions section\n const primaryGroup = document.createElement('div');\n primaryGroup.className = 'dm-block-context-menu-group';\n primaryGroup.setAttribute('role', 'group');\n\n primaryGroup.appendChild(\n makeItem('Delete', 'trash', runDelete),\n );\n if (node.type.name !== 'horizontalRule') {\n primaryGroup.appendChild(\n makeItem('Duplicate', 'copy', runDuplicate),\n );\n }\n // Copy link - only when UniqueID is loaded AND this block has an id attr\n // AND the feature is enabled. Items on paragraphs without an id (legacy\n // content) gracefully skip the item rather than copying an empty hash.\n if (copyLinkEnabled && uniqueIDAttrName) {\n const id = (node.attrs as Record<string, unknown>)[uniqueIDAttrName];\n if (typeof id === 'string' && id.length > 0) {\n primaryGroup.appendChild(\n makeItem('Copy link', 'link', () => { runCopyLink(id); }),\n );\n }\n }\n root.appendChild(primaryGroup);\n\n // --- Colors section (text color + background)\n // Shown only when BlockColor is loaded AND the target block type is in\n // its `types` list. The picker renders two rows of swatches (bg + text)\n // plus a \"clear\" swatch that unsets the attribute.\n if (blockColorEnabled && blockColorTypes?.includes(node.type.name)) {\n const label = document.createElement('div');\n label.className = 'dm-block-context-menu-group-label';\n label.textContent = 'Colors';\n root.appendChild(label);\n\n const currentBg = (node.attrs as Record<string, unknown>)['bgColor'] as string | null;\n const currentText = (node.attrs as Record<string, unknown>)['textColor'] as string | null;\n\n root.appendChild(\n buildSwatchRow(\n 'Text color',\n 'text',\n blockTextPalette,\n currentText,\n (color) => { runSetColor('textColor', color); },\n ),\n );\n root.appendChild(\n buildSwatchRow(\n 'Background',\n 'bg',\n blockBgPalette,\n currentBg,\n (color) => { runSetColor('bgColor', color); },\n ),\n );\n }\n\n // --- Turn into section. Two source modes:\n //\n // A. Textblock source (paragraph, heading, codeBlock): both\n // textblock and wrapper targets are eligible (subject to filter).\n // B. Wrapper source (listItem, taskItem, blockquote whose first\n // child is a textblock): only wrapper targets are eligible,\n // and we descend to the inner textblock for the ancestor walk.\n // Textblock targets would need a lift-then-convert step that\n // is out of scope - they're filtered out.\n //\n // Pure non-textblock atoms (HR) and wrapper-of-wrapper (bulletList\n // whose first child is listItem, not a textblock) hide Turn into\n // entirely - Notion matches this.\n const sourceIsTextblock = node.type.isTextblock;\n const sourceIsWrapper = !sourceIsTextblock && node.firstChild?.isTextblock === true;\n if (turnIntoEnabled && (sourceIsTextblock || sourceIsWrapper)) {\n // For wrapper sources, the ancestor walk starts at the inner\n // textblock (blockPos + 1 = past the wrapper opening token) so\n // it picks up listItem / taskList / blockquote correctly.\n const ancestorPos = sourceIsTextblock ? blockPos : blockPos + 1;\n const $pos = editor.view.state.doc.resolve(ancestorPos);\n const ancestorTypeNames = new Set<string>();\n for (let d = 0; d <= $pos.depth; d++) {\n ancestorTypeNames.add($pos.node(d).type.name);\n }\n\n // listItem / taskItem schema requires their FIRST child to be a\n // paragraph. Calling toggleBlockquote on that inner paragraph\n // would try to make blockquote the first child, which the schema\n // rejects. Hide the Quote target upfront to avoid a clickable-\n // but-no-op item.\n const isListItemFamilySource =\n node.type.name === 'listItem' || node.type.name === 'taskItem';\n\n const eligible = turnIntoTargets.filter((target) => {\n const type = editor.view.state.schema.nodes[target.nodeType];\n if (!type) return false;\n\n // Wrapper target (toggleList / toggleBlockquote). Hide when an\n // ancestor of the same type already wraps the block - Notion-\n // style \"you're already there, no point offering\".\n if (target.command) {\n if (ancestorTypeNames.has(target.nodeType)) return false;\n if (target.command === 'toggleBlockquote' && isListItemFamilySource) return false;\n return true;\n }\n\n // Textblock target. Only valid when source is itself a textblock.\n // Wrapper sources need lift-then-convert (out of scope).\n if (!sourceIsTextblock) return false;\n if (!type.isTextblock) return false;\n // Skip targets identical to the current block (same node type AND\n // matching attrs - e.g. hide \"Heading 1\" when already on H1).\n if (type.name !== node.type.name) return true;\n const targetAttrs = target.attrs;\n if (!targetAttrs) return false;\n const nodeAttrs = node.attrs as Record<string, unknown>;\n for (const k of Object.keys(targetAttrs)) {\n if (nodeAttrs[k] !== (targetAttrs as Record<string, unknown>)[k]) return true;\n }\n return false;\n });\n\n if (eligible.length > 0) {\n const label = document.createElement('div');\n label.className = 'dm-block-context-menu-group-label';\n label.textContent = 'Turn into';\n root.appendChild(label);\n\n const group = document.createElement('div');\n group.className = 'dm-block-context-menu-group';\n group.setAttribute('role', 'group');\n group.setAttribute('aria-label', 'Turn into');\n\n for (const target of eligible) {\n group.appendChild(\n makeItem(target.label, target.icon, () => { runTurnInto(target); }),\n );\n }\n root.appendChild(group);\n }\n }\n };\n\n /**\n * Construct the chrome shared by every menu button (regular item + color\n * swatch): role=menuitem, roving-tabindex registration, mousedown\n * preventDefault (keeps editor focus), click handler.\n */\n const createMenuButton = (config: {\n className: string;\n ariaLabel: string;\n onClick: () => void;\n attributes?: Record<string, string>;\n }): HTMLButtonElement => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = config.className;\n btn.setAttribute('role', 'menuitem');\n btn.setAttribute('aria-label', config.ariaLabel);\n if (config.attributes) {\n for (const [k, v] of Object.entries(config.attributes)) {\n btn.setAttribute(k, v);\n }\n }\n btn.tabIndex = menuItemButtons.length === 0 ? 0 : -1;\n btn.addEventListener('mousedown', (e: MouseEvent) => { e.preventDefault(); });\n btn.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault();\n config.onClick();\n });\n menuItemButtons.push(btn);\n return btn;\n };\n\n /** Helper to construct a menuitem button (icon + label) and register it for nav. */\n const makeItem = (\n label: string,\n iconKey: string,\n onClick: () => void,\n ): HTMLButtonElement => {\n const btn = createMenuButton({\n className: 'dm-block-context-menu-item',\n ariaLabel: label,\n onClick,\n });\n\n // Build DOM safely: icon SVG is trusted (from our own phosphor set), but\n // `label` may come from user-supplied `turnIntoTargets` config - use\n // textContent for any string that could originate outside this package.\n const iconHTML = defaultIcons[iconKey] ?? '';\n const iconSpan = document.createElement('span');\n iconSpan.className = 'dm-block-context-menu-item-icon';\n iconSpan.setAttribute('aria-hidden', 'true');\n iconSpan.innerHTML = iconHTML;\n\n const labelSpan = document.createElement('span');\n labelSpan.className = 'dm-block-context-menu-item-label';\n labelSpan.textContent = label;\n\n btn.appendChild(iconSpan);\n btn.appendChild(labelSpan);\n return btn;\n };\n\n /**\n * Build a single color-picker swatch. `null` color becomes a \"clear\"\n * swatch (unset the attribute). Swatches participate in roving-tabindex\n * keyboard nav alongside menu items.\n */\n const makeSwatch = (\n variant: 'bg' | 'text',\n color: string | null,\n current: string | null,\n onClick: (c: string | null) => void,\n ): HTMLButtonElement => {\n const ariaLabel = color === null\n ? (variant === 'bg' ? 'No background' : 'Default text color')\n : `${variant === 'bg' ? 'Background' : 'Text color'}: ${color}`;\n const isPressed = (current === color || (color === null && !current));\n return createMenuButton({\n className: `dm-block-color-swatch dm-block-color-swatch--${variant}`,\n ariaLabel,\n onClick: () => { onClick(color); },\n attributes: {\n 'data-color': color ?? 'null',\n 'aria-pressed': isPressed ? 'true' : 'false',\n },\n });\n };\n\n /**\n * Compose a labelled swatch row (a strip of color buttons) for either\n * text color or background. The first entry is always a \"clear\" swatch\n * that unsets the attribute.\n */\n const buildSwatchRow = (\n rowLabel: string,\n variant: 'bg' | 'text',\n palette: string[],\n current: string | null,\n onClick: (color: string | null) => void,\n ): HTMLElement => {\n const row = document.createElement('div');\n row.className = 'dm-block-color-row';\n row.setAttribute('role', 'group');\n row.setAttribute('aria-label', rowLabel);\n\n const visuallyHidden = document.createElement('span');\n visuallyHidden.className = 'dm-block-color-row-label';\n visuallyHidden.textContent = rowLabel;\n row.appendChild(visuallyHidden);\n\n row.appendChild(makeSwatch(variant, null, current, onClick));\n for (const c of palette) {\n row.appendChild(makeSwatch(variant, c, current, onClick));\n }\n return row;\n };\n\n /**\n * Opens the menu anchored to `anchorElement`, targeting `blockPos`.\n * Dispatches `dm:dismiss-overlays` first so any other chrome closes.\n *\n * `detail.blockPos` is whatever block the dispatcher (BlockHandle)\n * resolved under the cursor - this includes nested list items when\n * `BlockHandle.nested` is enabled. Using `findTopLevelBlock` here\n * would walk past those and target the wrapping list, which would\n * mean a \"Delete\" click on a single list item nukes the entire list\n * (the user's reported bug).\n */\n const open = (detail: BlockContextMenuOpenDetail): void => {\n if (!editorEl) return;\n\n const node = editor.view.state.doc.nodeAt(detail.blockPos);\n if (!node) return;\n\n currentBlockPos = detail.blockPos;\n renderItems(detail.blockPos);\n if (menuItemButtons.length === 0) return;\n\n // Must set the cross-plugin signal BEFORE the dismiss dispatch\n // so BlockHandle's dismiss listener can distinguish \"menu opening\"\n // from \"another overlay dismissing me\" and keep the drag handle\n // anchored.\n editorEl.setAttribute('data-block-context-menu-open', '');\n editorEl.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n root.setAttribute('data-show', '');\n lockScroll();\n const openTr = editor.view.state.tr.setMeta(pluginKey, { activeBlockPos: detail.blockPos });\n openTr.setMeta('addToHistory', false);\n editor.view.dispatch(openTr);\n\n cleanupFloating?.();\n // Virtual reference: caches the last valid rect and returns it when the\n // anchor element later becomes disconnected. Vanilla bubble menus rebuild\n // their DOM via `replaceChildren()` on every editor transaction, which\n // orphans the anchor we were given; without this caching, `autoUpdate`\n // re-computes against a zero rect and the menu flies to the corner.\n let anchorEl: HTMLElement = detail.anchorElement;\n const bubbleMenuRef = anchorEl.closest<HTMLElement>('.dm-bubble-menu');\n const matchingSelector = matchingSelectorFor(anchorEl);\n let lastRect = anchorEl.getBoundingClientRect();\n const virtualRef: { getBoundingClientRect: () => DOMRect } = {\n getBoundingClientRect: () => {\n if (anchorEl.isConnected) {\n lastRect = anchorEl.getBoundingClientRect();\n return lastRect;\n }\n // Anchor disconnected. Try to find an equivalent in the same bubble\n // menu (where applicable) so the menu tracks live DOM rather than\n // pinning to the now-stale rect.\n if (matchingSelector && bubbleMenuRef?.isConnected) {\n const fresh = bubbleMenuRef.querySelector<HTMLElement>(matchingSelector);\n if (fresh) {\n anchorEl = fresh;\n lastRect = fresh.getBoundingClientRect();\n return lastRect;\n }\n }\n return lastRect;\n },\n };\n cleanupFloating = positionFloatingOnce(virtualRef, root, {\n placement: 'right-start',\n offsetValue: 4,\n });\n\n // Focus first menu item so keyboard users can Arrow through immediately.\n focusedIndex = 0;\n // Wait for layout so the focus call sees the newly visible element.\n // Track the rAF id so `hide()` can cancel it if the menu closes before\n // the frame fires.\n initialFocusRaf = requestAnimationFrame(() => {\n initialFocusRaf = null;\n menuItemButtons[0]?.focus();\n });\n };\n\n // --- Event handlers\n const onOpen = (event: Event): void => {\n // CustomEvent<T> extends Event so the downcast is safe; we widen detail\n // to `T | undefined` to keep the runtime guard for cases where a plain\n // Event was dispatched without detail.\n const detail = (event as CustomEvent<BlockContextMenuOpenDetail | undefined>).detail;\n if (!detail) return;\n open(detail);\n };\n\n const onDismiss = (): void => {\n if (!isOpen()) return;\n hide();\n };\n\n const onClickOutside = (event: Event): void => {\n if (!isOpen()) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (root.contains(target)) return;\n hide();\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n if (!isOpen()) return;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusItem((focusedIndex + 1) % menuItemButtons.length);\n return;\n case 'ArrowUp':\n event.preventDefault();\n focusItem((focusedIndex - 1 + menuItemButtons.length) % menuItemButtons.length);\n return;\n case 'Home':\n event.preventDefault();\n focusItem(0);\n return;\n case 'End':\n event.preventDefault();\n focusItem(menuItemButtons.length - 1);\n return;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n hide();\n editor.view.focus();\n return;\n default:\n return;\n }\n };\n\n return new Plugin<BlockContextMenuPluginState>({\n key: pluginKey,\n state: {\n init: () => ({ activeBlockPos: null }),\n apply(tr, value) {\n const meta = tr.getMeta(pluginKey) as { activeBlockPos?: number | null } | undefined;\n if (meta && 'activeBlockPos' in meta) {\n return { activeBlockPos: meta.activeBlockPos ?? null };\n }\n // Re-map across doc changes so the highlight tracks structural edits.\n if (value.activeBlockPos !== null && tr.docChanged) {\n const mapped = tr.mapping.mapResult(value.activeBlockPos, 1);\n return { activeBlockPos: mapped.deleted ? null : mapped.pos };\n }\n return value;\n },\n },\n props: {\n decorations(state) {\n const plugin = pluginKey.getState(state);\n const activePos = plugin?.activeBlockPos ?? null;\n if (activePos === null) return null;\n const node = state.doc.nodeAt(activePos);\n if (!node) return null;\n return DecorationSet.create(state.doc, [\n Decoration.node(activePos, activePos + node.nodeSize, { class: 'dm-block-context-active' }),\n ]);\n },\n },\n\n view: (editorView) => {\n editorEl = editorView.dom.closest('.dm-editor');\n if (!editorEl) return { destroy: () => { /* noop */ } };\n\n editorEl.appendChild(root);\n hide();\n\n editorEl.addEventListener('dm:block-context-menu-open', onOpen);\n editorEl.addEventListener('dm:dismiss-overlays', onDismiss);\n document.addEventListener('mousedown', onClickOutside, true);\n root.addEventListener('keydown', onKeyDown);\n\n return {\n destroy: () => {\n hide();\n editorEl?.removeEventListener('dm:block-context-menu-open', onOpen);\n editorEl?.removeEventListener('dm:dismiss-overlays', onDismiss);\n document.removeEventListener('mousedown', onClickOutside, true);\n root.removeEventListener('keydown', onKeyDown);\n root.remove();\n editorEl = null;\n },\n };\n },\n });\n}\n\nexport const BlockContextMenu = Extension.create<BlockContextMenuOptions>({\n name: 'blockContextMenu',\n\n addOptions() {\n return {\n turnIntoEnabled: true,\n turnIntoTargets: DEFAULT_TURN_INTO,\n copyLinkEnabled: true,\n onCopyLink: defaultCopyLinkUrl,\n blockColorEnabled: true,\n };\n },\n\n addProseMirrorPlugins() {\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n // `addOptions()` provides defaults, but the public option interface\n // marks each field optional so consumers can pass a partial config.\n // Re-applying defaults here narrows the types back to non-optional\n // for the plugin factory.\n const opts = this.options;\n return [\n createBlockContextMenuPlugin({\n pluginKey: blockContextMenuPluginKey,\n editor,\n turnIntoEnabled: opts.turnIntoEnabled ?? true,\n turnIntoTargets: opts.turnIntoTargets ?? DEFAULT_TURN_INTO,\n copyLinkEnabled: opts.copyLinkEnabled ?? true,\n onCopyLink: opts.onCopyLink ?? defaultCopyLinkUrl,\n blockColorEnabled: opts.blockColorEnabled ?? true,\n }),\n ];\n },\n});\n","/**\n * Default DOM renderer factory for SlashCommand.\n *\n * Returns `{ onStart, onUpdate, onExit, onKeyDown }` callbacks that build\n * and manage a grouped popup anchored at the cursor. Mirrors the\n * Mention/Emoji suggestion renderer pattern so consumers already familiar\n * with those APIs have zero learning curve.\n *\n * The popup DOM reuses the same visual vocabulary as FloatingMenu:\n * `role=\"menu\"` container, `role=\"group\"` sections, `role=\"menuitem\"`\n * buttons with `icon + label + shortcut chip` layout. A dedicated\n * `dm-slash-command-menu` root class scopes SCSS overrides.\n */\nimport {\n defaultIcons,\n groupFloatingMenuItems,\n positionFloatingOnce,\n} from '@domternal/core';\nimport type { FloatingMenuItem } from '@domternal/core';\nimport type { SlashCommandProps, SlashCommandRenderer } from './SlashCommand.js';\n\n// Module-level counter for unique id suffixes - lets us set\n// `aria-activedescendant` on the menu root so screen readers announce the\n// selection as the user arrow-keys through items.\nlet idCounter = 0;\n\nexport function createSlashSuggestionRenderer(): SlashCommandRenderer {\n let root: HTMLDivElement | null = null;\n let cleanupFloating: (() => void) | null = null;\n // Flat list of rendered menuitem buttons, parallel to filtered item list.\n let itemButtons: HTMLButtonElement[] = [];\n let flatItems: FloatingMenuItem[] = [];\n let selectedIndex = 0;\n let currentCommand: SlashCommandProps['command'] | null = null;\n // Flag set during onExit so any pending event that was already queued\n // (e.g. a trailing mousedown+click after the teardown starts) can bail\n // instead of dispatching into a now-destroyed editor.\n let destroyed = false;\n const rendererId = `dm-slash-${String(++idCounter)}`;\n\n const renderPopup = (props: SlashCommandProps): void => {\n if (!root) return;\n root.innerHTML = '';\n itemButtons = [];\n flatItems = [];\n\n if (props.items.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'dm-slash-command-empty';\n // `role=\"status\"` + `aria-live=\"polite\"` makes screen readers\n // announce the filter result change without stealing focus.\n empty.setAttribute('role', 'status');\n empty.setAttribute('aria-live', 'polite');\n empty.textContent = 'No matches';\n root.appendChild(empty);\n return;\n }\n\n const groups = groupFloatingMenuItems(props.items);\n for (const group of groups) {\n if (group.name) {\n const label = document.createElement('div');\n label.className = 'dm-slash-command-group-label';\n label.textContent = group.name;\n root.appendChild(label);\n }\n const groupEl = document.createElement('div');\n groupEl.className = 'dm-slash-command-group';\n groupEl.setAttribute('role', 'group');\n if (group.name) groupEl.setAttribute('aria-label', group.name);\n\n for (const item of group.items) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'dm-slash-command-item';\n btn.setAttribute('role', 'menuitem');\n btn.setAttribute('aria-label', item.label);\n btn.tabIndex = -1;\n // Stable id per-button so the root element can set\n // `aria-activedescendant` to announce the current selection.\n btn.id = `${rendererId}-item-${String(flatItems.length)}`;\n\n // Build DOM safely: only the icon SVG (from our trusted phosphor\n // set) is interpolated as HTML. label / description / shortcut use\n // textContent since FloatingMenuItem fields may come from arbitrary\n // extension authors and could carry unescaped HTML/scripts.\n const iconHTML = item.icon ? (defaultIcons[item.icon] ?? '') : '';\n if (iconHTML) {\n const iconSpan = document.createElement('span');\n iconSpan.className = 'dm-slash-command-item-icon';\n iconSpan.setAttribute('aria-hidden', 'true');\n iconSpan.innerHTML = iconHTML;\n btn.appendChild(iconSpan);\n }\n\n const textSpan = document.createElement('span');\n textSpan.className = 'dm-slash-command-item-text';\n\n const labelSpan = document.createElement('span');\n labelSpan.className = 'dm-slash-command-item-label';\n labelSpan.textContent = item.label;\n textSpan.appendChild(labelSpan);\n\n if (item.description) {\n const descSpan = document.createElement('span');\n descSpan.className = 'dm-slash-command-item-description';\n descSpan.textContent = item.description;\n textSpan.appendChild(descSpan);\n }\n\n btn.appendChild(textSpan);\n\n if (item.shortcut) {\n const shortcutSpan = document.createElement('span');\n shortcutSpan.className = 'dm-slash-command-item-shortcut';\n shortcutSpan.setAttribute('aria-hidden', 'true');\n shortcutSpan.textContent = item.shortcut;\n btn.appendChild(shortcutSpan);\n }\n\n const indexForItem = flatItems.length;\n btn.addEventListener('mousedown', (e: MouseEvent) => { e.preventDefault(); });\n btn.addEventListener('mouseenter', () => { selectItem(indexForItem); });\n btn.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault();\n // Guard against post-teardown clicks: a mousedown-to-click pair\n // can span `onExit` if the user was holding the mouse button\n // when the popup was dismissed by an outside event.\n if (destroyed) return;\n currentCommand?.(item);\n });\n\n itemButtons.push(btn);\n flatItems.push(item);\n groupEl.appendChild(btn);\n }\n root.appendChild(groupEl);\n }\n\n if (selectedIndex >= flatItems.length) selectedIndex = 0;\n highlight(selectedIndex);\n };\n\n const highlight = (index: number): void => {\n for (const [i, btn] of itemButtons.entries()) {\n if (i === index) {\n btn.setAttribute('data-selected', '');\n } else {\n btn.removeAttribute('data-selected');\n }\n }\n const selected = itemButtons[index];\n // Scroll the selected item into view WITHIN the popup only - never via\n // `scrollIntoView`, which walks ancestors and would yank the page when\n // called during `renderPopup` (runs before `positionFloatingOnce`\n // resolves, so the popup is still at its natural flow position at the\n // bottom of `.dm-editor`).\n if (root && selected) {\n const btnTop = selected.offsetTop;\n const btnBottom = btnTop + selected.offsetHeight;\n const viewTop = root.scrollTop;\n const viewBottom = viewTop + root.clientHeight;\n if (btnTop < viewTop) root.scrollTop = btnTop;\n else if (btnBottom > viewBottom) root.scrollTop = btnBottom - root.clientHeight;\n root.setAttribute('aria-activedescendant', selected.id);\n } else {\n root?.removeAttribute('aria-activedescendant');\n }\n };\n\n const selectItem = (index: number): void => {\n if (index < 0 || index >= itemButtons.length) return;\n selectedIndex = index;\n highlight(index);\n };\n\n const reposition = (props: SlashCommandProps): void => {\n if (!root) return;\n cleanupFloating?.();\n // Pass a callable virtualRef so floating-ui's autoUpdate reads fresh\n // cursor coords on every tick (scroll, resize). Capturing a single rect\n // at call time would freeze the anchor and the popup would drift on\n // scroll. Mirrors the emoji suggestion renderer's pattern.\n const virtualRef = {\n getBoundingClientRect: (): DOMRect => props.clientRect() ?? new DOMRect(),\n };\n cleanupFloating = positionFloatingOnce(\n virtualRef,\n root,\n { placement: 'bottom-start', offsetValue: 4 },\n );\n };\n\n return {\n onStart(props): void {\n currentCommand = props.command;\n selectedIndex = 0;\n destroyed = false;\n\n root = document.createElement('div');\n root.className = 'dm-slash-command-menu';\n root.setAttribute('role', 'menu');\n root.setAttribute('aria-label', 'Insert block');\n root.setAttribute('data-dm-editor-ui', '');\n\n const editorEl = props.element.closest('.dm-editor');\n (editorEl ?? document.body).appendChild(root);\n root.setAttribute('data-show', '');\n\n renderPopup(props);\n reposition(props);\n },\n\n onUpdate(props): void {\n currentCommand = props.command;\n if (!root) return;\n renderPopup(props);\n reposition(props);\n },\n\n onExit(): void {\n destroyed = true;\n cleanupFloating?.();\n cleanupFloating = null;\n root?.remove();\n root = null;\n itemButtons = [];\n flatItems = [];\n selectedIndex = 0;\n currentCommand = null;\n },\n\n onKeyDown(event): boolean {\n if (!root || flatItems.length === 0) return false;\n\n switch (event.key) {\n case 'ArrowDown':\n selectItem((selectedIndex + 1) % flatItems.length);\n return true;\n case 'ArrowUp':\n selectItem((selectedIndex - 1 + flatItems.length) % flatItems.length);\n return true;\n case 'Home':\n selectItem(0);\n return true;\n case 'End':\n selectItem(flatItems.length - 1);\n return true;\n case 'Enter':\n case 'Tab': {\n const item = flatItems[selectedIndex];\n if (item && currentCommand) currentCommand(item);\n return true;\n }\n default:\n return false;\n }\n },\n };\n}\n","/**\n * `/` trigger that opens a filtered popup of insertable blocks. Items are\n * shared with FloatingMenu and BlockHandle via `addFloatingMenuItems()`.\n * On select, the `/query` range is deleted and the item's command runs at\n * the now-empty cursor (so \"Heading 1\" transforms the block, \"Image\" opens\n * its popover, etc.).\n */\nimport {\n Extension,\n FloatingMenuController,\n} from '@domternal/core';\nimport type {\n Editor,\n FloatingMenuItem,\n FloatingMenuItemsOverride,\n} from '@domternal/core';\nimport { Plugin, PluginKey } from '@domternal/pm/state';\nimport type { EditorState, Transaction } from '@domternal/pm/state';\nimport type { EditorView } from '@domternal/pm/view';\nimport { Decoration, DecorationSet } from '@domternal/pm/view';\nimport { ReplaceStep } from '@domternal/pm/transform';\nimport { createSlashSuggestionRenderer } from './createSlashSuggestionRenderer.js';\n\nexport const slashCommandPluginKey = new PluginKey<SlashCommandPluginState>('slashCommand');\n\n// Object Replacement Character. ProseMirror uses U+FFFC as a placeholder\n// for non-text leaf nodes when flattening a range to a string, so we never\n// want a real query char to collide with it.\nconst PM_LEAF_PLACEHOLDER = '';\n\n// ─── Public renderer contract ─────────────────────────────────────────────\n\nexport interface SlashCommandProps {\n /** The editor instance (passed so custom renderers can read state). */\n editor: Editor;\n /** Current query string (text after the `/`). */\n query: string;\n /** Document range of the `/` + query (for replacement). */\n range: { from: number; to: number };\n /** Filtered and ranked items matching the query. */\n items: FloatingMenuItem[];\n /** Execute the selected item and close the popup. */\n command: (item: FloatingMenuItem) => void;\n /** Returns the client rect of the cursor for positioning the popup. */\n clientRect: () => DOMRect | null;\n /** The editor's ProseMirror DOM node (for portal parents etc.). */\n element: HTMLElement;\n}\n\nexport interface SlashCommandRenderer {\n onStart: (props: SlashCommandProps) => void;\n onUpdate: (props: SlashCommandProps) => void;\n onExit: () => void;\n /** Return `true` to consume the key event and prevent default handling. */\n onKeyDown: (event: KeyboardEvent) => boolean;\n}\n\n// ─── Options ──────────────────────────────────────────────────────────────\n\nexport interface SlashCommandOptions {\n /**\n * The trigger character. @default '/'\n */\n char?: string;\n /**\n * Items override. When omitted, items from `editor.floatingMenuItems`\n * (collected via `addFloatingMenuItems()`) are used. An array replaces\n * defaults; a function transforms them.\n */\n items?: FloatingMenuItemsOverride;\n /**\n * Factory returning render callbacks for the popup. Default uses\n * `createSlashSuggestionRenderer()`.\n */\n render?: () => SlashCommandRenderer;\n /**\n * Node types where slash should NOT activate (e.g. `codeBlock`).\n * @default ['codeBlock']\n */\n invalidNodes?: string[];\n}\n\nexport interface CreateSlashCommandPluginOptions {\n pluginKey: PluginKey<SlashCommandPluginState>;\n editor: Editor;\n char: string;\n items?: FloatingMenuItemsOverride;\n render: () => SlashCommandRenderer;\n invalidNodes: string[];\n}\n\n// ─── Internal state ───────────────────────────────────────────────────────\n\nexport interface SlashCommandPluginState {\n active: boolean;\n query: string;\n range: { from: number; to: number } | null;\n}\n\nconst INITIAL_STATE: SlashCommandPluginState = {\n active: false,\n query: '',\n range: null,\n};\n\n/**\n * Returns `true` only when the transaction's effect was inserting EXACTLY\n * the trigger character as a single ReplaceStep with a single-char text\n * slice (no opening/closing depth, no surrounding inserted content).\n *\n * This is the \"did the user just type `/`\" heuristic that gates popup\n * activation. It distinguishes:\n * - real typing (`/`) ✓\n * - typing `/` while a range was selected ✓ (one ReplaceStep, slice \"/\")\n * - paste of `/text...` ✗ (slice.size > 1)\n * - programmatic `insertContent('/foo')` ✗ (slice.size > 1)\n * - selection-only changes (click/arrow) ✗ (no steps)\n * - undo/redo creating a `/` ✗ (multi-step / non-Replace)\n *\n * Rationale: tying activation to the typing event - not to the static\n * presence of `/` before the cursor - matches Notion. Once a slash session\n * is dismissed, the same `/` becomes plain text and doesn't reopen the\n * popup if the user later clicks back next to it.\n */\nfunction justTypedTrigger(tr: Transaction, char: string): boolean {\n if (tr.steps.length !== 1) return false;\n const step = tr.steps[0];\n if (!(step instanceof ReplaceStep)) return false;\n const slice = step.slice;\n if (slice.size !== 1 || slice.openStart !== 0 || slice.openEnd !== 0) return false;\n const node = slice.content.firstChild;\n return !!(node && node.isText && node.text === char);\n}\n\n/**\n * Resolves the current `/query` at the cursor, if any. Returns null if the\n * cursor isn't after a `/` on a qualifying line.\n */\nfunction findSlashQuery(\n state: EditorState,\n triggerChar: string,\n invalidNodes: string[],\n): { query: string; range: { from: number; to: number } } | null {\n const { selection } = state;\n if (!selection.empty) return null;\n\n const { $from } = selection;\n // Disallow in code blocks and any explicitly blocked node types.\n if ($from.parent.type.spec.code) return null;\n if (invalidNodes.includes($from.parent.type.name)) return null;\n\n const textBefore = $from.parent.textBetween(\n 0,\n $from.parentOffset,\n undefined,\n PM_LEAF_PLACEHOLDER,\n );\n const triggerIndex = textBefore.lastIndexOf(triggerChar);\n if (triggerIndex === -1) return null;\n\n // Trigger must be at textblock start OR preceded by whitespace.\n if (triggerIndex > 0 && !/\\s/.test(textBefore[triggerIndex - 1] ?? '')) return null;\n\n const queryText = textBefore.slice(triggerIndex + triggerChar.length);\n // Block queries that contain newlines or tabs (they'd break display).\n if (/[\\n\\t]/.test(queryText)) return null;\n\n const from = $from.start() + triggerIndex;\n const to = $from.pos;\n return { query: queryText, range: { from, to } };\n}\n\n/**\n * Removes items whose `hideWhenInside` matches the cursor's wrapping\n * list type WHEN the cursor sits in the LABEL paragraph of a list-item\n * (the first-child slot). Picking the same list type from a label would\n * lift the user out of the list (PM `liftListItem` semantics) - that's\n * surprising, so we hide the option.\n *\n * The CHILDREN-ZONE case (cursor in a non-first paragraph of a list\n * item) is preserved on purpose: picking the same list type there\n * creates a nested sublist, which is useful and Notion-like.\n */\nexport function filterByCursorAncestors(\n items: FloatingMenuItem[],\n editor: Editor,\n): FloatingMenuItem[] {\n const { $from } = editor.view.state.selection;\n\n // Find the cursor's nearest list-item ancestor; if cursor is in the\n // LABEL slot of that item, record its wrapping list's type name.\n let wrappingListType: string | null = null;\n for (let d = $from.depth; d >= 1; d--) {\n const t = $from.node(d).type.name;\n if (t === 'listItem' || t === 'taskItem') {\n if ($from.index(d) === 0 && d >= 1) {\n wrappingListType = $from.node(d - 1).type.name;\n }\n break;\n }\n }\n\n return items.filter((item) => {\n if (!item.hideWhenInside || item.hideWhenInside.length === 0) return true;\n if (!wrappingListType) return true;\n return !item.hideWhenInside.includes(wrappingListType);\n });\n}\n\n/**\n * Filters and ranks FloatingMenuItems against a query. Priority:\n * 1. Exact label prefix (case-insensitive)\n * 2. Label substring match\n * 3. Keyword match (preserving original keyword index for stable ranking)\n * Returns items in rank order, stable within the same rank.\n */\nexport function filterSlashItems(items: FloatingMenuItem[], query: string): FloatingMenuItem[] {\n if (query.length === 0) return items;\n const q = query.toLowerCase();\n\n const ranked: { item: FloatingMenuItem; score: number }[] = [];\n for (const item of items) {\n const label = item.label.toLowerCase();\n if (label.startsWith(q)) {\n ranked.push({ item, score: 0 });\n continue;\n }\n if (label.includes(q)) {\n ranked.push({ item, score: 1 });\n continue;\n }\n const keywords = item.keywords ?? [];\n const kwIndex = keywords.findIndex((k) => k.toLowerCase().includes(q));\n if (kwIndex !== -1) {\n ranked.push({ item, score: 2 + kwIndex * 0.01 });\n }\n }\n ranked.sort((a, b) => a.score - b.score);\n return ranked.map((r) => r.item);\n}\n\n// ─── Plugin factory ───────────────────────────────────────────────────────\n\nexport function createSlashCommandPlugin(\n options: CreateSlashCommandPluginOptions,\n): Plugin<SlashCommandPluginState> {\n const { pluginKey, editor, char, items: itemsOverride, render, invalidNodes } = options;\n let renderer: SlashCommandRenderer | null = null;\n\n return new Plugin<SlashCommandPluginState>({\n key: pluginKey,\n\n state: {\n init: (): SlashCommandPluginState => ({ ...INITIAL_STATE }),\n apply(tr: Transaction, prev, _oldState, newState): SlashCommandPluginState {\n if (tr.getMeta(pluginKey) === 'dismiss') return { ...INITIAL_STATE };\n\n // Neither doc nor selection changed - nothing to do (popup stays as-is).\n if (!tr.docChanged && !tr.selectionSet) return prev;\n\n // ── Branch 1: popup was ALREADY active ─────────────────────────\n //\n // The query is the text between the trigger position (`range.from`)\n // and the typed-end position (`range.to`). Crucially, `range.to`\n // tracks WHAT THE USER TYPED, not the current cursor. That way\n // navigating the cursor with arrow keys past existing text does\n // not \"swallow\" surrounding chars into the query.\n //\n // Rules per transaction kind:\n // - docChange (typing / backspace / paste / collab):\n // * map both range bounds forward through tr.mapping\n // * if the trigger position itself was deleted, dismiss\n // * if the char at `range.from` is no longer the trigger,\n // dismiss (the `/` got replaced or pushed away)\n // * if the cursor moved PAST the mapped `to`, the user\n // typed more chars at the end - extend `to` to cursor\n // - selection-only (mouse click / arrow key without typing):\n // * cursor must remain in the typed query span\n // [from + 1, to]. Stepping out either end dismisses.\n // Mid-query navigation keeps the popup open with the\n // same query.\n // - non-empty selection (shift+arrow drag): dismiss.\n if (prev.active && prev.range) {\n let { from, to } = prev.range;\n\n if (tr.docChanged) {\n // bias = 1 (default, right): an insertion AT the trigger\n // position pushes the `/` forward; we want our `from` to\n // follow it. Same bias for `to` so a typed char inserted\n // exactly at the end of the query extends the range.\n const fromResult = tr.mapping.mapResult(from);\n const toResult = tr.mapping.mapResult(to);\n if (fromResult.deleted) return { ...INITIAL_STATE };\n from = fromResult.pos;\n to = toResult.pos;\n\n // The char that was the trigger may have been replaced\n // (e.g. autocomplete inserting AT `from`, or the user\n // pasting over it). If so, the session is gone.\n if (\n newState.doc.textBetween(from, from + 1, undefined, PM_LEAF_PLACEHOLDER) !== char\n ) {\n return { ...INITIAL_STATE };\n }\n }\n\n // Range selections (shift+arrow, click-drag) make no sense for\n // a single-cursor suggestion popup.\n if (!newState.selection.empty) return { ...INITIAL_STATE };\n const cursor = newState.selection.from;\n\n // Cursor must remain at or after the first char of the query\n // (i.e. at-or-past the position immediately after `/`).\n if (cursor < from + 1) return { ...INITIAL_STATE };\n\n if (cursor > to) {\n // Past the typed end: only legal as the natural side-effect\n // of typing more chars (cursor moves forward by the inserted\n // length). A pure selection move past `to` (arrow-right past\n // existing text) means the user left the typing session.\n if (!tr.docChanged) return { ...INITIAL_STATE };\n to = cursor;\n }\n\n // Defensive: a collab edit could have flipped the surrounding\n // block into a code block / other invalidNodes type, in which\n // case the slash session should not survive.\n const $cursor = newState.doc.resolve(cursor);\n if ($cursor.parent.type.spec.code) return { ...INITIAL_STATE };\n if (invalidNodes.includes($cursor.parent.type.name)) {\n return { ...INITIAL_STATE };\n }\n\n const query = newState.doc.textBetween(\n from + 1,\n to,\n undefined,\n PM_LEAF_PLACEHOLDER,\n );\n if (/[\\n\\t]/.test(query)) return { ...INITIAL_STATE };\n\n return { active: true, query, range: { from, to } };\n }\n\n // ── Branch 2: popup was INACTIVE ───────────────────────────────\n // Activation is gated to a real typing event of the trigger char.\n // Selection-only changes (mouse click into existing `/text`,\n // arrow-key navigation) and bulk doc changes (paste, programmatic\n // `insertContent` of >1 char) MUST NOT open the popup, even if\n // the cursor lands right after a `/` already in the document.\n // This keeps the slash menu tied to a typing session - matching\n // Notion: once the session is dismissed, the same `/` becomes\n // plain text and clicking back next to it doesn't reopen anything.\n if (!tr.docChanged) return prev;\n if (!justTypedTrigger(tr, char)) return prev;\n\n const result = findSlashQuery(newState, char, invalidNodes);\n if (result) return { active: true, query: result.query, range: result.range };\n return prev;\n },\n },\n\n view(editorView) {\n // Cooperative dismissal: other overlays broadcast `dm:dismiss-overlays`\n // when they open; listen and close the slash popup so two floating\n // menus never appear at once. We suppress the handler while WE are\n // the one dispatching - otherwise the slash popup would dismiss\n // itself the moment it opens (the dispatch is synchronous and reaches\n // our own listener before `update` reaches `renderer.onStart`).\n const editorEl = editorView.dom.closest<HTMLElement>('.dm-editor');\n let suppressDismissHandler = false;\n const dismissHandler = (): void => {\n if (suppressDismissHandler) return;\n const state = pluginKey.getState(editor.view.state);\n if (state?.active) dismissSlashCommand(editor.view);\n };\n editorEl?.addEventListener('dm:dismiss-overlays', dismissHandler);\n\n // Track whether we've already fired the open-time dismiss so we only\n // do it on transition false→true.\n let wasActive = false;\n\n return {\n update(view: EditorView) {\n const state = pluginKey.getState(view.state);\n if (!state) return;\n\n // On activation (first true after being false), broadcast dismiss\n // to close any other overlays that might be open. The local\n // suppression flag prevents our own dismissHandler from firing\n // back at us (the dispatch is synchronous and would otherwise\n // self-dismiss the popup the instant it opens).\n //\n // We MUST flip `wasActive = true` BEFORE dispatching, not after.\n // The dispatch synchronously triggers other listeners (e.g.\n // BlockHandle's `onDismissOverlays` which itself dispatches a\n // ProseMirror transaction to clear `hoveredPos`); that re-enters\n // this same `update` callback. Without flipping `wasActive` first\n // the re-entry would think the popup is still opening and dispatch\n // a *second* `dm:dismiss-overlays` whose nested `finally` would\n // reset `suppressDismissHandler` to false - letting our own\n // dismiss listener fire on the way out and tear down the popup\n // we just created. (`clientRect()` then returns null because the\n // plugin state was just cleared, so the second `onStart` paints\n // an unpositioned popup at the bottom of `.dm-editor`.)\n const becameActive = state.active && !wasActive;\n wasActive = state.active;\n if (becameActive) {\n suppressDismissHandler = true;\n try {\n editorEl?.dispatchEvent(new Event('dm:dismiss-overlays', { bubbles: false }));\n } finally {\n suppressDismissHandler = false;\n }\n }\n\n if (state.active && state.range) {\n const items = FloatingMenuController.resolveItems(editor, itemsOverride);\n const contextual = filterByCursorAncestors(items, editor);\n const filtered = filterSlashItems(contextual, state.query);\n\n const command = (item: FloatingMenuItem): void => {\n const current = pluginKey.getState(view.state);\n if (!current?.range) return;\n\n // Delete the `/query` range first so item's command runs on\n // the now-clean cursor position. Close popup state in the\n // same transaction to avoid a stale-render flash.\n const tr = view.state.tr;\n tr.delete(current.range.from, current.range.to);\n tr.setMeta(pluginKey, 'dismiss');\n view.dispatch(tr);\n\n // Execute the item on a fresh transaction (its command will\n // read the latest state). Items that open a popover (Image\n // URL, Link, etc.) need the popover to claim focus - don't\n // force focus back to the editor here. Simple insert items\n // already leave focus in the editor, so no focus() call is\n // needed in either case.\n FloatingMenuController.executeItem(editor, item);\n };\n\n const clientRect = (): DOMRect | null => {\n const current = pluginKey.getState(view.state);\n if (!current?.range) return null;\n try {\n const coords = view.coordsAtPos(current.range.from);\n return new DOMRect(\n coords.left,\n coords.top,\n 0,\n coords.bottom - coords.top,\n );\n } catch {\n return null;\n }\n };\n\n const props: SlashCommandProps = {\n editor,\n query: state.query,\n range: state.range,\n items: filtered,\n command,\n clientRect,\n element: view.dom,\n };\n\n if (!renderer) {\n renderer = render();\n renderer.onStart(props);\n } else {\n renderer.onUpdate(props);\n }\n } else if (renderer) {\n renderer.onExit();\n renderer = null;\n }\n },\n\n destroy() {\n editorEl?.removeEventListener('dm:dismiss-overlays', dismissHandler);\n if (renderer) {\n try {\n renderer.onExit();\n } finally {\n renderer = null;\n }\n }\n },\n };\n },\n\n props: {\n // Use handleDOMEvents.keydown (not handleKeyDown) so we intercept\n // keys BEFORE other keymap plugins claim them (same trick as Mention).\n handleDOMEvents: {\n keydown(view, event): boolean {\n const state = pluginKey.getState(view.state);\n if (!state?.active) return false;\n\n if (event.key === 'Escape') {\n event.preventDefault();\n const tr = view.state.tr;\n tr.setMeta(pluginKey, 'dismiss');\n view.dispatch(tr);\n return true;\n }\n\n if (renderer) {\n const handled = renderer.onKeyDown(event);\n if (handled) event.preventDefault();\n return handled;\n }\n return false;\n },\n },\n\n decorations(state): DecorationSet {\n const pluginState = pluginKey.getState(state);\n if (!pluginState?.active || !pluginState.range) return DecorationSet.empty;\n return DecorationSet.create(state.doc, [\n Decoration.inline(pluginState.range.from, pluginState.range.to, {\n class: 'dm-slash-command-query',\n nodeName: 'span',\n }),\n ]);\n },\n },\n });\n}\n\nexport const SlashCommand = Extension.create<SlashCommandOptions>({\n name: 'slashCommand',\n\n addOptions() {\n return {\n char: '/',\n invalidNodes: ['codeBlock'],\n };\n },\n\n addProseMirrorPlugins() {\n const editor = this.editor as Editor | null;\n if (!editor) return [];\n return [\n createSlashCommandPlugin({\n pluginKey: slashCommandPluginKey,\n editor,\n char: this.options.char ?? '/',\n ...(this.options.items !== undefined && { items: this.options.items }),\n render: this.options.render ?? createSlashSuggestionRenderer,\n invalidNodes: this.options.invalidNodes ?? ['codeBlock'],\n }),\n ];\n },\n});\n\n/**\n * Programmatically dismisses the slash suggestion.\n */\nexport function dismissSlashCommand(view: EditorView): void {\n view.dispatch(view.state.tr.setMeta(slashCommandPluginKey, 'dismiss'));\n}\n","/**\n * Pasting block-level content at an INLINE position normally goes through PM's\n * content fitter, which strips the block wrapper and pastes only inline text.\n * SmartPaste catches the relevant cases and routes each to the right strategy:\n *\n * 1. List slice into a list ancestor: items adapted (`convertListItemForParent`)\n * and merged as siblings, preserving the surrounding list.\n * 2. Trailing hardBreak (Shift+Enter scenario): trim the hardBreak and insert\n * the slice as a sibling after the parent.\n * 3. Truly empty parent paragraph (`parentSize === 0`): replace the parent.\n * 4-6. Caret at start / end / middle: insert as sibling or split-and-insert.\n * 7. Range selection: delete first, then run through 2-6.\n *\n * Skipped (PM default applies) when:\n * - Cursor isn't inside a textblock.\n * - Slice's top-level blocks are ALL plain paragraphs.\n * - Slice is a SINGLE top-level block of the SAME TYPE as the destination\n * (heading-into-heading, etc.) - PM's inline merge is the intended behavior.\n *\n * Note: do NOT bail on `openStart > 0` - PM's clipboard parser routinely sets\n * `openStart=1` even for closed-looking input like `<h1>x</h1>`. Top-level\n * children of the slice are what matter.\n */\n\nimport { Extension } from '@domternal/core';\nimport { Plugin, TextSelection, Selection } from '@domternal/pm/state';\nimport type { Slice, Node as PMNode, Fragment } from '@domternal/pm/model';\nimport type { EditorView } from '@domternal/pm/view';\nimport type { Transaction } from '@domternal/pm/state';\nimport { convertListItemForParent } from './helpers/convertListItemForParent.js';\n\nconst LIST_TYPES = new Set(['bulletList', 'orderedList', 'taskList']);\nconst LIST_ITEM_TYPES = new Set(['listItem', 'taskItem']);\n\nexport interface SmartPasteOptions {\n /**\n * Disable the plugin without removing the extension. Useful for tests\n * or to fall back to PM's default paste handling temporarily.\n * @default true\n */\n enabled?: boolean;\n}\n\nexport const SmartPaste = Extension.create<SmartPasteOptions>({\n name: 'smartPaste',\n\n addOptions() {\n return {\n enabled: true,\n };\n },\n\n addProseMirrorPlugins() {\n if (this.options.enabled === false) return [];\n return [\n new Plugin({\n props: {\n handlePaste: (view, _event, slice) => handleSmartPaste(view, slice),\n },\n }),\n ];\n },\n});\n\n/**\n * Returns `true` when this plugin handled the paste (PM should skip its\n * default), `false` otherwise.\n */\nfunction handleSmartPaste(view: EditorView, slice: Slice): boolean {\n const { state } = view;\n const { selection } = state;\n const $from = selection.$from;\n\n // Cursor must be at an inline position (inside a textblock). Otherwise\n // PM's default block-paste already does the right thing.\n if (!$from.parent.isTextblock) return false;\n\n // Bail when slice has no non-paragraph block at its top level - PM's\n // default merges plain inline content cleanly.\n if (!sliceHasNonParagraphBlock(slice)) return false;\n\n // Bail when the slice is a single block of the SAME TYPE as the\n // destination textblock (e.g. <h1> pasted inside an <h1>). Splitting\n // the parent block to \"preserve\" the same wrapper would visibly\n // shred the user's heading into three pieces - the inline merge that\n // PM's default does here is what the user actually wants.\n if (sliceIsSingleSameTypeAsParent(slice, $from.parent.type.name)) return false;\n\n // Strategy 1: list-slice into list ancestor - merge as siblings.\n if (tryPasteListSliceIntoList(view, slice)) return true;\n\n // Strategies 2-7: collapse range, then route by parent state + offset.\n const tr = state.tr;\n if (!selection.empty) tr.deleteSelection();\n\n const $pos = tr.selection.$from;\n const parent = $pos.parent;\n const parentStart = $pos.before($pos.depth);\n const parentEnd = $pos.after($pos.depth);\n const offset = $pos.parentOffset;\n const parentSize = parent.content.size;\n\n if (hasTrailingHardBreakAtCursor(parent, offset, parentSize)) {\n // Shift+Enter case: trim the trailing hardBreak and insert the\n // slice AS A SIBLING after the parent textblock. Preserves any\n // text that came before the break (e.g. \"Existing<br>|\" stays as\n // a paragraph \"Existing\", the heading lands as the next sibling).\n // Empty-shift+enter case: \"<p><br></p>\" becomes \"<p></p>\" + slice,\n // i.e. one empty row + the heading below it.\n const hbStart = parentEnd - 2; // hardBreak occupies 1 position before parent close\n const hbEnd = parentEnd - 1;\n tr.delete(hbStart, hbEnd);\n const adjustedParentEnd = parentEnd - 1;\n tr.insert(adjustedParentEnd, slice.content);\n setCaretAtEndOfInserted(tr, adjustedParentEnd, slice.content);\n } else if (parentSize === 0) {\n // Truly-empty parent (no Shift+Enter break either). Default: replace\n // the parent with the slice content so we don't leave a stray empty\n // p before/after the inserted block.\n //\n // Notion-strict carve-out: when the empty paragraph is the LABEL\n // slot of a listItem/taskItem (the schema-required first child of\n // `paragraph block*`), replacing it would either be schema-invalid\n // or trigger PM's content fitter to inject a fresh empty paragraph.\n // Insert the slice AFTER the label instead so the new content\n // attaches as a nested child below the (still empty) label.\n const isListItemLabel = $pos.depth >= 2\n && LIST_ITEM_TYPES.has($pos.node($pos.depth - 1).type.name)\n && $pos.index($pos.depth - 1) === 0;\n if (isListItemLabel) {\n tr.insert(parentEnd, slice.content);\n setCaretAtEndOfInserted(tr, parentEnd, slice.content);\n } else {\n tr.replaceWith(parentStart, parentEnd, slice.content);\n setCaretAtEndOfInserted(tr, parentStart, slice.content);\n }\n } else if (offset === 0) {\n tr.insert(parentStart, slice.content);\n setCaretAtEndOfInserted(tr, parentStart, slice.content);\n } else if (offset === parentSize) {\n tr.insert(parentEnd, slice.content);\n setCaretAtEndOfInserted(tr, parentEnd, slice.content);\n } else {\n // Caret in the middle. Split the textblock at the cursor, then\n // insert the slice content at the BOUNDARY between the two new\n // halves. After split, the cursor's original pos sits at the END\n // of the first half (just before its close marker); the boundary\n // we want is one past that - `cursorPos + 1` (between the close\n // of the first half and the open of the second).\n const cursorPos = $pos.pos;\n tr.split(cursorPos);\n const insertAt = cursorPos + 1;\n tr.insert(insertAt, slice.content);\n setCaretAtEndOfInserted(tr, insertAt, slice.content);\n }\n\n view.dispatch(tr.scrollIntoView());\n return true;\n}\n\n/** True if any top-level slice child is a block other than `paragraph`. */\nfunction sliceHasNonParagraphBlock(slice: Slice): boolean {\n let result = false;\n slice.content.forEach((child) => {\n if (child.isBlock && child.type.name !== 'paragraph') result = true;\n });\n return result;\n}\n\n/**\n * True when the slice contains exactly one top-level block whose type\n * name matches the destination textblock's parent. This is the\n * heading-pasted-inside-heading (and analogous) case where SmartPaste\n * would otherwise split the parent into pieces around the inserted\n * block. PM's default does the right thing here: it strips the\n * matching wrapper and inline-merges the slice content into the\n * existing parent.\n */\nfunction sliceIsSingleSameTypeAsParent(slice: Slice, parentTypeName: string): boolean {\n if (slice.content.childCount !== 1) return false;\n return slice.content.firstChild?.type.name === parentTypeName;\n}\n\n/**\n * Cursor sits at the very end of the parent textblock AND the parent's\n * last child is a `hardBreak`. The Shift+Enter row trigger.\n */\nfunction hasTrailingHardBreakAtCursor(parent: PMNode, offset: number, parentSize: number): boolean {\n if (offset !== parentSize) return false;\n return parent.lastChild?.type.name === 'hardBreak';\n}\n\n/**\n * Slice top-level is a single list (bulletList / orderedList / taskList)\n * AND the caret has a list ancestor. Adapts the slice's items to the\n * ancestor list's expected item type (via `convertListItemForParent`)\n * and merges them as siblings of the current `listItem` / `taskItem`.\n * Returns false (caller falls through) when this case doesn't apply.\n */\nfunction tryPasteListSliceIntoList(view: EditorView, slice: Slice): boolean {\n const { state } = view;\n const { selection, schema } = state;\n\n // Slice must be exactly one top-level list node.\n if (slice.content.childCount !== 1) return false;\n const sliceTop = slice.content.firstChild;\n if (!sliceTop || !LIST_TYPES.has(sliceTop.type.name)) return false;\n\n // Find nearest list-wrapper ancestor of the caret.\n const $from = selection.$from;\n let listDepth = -1;\n for (let d = $from.depth; d > 0; d--) {\n if (LIST_TYPES.has($from.node(d).type.name)) { listDepth = d; break; }\n }\n if (listDepth === -1) return false;\n\n // The corresponding listItem (one level inside the list).\n const listItemDepth = listDepth + 1;\n if ($from.depth < listItemDepth) return false;\n\n const listParent = $from.node(listDepth);\n const adapted = convertListItemForParent(schema, sliceTop.content, listParent.type);\n if (adapted.childCount === 0) return false;\n\n const tr = state.tr;\n if (!selection.empty) tr.deleteSelection();\n\n // Re-resolve after potential range delete. Bail if we lost the list\n // ancestor (selection straddled out - let the fallback paths run).\n const $pos = tr.selection.$from;\n if ($pos.depth < listItemDepth) return false;\n if (!LIST_TYPES.has($pos.node(listDepth).type.name)) return false;\n\n const parent = $pos.parent;\n const parentEnd = $pos.after($pos.depth);\n const offset = $pos.parentOffset;\n const parentSize = parent.content.size;\n const liStart = $pos.before(listItemDepth);\n const liEnd = $pos.after(listItemDepth);\n const itemHasOnlyOneChild = $pos.node(listItemDepth).childCount === 1;\n\n let insertAt: number;\n if (hasTrailingHardBreakAtCursor(parent, offset, parentSize)) {\n // Shift+Enter inside a listItem with a list-slice paste. Trim the\n // trailing hardBreak and insert the (adapted) items as siblings\n // AFTER the current listItem. Empty-row stays where the break was;\n // pasted items appear in subsequent rows.\n const hbStart = parentEnd - 2;\n const hbEnd = parentEnd - 1;\n tr.delete(hbStart, hbEnd);\n const adjustedLiEnd = liEnd - 1;\n tr.insert(adjustedLiEnd, adapted);\n insertAt = adjustedLiEnd;\n } else if (parentSize === 0 && itemHasOnlyOneChild) {\n // Truly-empty listItem: replace it with the slice's items so we\n // don't leave a leading / trailing empty item next to the merge.\n tr.replaceWith(liStart, liEnd, adapted);\n insertAt = liStart;\n } else if (offset === 0) {\n tr.insert(liStart, adapted);\n insertAt = liStart;\n } else if (offset === parentSize) {\n tr.insert(liEnd, adapted);\n insertAt = liEnd;\n } else {\n // Caret in middle of the textblock inside the listItem. Split the\n // listItem at the cursor, then insert items between the two halves.\n // `tr.split(pos, depth)` doubles close+open at each level. For\n // depth=2 (textblock + listItem) the boundary \"between the two new\n // listItems\" is at pos + 2 (after both close tokens).\n const cursorPos = $pos.pos;\n tr.split(cursorPos, 2);\n insertAt = cursorPos + 2;\n tr.insert(insertAt, adapted);\n }\n\n setCaretAtEndOfInserted(tr, insertAt, adapted);\n view.dispatch(tr.scrollIntoView());\n return true;\n}\n\n/**\n * Place the cursor at the END of the LAST inserted block. For text-bearing\n * blocks (paragraph, heading, list-item-with-p), this lands at the end of\n * the deepest textblock. For atom blocks (hr, image), Selection.near picks\n * the closest valid selection.\n *\n * Position math: the fragment occupies `[insertAt, insertAt + content.size)`\n * in the new doc. `insertAt + content.size - 1` is the position right\n * before the outermost close-token of the last inserted top-level child -\n * i.e., the END of its content.\n */\nfunction setCaretAtEndOfInserted(tr: Transaction, insertAt: number, content: Fragment): void {\n if (content.childCount === 0) return;\n const target = Math.max(0, Math.min(tr.doc.content.size, insertAt + content.size - 1));\n const $target = tr.doc.resolve(target);\n if ($target.parent.isTextblock) {\n tr.setSelection(TextSelection.create(tr.doc, target));\n } else {\n tr.setSelection(Selection.near($target, -1));\n }\n}\n"]}
|