@ecsplico/editor 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/adapters/direct-ai.d.ts +36 -0
  3. package/dist/adapters/direct-ai.js +169 -0
  4. package/dist/adapters/direct-ai.js.map +1 -0
  5. package/dist/adapters/memory.js.map +1 -1
  6. package/dist/code/CodeSurface.vue.d.ts +2 -2
  7. package/dist/core/block-drag.js +3 -0
  8. package/dist/core/block-drag.js.map +1 -1
  9. package/dist/core/block-transfer.d.ts +44 -0
  10. package/dist/core/block-transfer.js +68 -0
  11. package/dist/core/block-transfer.js.map +1 -0
  12. package/dist/core/commands.js +5 -0
  13. package/dist/core/commands.js.map +1 -1
  14. package/dist/core/core-feature.d.ts +4 -1
  15. package/dist/core/core-feature.js +8 -3
  16. package/dist/core/core-feature.js.map +1 -1
  17. package/dist/core/editor-ui.d.ts +3 -1
  18. package/dist/core/editor-ui.js.map +1 -1
  19. package/dist/core/extension-points.d.ts +17 -1
  20. package/dist/core/feature.d.ts +6 -1
  21. package/dist/core/feature.js.map +1 -1
  22. package/dist/core/index.d.ts +4 -2
  23. package/dist/core/index.js +3 -2
  24. package/dist/core/schema/index.d.ts +24 -3
  25. package/dist/core/schema/index.js +21 -4
  26. package/dist/core/schema/index.js.map +1 -1
  27. package/dist/core/surface-session.js +3 -1
  28. package/dist/core/surface-session.js.map +1 -1
  29. package/dist/core/toolbar-items.js +1 -1
  30. package/dist/core/toolbar-items.js.map +1 -1
  31. package/dist/document/DocumentSurface.vue.d.ts +2 -2
  32. package/dist/features/ai/agent-op-review.js +1 -1
  33. package/dist/features/ai/agent-ops.js +2 -2
  34. package/dist/features/ai/ai-apply.js +1 -1
  35. package/dist/features/ai/assistant.js +1 -1
  36. package/dist/features/ai/components/AiSelectionMenu.js +2 -2
  37. package/dist/features/ai/components/AiSidebar.js +2 -2
  38. package/dist/features/ai/components/SettingsAiTab.js +1 -1
  39. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  40. package/dist/features/ai/document-chat-model.js +1 -1
  41. package/dist/features/ai/document-chat.js +2 -2
  42. package/dist/features/ai/ghost-autocomplete.js +1 -1
  43. package/dist/features/ai/index.d.ts +4 -3
  44. package/dist/features/ai/index.js +6 -5
  45. package/dist/features/ai/protocol/complete.d.ts +19 -0
  46. package/dist/features/ai/protocol/complete.js +27 -1
  47. package/dist/features/ai/protocol/complete.js.map +1 -1
  48. package/dist/features/ai/protocol/generate.d.ts +95 -0
  49. package/dist/features/ai/protocol/generate.js +58 -0
  50. package/dist/features/ai/protocol/generate.js.map +1 -0
  51. package/dist/features/ai/protocol/index.d.ts +4 -3
  52. package/dist/features/ai/protocol/index.js +6 -5
  53. package/dist/features/ai/protocol/tasks.d.ts +3 -1
  54. package/dist/features/ai/protocol/tasks.js +74 -2
  55. package/dist/features/ai/protocol/tasks.js.map +1 -1
  56. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  57. package/dist/features/ai/react/AiSidebar.js +2 -2
  58. package/dist/features/ai/react/SettingsAiTab.js +1 -1
  59. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  60. package/dist/features/ai/selection-flow.js +1 -1
  61. package/dist/features/ai/sidebar-flow.js +1 -1
  62. package/dist/features/block-ui/block-actions.d.ts +19 -3
  63. package/dist/features/block-ui/block-actions.js +49 -3
  64. package/dist/features/block-ui/block-actions.js.map +1 -1
  65. package/dist/features/block-ui/components/BlockActionsOverlay.js +24 -13
  66. package/dist/features/block-ui/components/BlockActionsOverlay.js.map +1 -1
  67. package/dist/features/block-ui/components/BlockActionsOverlay.vue.d.ts +12 -5
  68. package/dist/features/block-ui/components/BlockUi.js +52 -20
  69. package/dist/features/block-ui/components/BlockUi.js.map +1 -1
  70. package/dist/features/block-ui/components/BlockUi.vue.d.ts +6 -4
  71. package/dist/features/block-ui/feature.d.ts +8 -2
  72. package/dist/features/block-ui/feature.js +7 -2
  73. package/dist/features/block-ui/feature.js.map +1 -1
  74. package/dist/features/block-ui/index.d.ts +3 -2
  75. package/dist/features/block-ui/index.js +2 -2
  76. package/dist/features/block-ui/react/BlockActionsOverlay.d.ts +14 -7
  77. package/dist/features/block-ui/react/BlockActionsOverlay.js +25 -13
  78. package/dist/features/block-ui/react/BlockActionsOverlay.js.map +1 -1
  79. package/dist/features/block-ui/react/BlockUi.d.ts +6 -4
  80. package/dist/features/block-ui/react/BlockUi.js +43 -15
  81. package/dist/features/block-ui/react/BlockUi.js.map +1 -1
  82. package/dist/features/block-ui/react.d.ts +4 -2
  83. package/dist/features/block-ui/react.js +3 -3
  84. package/dist/features/block-ui/react.js.map +1 -1
  85. package/dist/features/block-ui/vue.d.ts +4 -2
  86. package/dist/features/block-ui/vue.js +3 -3
  87. package/dist/features/block-ui/vue.js.map +1 -1
  88. package/dist/features/composites/baskets.d.ts +27 -0
  89. package/dist/features/composites/baskets.js +46 -0
  90. package/dist/features/composites/baskets.js.map +1 -0
  91. package/dist/features/composites/components/CompositeBasketMenu.js +97 -0
  92. package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -0
  93. package/dist/features/composites/components/CompositeChrome.js +79 -23
  94. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  95. package/dist/features/composites/components/CompositeFieldEditor.js +1 -0
  96. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  97. package/dist/features/composites/components/CompositeView.js +17 -2
  98. package/dist/features/composites/components/CompositeView.js.map +1 -1
  99. package/dist/features/composites/components/DerivationBadge.js +12 -3
  100. package/dist/features/composites/components/DerivationBadge.js.map +1 -1
  101. package/dist/features/composites/components/FocusChip.js +53 -0
  102. package/dist/features/composites/components/FocusChip.js.map +1 -0
  103. package/dist/features/composites/components/FocusChip.vue.d.ts +14 -0
  104. package/dist/features/composites/components/SettingsEditingTab.js +40 -4
  105. package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
  106. package/dist/features/composites/derivation.d.ts +2 -1
  107. package/dist/features/composites/derivation.js +5 -1
  108. package/dist/features/composites/derivation.js.map +1 -1
  109. package/dist/features/composites/derived-chrome.js +13 -3
  110. package/dist/features/composites/derived-chrome.js.map +1 -1
  111. package/dist/features/composites/feature.d.ts +7 -1
  112. package/dist/features/composites/feature.js +96 -23
  113. package/dist/features/composites/feature.js.map +1 -1
  114. package/dist/features/composites/focus.d.ts +38 -0
  115. package/dist/features/composites/focus.js +86 -0
  116. package/dist/features/composites/focus.js.map +1 -0
  117. package/dist/features/composites/index.d.ts +6 -3
  118. package/dist/features/composites/index.js +6 -3
  119. package/dist/features/composites/meta-keys.d.ts +4 -0
  120. package/dist/features/composites/meta-keys.js +8 -4
  121. package/dist/features/composites/meta-keys.js.map +1 -1
  122. package/dist/features/composites/nodes.d.ts +14 -2
  123. package/dist/features/composites/nodes.js +61 -5
  124. package/dist/features/composites/nodes.js.map +1 -1
  125. package/dist/features/composites/outline.d.ts +4 -0
  126. package/dist/features/composites/outline.js +3 -0
  127. package/dist/features/composites/outline.js.map +1 -1
  128. package/dist/features/composites/react/CompositeBasketMenu.js +88 -0
  129. package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -0
  130. package/dist/features/composites/react/CompositeChrome.js +52 -4
  131. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  132. package/dist/features/composites/react/CompositeView.js +12 -2
  133. package/dist/features/composites/react/CompositeView.js.map +1 -1
  134. package/dist/features/composites/react/DerivationBadge.js +10 -1
  135. package/dist/features/composites/react/DerivationBadge.js.map +1 -1
  136. package/dist/features/composites/react/FocusChip.d.ts +11 -0
  137. package/dist/features/composites/react/FocusChip.js +50 -0
  138. package/dist/features/composites/react/FocusChip.js.map +1 -0
  139. package/dist/features/composites/react/SettingsEditingTab.js +36 -1
  140. package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
  141. package/dist/features/composites/react.d.ts +2 -1
  142. package/dist/features/composites/react.js +3 -1
  143. package/dist/features/composites/react.js.map +1 -1
  144. package/dist/features/composites/schema.d.ts +5 -3
  145. package/dist/features/composites/schema.js +8 -4
  146. package/dist/features/composites/schema.js.map +1 -1
  147. package/dist/features/composites/split.d.ts +62 -0
  148. package/dist/features/composites/split.js +172 -0
  149. package/dist/features/composites/split.js.map +1 -0
  150. package/dist/features/composites/vue.d.ts +4 -3
  151. package/dist/features/composites/vue.js +7 -5
  152. package/dist/features/composites/vue.js.map +1 -1
  153. package/dist/features/media/index.js +1 -1
  154. package/dist/features/media/react/AudioRecorderModal.js +1 -1
  155. package/dist/features/media/react.js +1 -1
  156. package/dist/features/transfer/components/TransferMenu.js +93 -0
  157. package/dist/features/transfer/components/TransferMenu.js.map +1 -0
  158. package/dist/features/transfer/components/TransferMenu.vue.d.ts +15 -0
  159. package/dist/features/transfer/feature.d.ts +76 -0
  160. package/dist/features/transfer/feature.js +169 -0
  161. package/dist/features/transfer/feature.js.map +1 -0
  162. package/dist/features/transfer/index.d.ts +3 -0
  163. package/dist/features/transfer/index.js +3 -0
  164. package/dist/features/transfer/react/TransferMenu.d.ts +12 -0
  165. package/dist/features/transfer/react/TransferMenu.js +71 -0
  166. package/dist/features/transfer/react/TransferMenu.js.map +1 -0
  167. package/dist/features/transfer/react.d.ts +10 -0
  168. package/dist/features/transfer/react.js +11 -0
  169. package/dist/features/transfer/react.js.map +1 -0
  170. package/dist/features/transfer/transforms.d.ts +83 -0
  171. package/dist/features/transfer/transforms.js +137 -0
  172. package/dist/features/transfer/transforms.js.map +1 -0
  173. package/dist/features/transfer/vue.d.ts +9 -0
  174. package/dist/features/transfer/vue.js +11 -0
  175. package/dist/features/transfer/vue.js.map +1 -0
  176. package/dist/i18n/de/ai.js +4 -0
  177. package/dist/i18n/de/ai.js.map +1 -1
  178. package/dist/i18n/de/composites.js +20 -1
  179. package/dist/i18n/de/composites.js.map +1 -1
  180. package/dist/i18n/de/integrations.js +16 -0
  181. package/dist/i18n/de/integrations.js.map +1 -1
  182. package/dist/i18n/de/transfer.js +17 -0
  183. package/dist/i18n/de/transfer.js.map +1 -0
  184. package/dist/i18n/de/tree.js +6 -0
  185. package/dist/i18n/de/tree.js.map +1 -1
  186. package/dist/i18n/de.d.ts +55 -0
  187. package/dist/i18n/de.js +3 -1
  188. package/dist/i18n/de.js.map +1 -1
  189. package/dist/i18n/en/ai.js +4 -0
  190. package/dist/i18n/en/ai.js.map +1 -1
  191. package/dist/i18n/en/composites.js +20 -1
  192. package/dist/i18n/en/composites.js.map +1 -1
  193. package/dist/i18n/en/integrations.js +16 -0
  194. package/dist/i18n/en/integrations.js.map +1 -1
  195. package/dist/i18n/en/transfer.js +17 -0
  196. package/dist/i18n/en/transfer.js.map +1 -0
  197. package/dist/i18n/en/tree.js +6 -0
  198. package/dist/i18n/en/tree.js.map +1 -1
  199. package/dist/i18n/en.js +3 -1
  200. package/dist/i18n/en.js.map +1 -1
  201. package/dist/integrations/composite-ai/composite-fill.js +1 -1
  202. package/dist/integrations/composite-ai/composite-summary.js +1 -1
  203. package/dist/integrations/composite-ai/derive.d.ts +21 -0
  204. package/dist/integrations/composite-ai/derive.js +69 -47
  205. package/dist/integrations/composite-ai/derive.js.map +1 -1
  206. package/dist/integrations/composite-ai/index.d.ts +8 -3
  207. package/dist/integrations/composite-ai/index.js +50 -4
  208. package/dist/integrations/composite-ai/index.js.map +1 -1
  209. package/dist/integrations/composite-ai/outline-sanitize.d.ts +48 -0
  210. package/dist/integrations/composite-ai/outline-sanitize.js +175 -0
  211. package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -0
  212. package/dist/integrations/composite-ai/split.d.ts +44 -0
  213. package/dist/integrations/composite-ai/split.js +187 -0
  214. package/dist/integrations/composite-ai/split.js.map +1 -0
  215. package/dist/integrations/composite-ai/transfer-transforms.d.ts +27 -0
  216. package/dist/integrations/composite-ai/transfer-transforms.js +153 -0
  217. package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -0
  218. package/dist/integrations/transcript-ai/protocol.d.ts +13 -0
  219. package/dist/integrations/transcript-ai/protocol.js +49 -1
  220. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  221. package/dist/integrations/transcript-ai/transcript-cleanup.js +1 -1
  222. package/dist/markdown/MarkdownSurface.vue.d.ts +6 -6
  223. package/dist/nuxt/module.d.ts +110 -0
  224. package/dist/presets/compose.d.ts +24 -8
  225. package/dist/presets/compose.js +117 -58
  226. package/dist/presets/compose.js.map +1 -1
  227. package/dist/react/compose.js +6 -2
  228. package/dist/react/compose.js.map +1 -1
  229. package/dist/react/composed-surface.d.ts +9 -0
  230. package/dist/react/composed-surface.js +4 -1
  231. package/dist/react/composed-surface.js.map +1 -1
  232. package/dist/server/ai.d.ts +2 -5
  233. package/dist/server/ai.js.map +1 -1
  234. package/dist/server/handlers/ai.d.ts +7 -78
  235. package/dist/server/handlers/ai.js +30 -94
  236. package/dist/server/handlers/ai.js.map +1 -1
  237. package/dist/server/handlers/editor.d.ts +1 -0
  238. package/dist/server/handlers/index.d.ts +3 -1
  239. package/dist/server/handlers/index.js +3 -1
  240. package/dist/server/index.d.ts +2 -1
  241. package/dist/settings/index.d.ts +8 -0
  242. package/dist/settings/index.js +16 -4
  243. package/dist/settings/index.js.map +1 -1
  244. package/dist/styles/composites.css +32 -0
  245. package/dist/tree/DocumentTree.js +229 -78
  246. package/dist/tree/DocumentTree.js.map +1 -1
  247. package/dist/tree/drop-rules.js +8 -0
  248. package/dist/tree/drop-rules.js.map +1 -1
  249. package/dist/tree/react/DocumentTree.js +152 -31
  250. package/dist/tree/react/DocumentTree.js.map +1 -1
  251. package/dist/tree/tree-host.js +30 -1
  252. package/dist/tree/tree-host.js.map +1 -1
  253. package/dist/tree/tree-items.js +52 -5
  254. package/dist/tree/tree-items.js.map +1 -1
  255. package/dist/tree/tree-model.js +113 -10
  256. package/dist/tree/tree-model.js.map +1 -1
  257. package/dist/tree/tree-rows.js +20 -7
  258. package/dist/tree/tree-rows.js.map +1 -1
  259. package/dist/tree/tree-view-model.d.ts +5 -0
  260. package/dist/tree/tree-view-model.js +13 -0
  261. package/dist/tree/tree-view-model.js.map +1 -1
  262. package/dist/vue/AdvancedEditor.js +6 -0
  263. package/dist/vue/AdvancedEditor.js.map +1 -1
  264. package/dist/vue/AdvancedEditor.vue.d.ts +13 -5
  265. package/dist/vue/SimpleEditor.vue.d.ts +4 -4
  266. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  267. package/dist/vue/compose.js +6 -2
  268. package/dist/vue/compose.js.map +1 -1
  269. package/dist/vue/kit/types.d.ts +2 -0
  270. package/package.json +21 -1
@@ -1 +1 @@
1
- {"version":3,"file":"BlockUi.js","names":[],"sources":["../../../../src/features/block-ui/react/BlockUi.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { DragHandle, type DragHandleProps } from '@tiptap/extension-drag-handle-react'\nimport type { Node } from '@tiptap/pm/model'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { type BlockTarget, editorEntryOf } from '../../../core'\nimport { isChromeNode } from '../../../core/schema'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorSettings } from '../../../react/settings'\nimport { cn } from '../../../react/ui/utils'\nimport { firstLineCenterShift, gutterShiftOf, handleLeftOf, hasKindIcon } from '../handle-geometry'\nimport { BlockActionsOverlay } from './BlockActionsOverlay'\nimport { BlockHandles } from './BlockHandles'\n\n/**\n * Block UI of an editor: the drag handle on the left of the hovered block (hidden while the editor is read-only) and the\n * hover actions (`BlockActionsOverlay`) at the editor's right edge, both targeting the same block. The actions are those\n * the surface registered for `editor` (features' block actions, then the host's). A block with a kind icon (a composite)\n * gets no handle: its icon drags it. With `blocks.dragHandle: 'always'` the hover handle is replaced by permanent\n * handles on every eligible block (`BlockHandles`). Mounted by the block-ui feature beside the editor.\n */\nexport function BlockUi({ editor }: { editor: Editor }) {\n // Hover actions target the drag handle's block. The plugin drops its target when the pointer leaves the editor (also\n // onto the overlay, which sits outside it) and on keydown; a short grace keeps the overlay while the pointer moves\n // onto it, and typing hides it at once.\n const [host, setHost] = useState<HTMLElement | null>(null)\n const [hoverTarget, setHoverTarget] = useState<BlockTarget | null>(null)\n const [targetHasKindIcon, setTargetHasKindIcon] = useState(false)\n const { settings } = useEditorSettings()\n // Read while rendering: the surface registers its entry after its overlays have mounted, and the overlay renders\n // again once a block is hovered.\n const actions = editorEntryOf(editor)?.blockActions ?? []\n\n // Everything the plugin callbacks and the targeting rules below read while the pointer moves: not render state.\n const track = useRef({\n overlayHovered: false,\n clearTimer: undefined as number | undefined,\n pointer: null as { x: number, y: number } | null,\n dom: null as HTMLElement | null,\n node: null as Node | null,\n gutterShift: 0,\n }).current\n // The handle's content; its parent is the handle element the plugin positions (`handleWidth`).\n const handleContent = useRef<HTMLSpanElement>(null)\n const handleWidth = () => handleContent.current?.parentElement?.offsetWidth ?? 0\n\n const scheduleHoverClear = useCallback(() => {\n clearTimeout(track.clearTimer)\n track.clearTimer = window.setTimeout(() => {\n if (!track.overlayHovered) setHoverTarget(null)\n }, 200)\n }, [track])\n\n // The overlay is positioned inside the element that holds the editor content (`relative`); Tiptap's content component\n // has moved the editor DOM into it by the time this effect runs.\n useEffect(() => {\n if (editor.isDestroyed) return\n const dom = editor.view.dom\n setHost(dom.isConnected ? dom.parentElement : null)\n // Like the drag-handle plugin: a key pressed in the focused editor hides the actions.\n const onKeydown = () => {\n clearTimeout(track.clearTimer)\n setHoverTarget(null)\n }\n // Pointer position for the targeting rules below. The plugin evaluates them in a frame callback after the\n // mousemove, so this is the position they see.\n const onMousemove = (event: MouseEvent) => {\n track.pointer = { x: event.clientX, y: event.clientY }\n }\n dom.addEventListener('keydown', onKeydown)\n dom.addEventListener('mousemove', onMousemove)\n return () => {\n clearTimeout(track.clearTimer)\n dom.removeEventListener('keydown', onKeydown)\n dom.removeEventListener('mousemove', onMousemove)\n setHost(null)\n }\n }, [editor, track])\n\n const onOverlayHover = useCallback((hovered: boolean) => {\n track.overlayHovered = hovered\n if (!hovered) scheduleHoverClear()\n }, [track, scheduleHoverClear])\n\n // The drag-handle plugin hides the handle on dragend but keeps its current target. A dropped\n // nested node is the same node object, so hovering it again would not re-show the handle.\n // The plugin's `hideDragHandle` meta clears the target.\n const resetDragHandle = useCallback(() => {\n if (editor.isDestroyed) return\n editor.view.dispatch(editor.state.tr.setMeta('hideDragHandle', true).setMeta('addToHistory', false))\n }, [editor])\n\n // The plugin puts the handle's right edge on the target block's left edge (`gutterShiftOf`: list items move further\n // left). The hover handle is hidden where the block has a handle of its own: the kind icon of a composite, or, with\n // `blocks.dragHandle: 'always'`, the permanent handles. Hiding keeps its layout, which the targeting rules below measure.\n const alwaysHandles = settings.blocks.dragHandle === 'always'\n const hoverHandleHidden = alwaysHandles || targetHasKindIcon\n const trackDragTarget = useCallback(({ node, pos }: { node: Node | null, pos: number }) => {\n if (node) {\n clearTimeout(track.clearTimer)\n setHoverTarget({ node, pos })\n }\n else {\n scheduleHoverClear()\n }\n const dom = node ? editor.view.nodeDOM(pos) : null\n track.dom = dom instanceof HTMLElement ? dom : null\n track.node = track.dom ? node : null\n track.gutterShift = track.dom && track.node ? gutterShiftOf(track.node, track.dom) : 0\n setTargetHasKindIcon(track.dom ? hasKindIcon(track.dom) : false)\n }, [editor, track, scheduleHoverClear])\n\n // The plugin re-registers when its configuration changes: both objects below are made once and read `track`.\n const dragHandlePosition = useMemo<DragHandleProps['computePositionConfig']>(() => ({\n // The plugin aligns the handle's top with the block's top, which sits above the middle of the block's first text\n // line: `firstLineCenterShift` moves the handle's centre to that line's centre.\n middleware: [\n { name: 'gutterShift', fn: ({ x, y }) => ({ x: x - track.gutterShift, y }) },\n {\n name: 'firstLineCenter',\n fn: ({ x, y, elements, rects }) => ({\n x,\n y: track.dom ? y + firstLineCenterShift(track.dom, elements.reference.getBoundingClientRect().top, rects.floating.height) : y,\n }),\n },\n ],\n }), [track])\n\n // Targeting among nested blocks. `compositeChrome`: hovering a composite's title, description or tags row targets the\n // composite itself (a deduction of 1000, the base score, excludes a node). `reachTarget`: see `pointerReachesTarget`.\n // `ownGutter`: a nested block is targeted only from its handle column rightwards; further left its ancestors are, so\n // on any row the gutter is partitioned by the handle columns of the blocks nested there. The plugin's edge detection\n // is off: its left strip is this partition, its top strip would hand the handle to the parent on the block's first\n // line, where the handle sits.\n const dragHandleNested = useMemo<DragHandleProps['nested']>(() => {\n // Left of a block, ProseMirror resolves the pointer to the position before the block, so the plugin only considers\n // the block's ancestors there: the target's own handle column would hand the handle to its parent before the pointer\n // reaches it. This keeps the target while the pointer is between its handle and its box, over its whole height\n // including the gaps to its neighbours, and in those gaps themselves (which resolve to the parent as well). The rule\n // then excludes every candidate, and the plugin keeps its target when the detection yields none. Inside the target's\n // own box the rule is off, so its descendants are still targeted.\n const pointerReachesTarget = (): boolean => {\n const { pointer, node, dom } = track\n if (!pointer || !node || !dom?.isConnected) return false\n const rect = dom.getBoundingClientRect()\n const { x, y } = pointer\n if (x < handleLeftOf(node, dom, handleWidth()) || x >= rect.right) return false\n if (y < (laidOutSibling(dom, 'previous')?.bottom ?? rect.top)) return false\n if (y >= (laidOutSibling(dom, 'next')?.top ?? rect.bottom)) return false\n return x < rect.left || y < rect.top || y >= rect.bottom\n }\n return {\n edgeDetection: 'none',\n rules: [\n { id: 'compositeChrome', evaluate: ({ node }) => isChromeNode(node) ? 1000 : 0 },\n { id: 'reachTarget', evaluate: () => pointerReachesTarget() ? 1000 : 0 },\n {\n id: 'ownGutter',\n evaluate: ({ node, pos, depth, view }) => {\n const { pointer } = track\n if (depth < 2 || !pointer) return 0\n const dom = view.nodeDOM(pos)\n return dom instanceof HTMLElement && pointer.x < handleLeftOf(node, dom, handleWidth()) ? 1000 : 0\n },\n },\n ],\n }\n }, [track])\n\n return (\n <>\n {host && createPortal(\n <>\n <BlockActionsOverlay editor={editor} target={hoverTarget} host={host} actions={actions} onHover={onOverlayHover} />\n {alwaysHandles && <BlockHandles editor={editor} host={host} />}\n </>,\n host,\n )}\n <DragHandle\n editor={editor}\n onElementDragEnd={resetDragHandle}\n onNodeChange={trackDragTarget}\n computePositionConfig={dragHandlePosition}\n nested={dragHandleNested}\n className={cn(\n 'flex size-6 cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground data-[dragging=true]:cursor-grabbing',\n hoverHandleHidden && 'invisible! pointer-events-none!',\n )}\n >\n <span ref={handleContent} className=\"contents\">\n <Icon name=\"i-lucide-grip-vertical\" />\n </span>\n </DragHandle>\n </>\n )\n}\n\n// Nearest sibling with a layout box (a composite's hidden description/tags rows have none).\nfunction laidOutSibling(dom: Element, side: 'previous' | 'next'): DOMRect | null {\n for (let element = dom[`${side}ElementSibling`]; element; element = element[`${side}ElementSibling`]) {\n const rect = element.getBoundingClientRect()\n if (rect.height > 0) return rect\n }\n return null\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BlockUi.js","names":[],"sources":["../../../../src/features/block-ui/react/BlockUi.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { DragHandle, type DragHandleProps } from '@tiptap/extension-drag-handle-react'\nimport type { Node } from '@tiptap/pm/model'\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { type BlockTarget, editorEntryOf } from '../../../core'\nimport { isChromeNode } from '../../../core/schema'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorSettings } from '../../../react/settings'\nimport { cn } from '../../../react/ui/utils'\nimport { firstLineCenterShift, gutterShiftOf, handleLeftOf, hasKindIcon } from '../handle-geometry'\nimport { actionSurfacesOf, sameBlock, selectedBlockOf } from '../block-actions'\nimport { BlockActionsOverlay } from './BlockActionsOverlay'\nimport { BlockHandles } from './BlockHandles'\n\n/**\n * Block UI of an editor: the drag handle on the left of the hovered block (hidden while the editor is read-only) and the\n * block actions (`BlockActionsOverlay`) at the editor's right edge. The actions are those the surface registered for\n * `editor` (features' block actions, then the host's), shown per `BlockUiOptions.actions`: on a hover bar for the block\n * the drag handle targets, on a persistent toolbar for the block holding the selection, both, or neither. When both\n * would show a bar on the same block, only the toolbar does. A block with a kind icon (a composite) gets no handle: its\n * icon drags it. With `blocks.dragHandle: 'always'` the hover handle is replaced by permanent handles on every eligible\n * block (`BlockHandles`). Mounted by the block-ui feature beside the editor.\n */\nexport function BlockUi({ editor }: { editor: Editor }) {\n // Hover actions target the drag handle's block. The plugin drops its target when the pointer leaves the editor (also\n // onto the overlay, which sits outside it) and on keydown; a short grace keeps the overlay while the pointer moves\n // onto it, and typing hides it at once.\n const [host, setHost] = useState<HTMLElement | null>(null)\n const [hoverTarget, setHoverTarget] = useState<BlockTarget | null>(null)\n const [targetHasKindIcon, setTargetHasKindIcon] = useState(false)\n const { settings } = useEditorSettings()\n // Read while rendering: the surface registers its entry after its overlays have mounted, and the overlay renders\n // again once a block is hovered.\n const actions = editorEntryOf(editor)?.blockActions ?? []\n const surfaces = actionSurfacesOf(editor)\n\n // The toolbar follows the selection: render on each transaction, but only while that surface exists (the options are\n // read when the transaction happens, the entry being registered after this component mounted).\n const [, rerender] = useReducer((count: number) => count + 1, 0)\n useEffect(() => {\n const onTransaction = () => { if (actionSurfacesOf(editor).toolbar) rerender() }\n editor.on('transaction', onTransaction)\n return () => { editor.off('transaction', onTransaction) }\n }, [editor])\n const selectedTarget = surfaces.toolbar ? selectedBlockOf(editor) : null\n // One bar per block: the toolbar wins where the hover bar would sit on the same block.\n const hoverBarTarget = hoverTarget && selectedTarget && sameBlock(editor, hoverTarget, selectedTarget) ? null : hoverTarget\n\n // Everything the plugin callbacks and the targeting rules below read while the pointer moves: not render state.\n const track = useRef({\n overlayHovered: false,\n clearTimer: undefined as number | undefined,\n pointer: null as { x: number, y: number } | null,\n dom: null as HTMLElement | null,\n node: null as Node | null,\n gutterShift: 0,\n }).current\n // The handle's content; its parent is the handle element the plugin positions (`handleWidth`).\n const handleContent = useRef<HTMLSpanElement>(null)\n const handleWidth = () => handleContent.current?.parentElement?.offsetWidth ?? 0\n\n const scheduleHoverClear = useCallback(() => {\n clearTimeout(track.clearTimer)\n track.clearTimer = window.setTimeout(() => {\n if (!track.overlayHovered) setHoverTarget(null)\n }, 200)\n }, [track])\n\n // The overlay is positioned inside the element that holds the editor content (`relative`); Tiptap's content component\n // has moved the editor DOM into it by the time this effect runs.\n useEffect(() => {\n if (editor.isDestroyed) return\n const dom = editor.view.dom\n setHost(dom.isConnected ? dom.parentElement : null)\n // Like the drag-handle plugin: a key pressed in the focused editor hides the actions.\n const onKeydown = () => {\n clearTimeout(track.clearTimer)\n setHoverTarget(null)\n }\n // Pointer position for the targeting rules below. The plugin evaluates them in a frame callback after the\n // mousemove, so this is the position they see.\n const onMousemove = (event: MouseEvent) => {\n track.pointer = { x: event.clientX, y: event.clientY }\n }\n dom.addEventListener('keydown', onKeydown)\n dom.addEventListener('mousemove', onMousemove)\n return () => {\n clearTimeout(track.clearTimer)\n dom.removeEventListener('keydown', onKeydown)\n dom.removeEventListener('mousemove', onMousemove)\n setHost(null)\n }\n }, [editor, track])\n\n const onOverlayHover = useCallback((hovered: boolean) => {\n track.overlayHovered = hovered\n if (!hovered) scheduleHoverClear()\n }, [track, scheduleHoverClear])\n\n // The drag-handle plugin hides the handle on dragend but keeps its current target. A dropped\n // nested node is the same node object, so hovering it again would not re-show the handle.\n // The plugin's `hideDragHandle` meta clears the target.\n const resetDragHandle = useCallback(() => {\n if (editor.isDestroyed) return\n editor.view.dispatch(editor.state.tr.setMeta('hideDragHandle', true).setMeta('addToHistory', false))\n }, [editor])\n\n // The plugin puts the handle's right edge on the target block's left edge (`gutterShiftOf`: list items move further\n // left). The hover handle is hidden where the block has a handle of its own: the kind icon of a composite, or, with\n // `blocks.dragHandle: 'always'`, the permanent handles. Hiding keeps its layout, which the targeting rules below measure.\n const alwaysHandles = settings.blocks.dragHandle === 'always'\n const hoverHandleHidden = alwaysHandles || targetHasKindIcon\n const trackDragTarget = useCallback(({ node, pos }: { node: Node | null, pos: number }) => {\n if (node) {\n clearTimeout(track.clearTimer)\n setHoverTarget({ node, pos })\n }\n else {\n scheduleHoverClear()\n }\n const dom = node ? editor.view.nodeDOM(pos) : null\n track.dom = dom instanceof HTMLElement ? dom : null\n track.node = track.dom ? node : null\n track.gutterShift = track.dom && track.node ? gutterShiftOf(track.node, track.dom) : 0\n setTargetHasKindIcon(track.dom ? hasKindIcon(track.dom) : false)\n }, [editor, track, scheduleHoverClear])\n\n // The plugin re-registers when its configuration changes: both objects below are made once and read `track`.\n const dragHandlePosition = useMemo<DragHandleProps['computePositionConfig']>(() => ({\n // The plugin aligns the handle's top with the block's top, which sits above the middle of the block's first text\n // line: `firstLineCenterShift` moves the handle's centre to that line's centre.\n middleware: [\n { name: 'gutterShift', fn: ({ x, y }) => ({ x: x - track.gutterShift, y }) },\n {\n name: 'firstLineCenter',\n fn: ({ x, y, elements, rects }) => ({\n x,\n y: track.dom ? y + firstLineCenterShift(track.dom, elements.reference.getBoundingClientRect().top, rects.floating.height) : y,\n }),\n },\n ],\n }), [track])\n\n // Targeting among nested blocks. `compositeChrome`: hovering a composite's title, description or tags row targets the\n // composite itself (a deduction of 1000, the base score, excludes a node). `reachTarget`: see `pointerReachesTarget`.\n // `ownGutter`: a nested block is targeted only from its handle column rightwards; further left its ancestors are, so\n // on any row the gutter is partitioned by the handle columns of the blocks nested there. The plugin's edge detection\n // is off: its left strip is this partition, its top strip would hand the handle to the parent on the block's first\n // line, where the handle sits.\n const dragHandleNested = useMemo<DragHandleProps['nested']>(() => {\n // Left of a block, ProseMirror resolves the pointer to the position before the block, so the plugin only considers\n // the block's ancestors there: the target's own handle column would hand the handle to its parent before the pointer\n // reaches it. This keeps the target while the pointer is between its handle and its box, over its whole height\n // including the gaps to its neighbours, and in those gaps themselves (which resolve to the parent as well). The rule\n // then excludes every candidate, and the plugin keeps its target when the detection yields none. Inside the target's\n // own box the rule is off, so its descendants are still targeted.\n const pointerReachesTarget = (): boolean => {\n const { pointer, node, dom } = track\n if (!pointer || !node || !dom?.isConnected) return false\n const rect = dom.getBoundingClientRect()\n const { x, y } = pointer\n if (x < handleLeftOf(node, dom, handleWidth()) || x >= rect.right) return false\n if (y < (laidOutSibling(dom, 'previous')?.bottom ?? rect.top)) return false\n if (y >= (laidOutSibling(dom, 'next')?.top ?? rect.bottom)) return false\n return x < rect.left || y < rect.top || y >= rect.bottom\n }\n return {\n edgeDetection: 'none',\n rules: [\n { id: 'compositeChrome', evaluate: ({ node }) => isChromeNode(node) ? 1000 : 0 },\n { id: 'reachTarget', evaluate: () => pointerReachesTarget() ? 1000 : 0 },\n {\n id: 'ownGutter',\n evaluate: ({ node, pos, depth, view }) => {\n const { pointer } = track\n if (depth < 2 || !pointer) return 0\n const dom = view.nodeDOM(pos)\n return dom instanceof HTMLElement && pointer.x < handleLeftOf(node, dom, handleWidth()) ? 1000 : 0\n },\n },\n ],\n }\n }, [track])\n\n return (\n <>\n {host && createPortal(\n <>\n {surfaces.hover && (\n <BlockActionsOverlay editor={editor} target={hoverBarTarget} host={host} actions={actions} surface=\"hover\" onHover={onOverlayHover} />\n )}\n {surfaces.toolbar && (\n <BlockActionsOverlay editor={editor} target={selectedTarget} host={host} actions={actions} surface=\"toolbar\" persistent />\n )}\n {alwaysHandles && <BlockHandles editor={editor} host={host} />}\n </>,\n host,\n )}\n <DragHandle\n editor={editor}\n onElementDragEnd={resetDragHandle}\n onNodeChange={trackDragTarget}\n computePositionConfig={dragHandlePosition}\n nested={dragHandleNested}\n className={cn(\n 'flex size-6 cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground data-[dragging=true]:cursor-grabbing',\n hoverHandleHidden && 'invisible! pointer-events-none!',\n )}\n >\n <span ref={handleContent} className=\"contents\">\n <Icon name=\"i-lucide-grip-vertical\" />\n </span>\n </DragHandle>\n </>\n )\n}\n\n// Nearest sibling with a layout box (a composite's hidden description/tags rows have none).\nfunction laidOutSibling(dom: Element, side: 'previous' | 'next'): DOMRect | null {\n for (let element = dom[`${side}ElementSibling`]; element; element = element[`${side}ElementSibling`]) {\n const rect = element.getBoundingClientRect()\n if (rect.height > 0) return rect\n }\n return null\n}\n"],"mappings":"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"}
@@ -1,11 +1,13 @@
1
+ import { BlockUiOptions } from "../../core/extension-points.js";
2
+ import "../../core/index.js";
1
3
  import { ReactFeature } from "../../react/EditorSurface.js";
2
4
  import "../../react/index.js";
3
5
  import { BlockActionsOverlay } from "./react/BlockActionsOverlay.js";
4
6
  import { BlockHandles } from "./react/BlockHandles.js";
5
7
  import { BlockUi } from "./react/BlockUi.js";
6
8
  //#region src/features/block-ui/react.d.ts
7
- /** The React block-ui feature: the drag handle (`@tiptap/extension-drag-handle-react`), permanent handles and hover actions with shadcn menus. */
8
- export declare function blockUiFeature(): ReactFeature;
9
+ /** The React block-ui feature: the drag handle (`@tiptap/extension-drag-handle-react`), permanent handles and the block actions (hover bar and/or selected-block toolbar, per `options.actions`) with shadcn menus. */
10
+ export declare function blockUiFeature(options?: BlockUiOptions): ReactFeature;
9
11
  //#endregion
10
12
  export { BlockActionsOverlay, BlockHandles, BlockUi };
11
13
  //# sourceMappingURL=react.d.ts.map
@@ -3,9 +3,9 @@ import { BlockActionsOverlay } from "./react/BlockActionsOverlay.js";
3
3
  import { BlockHandles } from "./react/BlockHandles.js";
4
4
  import { BlockUi } from "./react/BlockUi.js";
5
5
  //#region src/features/block-ui/react.ts
6
- /** The React block-ui feature: the drag handle (`@tiptap/extension-drag-handle-react`), permanent handles and hover actions with shadcn menus. */
7
- function blockUiFeature() {
8
- return blockUiFeatureCore({ overlay: BlockUi });
6
+ /** The React block-ui feature: the drag handle (`@tiptap/extension-drag-handle-react`), permanent handles and the block actions (hover bar and/or selected-block toolbar, per `options.actions`) with shadcn menus. */
7
+ function blockUiFeature(options) {
8
+ return blockUiFeatureCore({ overlay: BlockUi }, options);
9
9
  }
10
10
  //#endregion
11
11
  export { BlockActionsOverlay, BlockHandles, BlockUi, blockUiFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../../../src/features/block-ui/react.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { ComponentType } from 'react'\nimport type { ReactFeature } from '../../react'\nimport { blockUiFeatureCore } from './feature'\nimport { BlockUi } from './react/BlockUi'\n\nexport { BlockActionsOverlay } from './react/BlockActionsOverlay'\nexport { BlockHandles } from './react/BlockHandles'\nexport { BlockUi } from './react/BlockUi'\n\n/** The React block-ui feature: the drag handle (`@tiptap/extension-drag-handle-react`), permanent handles and hover actions with shadcn menus. */\nexport function blockUiFeature(): ReactFeature {\n return blockUiFeatureCore<ComponentType<{ editor: Editor }>>({ overlay: BlockUi })\n}\n"],"mappings":";;;;;;AAWA,SAAgB,iBAA+B;CAC7C,OAAO,mBAAsD,EAAE,SAAS,QAAQ,CAAC;AACnF"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../../../src/features/block-ui/react.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { ComponentType } from 'react'\nimport type { BlockUiOptions } from '../../core'\nimport type { ReactFeature } from '../../react'\nimport { blockUiFeatureCore } from './feature'\nimport { BlockUi } from './react/BlockUi'\n\nexport { BlockActionsOverlay } from './react/BlockActionsOverlay'\nexport { BlockHandles } from './react/BlockHandles'\nexport { BlockUi } from './react/BlockUi'\n\n/** The React block-ui feature: the drag handle (`@tiptap/extension-drag-handle-react`), permanent handles and the block actions (hover bar and/or selected-block toolbar, per `options.actions`) with shadcn menus. */\nexport function blockUiFeature(options?: BlockUiOptions): ReactFeature {\n return blockUiFeatureCore<ComponentType<{ editor: Editor }>>({ overlay: BlockUi }, options)\n}\n"],"mappings":";;;;;;AAYA,SAAgB,eAAe,SAAwC;CACrE,OAAO,mBAAsD,EAAE,SAAS,QAAQ,GAAG,OAAO;AAC5F"}
@@ -1,9 +1,11 @@
1
+ import { BlockUiOptions } from "../../core/extension-points.js";
2
+ import "../../core/index.js";
1
3
  import { VueFeature } from "../../vue/index.js";
2
4
  import _default from "./components/BlockActionsOverlay.vue.js";
3
5
  import _default$1 from "./components/BlockUi.vue.js";
4
6
  //#region src/features/block-ui/vue.d.ts
5
- /** The Vue block-ui feature: the Nuxt UI drag handle, permanent handles and hover actions. */
6
- export declare function blockUiFeature(): VueFeature;
7
+ /** The Vue block-ui feature: the Nuxt UI drag handle, permanent handles and the block actions (hover bar and/or selected-block toolbar, per `options.actions`). */
8
+ export declare function blockUiFeature(options?: BlockUiOptions): VueFeature;
7
9
  //#endregion
8
10
  export { _default as BlockActionsOverlay, _default$1 as BlockUi };
9
11
  //# sourceMappingURL=vue.d.ts.map
@@ -2,9 +2,9 @@ import { blockUiFeatureCore } from "./feature.js";
2
2
  import _sfc_main from "./components/BlockActionsOverlay.js";
3
3
  import _sfc_main$1 from "./components/BlockUi.js";
4
4
  //#region src/features/block-ui/vue.ts
5
- /** The Vue block-ui feature: the Nuxt UI drag handle, permanent handles and hover actions. */
6
- function blockUiFeature() {
7
- return blockUiFeatureCore({ overlay: _sfc_main$1 });
5
+ /** The Vue block-ui feature: the Nuxt UI drag handle, permanent handles and the block actions (hover bar and/or selected-block toolbar, per `options.actions`). */
6
+ function blockUiFeature(options) {
7
+ return blockUiFeatureCore({ overlay: _sfc_main$1 }, options);
8
8
  }
9
9
  //#endregion
10
10
  export { _sfc_main as BlockActionsOverlay, _sfc_main$1 as BlockUi, blockUiFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"vue.js","names":["BlockUi"],"sources":["../../../src/features/block-ui/vue.ts"],"sourcesContent":["import type { Component } from 'vue'\nimport type { VueFeature } from '../../vue'\nimport BlockUi from './components/BlockUi.vue'\nimport { blockUiFeatureCore } from './feature'\n\nexport { default as BlockActionsOverlay } from './components/BlockActionsOverlay.vue'\nexport { default as BlockUi } from './components/BlockUi.vue'\n\n/** The Vue block-ui feature: the Nuxt UI drag handle, permanent handles and hover actions. */\nexport function blockUiFeature(): VueFeature {\n return blockUiFeatureCore<Component>({ overlay: BlockUi })\n}\n"],"mappings":";;;;;AASA,SAAgB,iBAA6B;CAC3C,OAAO,mBAA8B,EAAE,SAASA,YAAQ,CAAC;AAC3D"}
1
+ {"version":3,"file":"vue.js","names":["BlockUi"],"sources":["../../../src/features/block-ui/vue.ts"],"sourcesContent":["import type { Component } from 'vue'\nimport type { BlockUiOptions } from '../../core'\nimport type { VueFeature } from '../../vue'\nimport BlockUi from './components/BlockUi.vue'\nimport { blockUiFeatureCore } from './feature'\n\nexport { default as BlockActionsOverlay } from './components/BlockActionsOverlay.vue'\nexport { default as BlockUi } from './components/BlockUi.vue'\n\n/** The Vue block-ui feature: the Nuxt UI drag handle, permanent handles and the block actions (hover bar and/or selected-block toolbar, per `options.actions`). */\nexport function blockUiFeature(options?: BlockUiOptions): VueFeature {\n return blockUiFeatureCore<Component>({ overlay: BlockUi }, options)\n}\n"],"mappings":";;;;;AAUA,SAAgB,eAAe,SAAsC;CACnE,OAAO,mBAA8B,EAAE,SAASA,YAAQ,GAAG,OAAO;AACpE"}
@@ -0,0 +1,27 @@
1
+ import { Translate } from "../../i18n/index.js";
2
+ import { Node } from "@tiptap/pm/model";
3
+ //#region src/features/composites/baskets.d.ts
4
+ /** A colour basket a Baustein can be put into; the host app defines the set (`compositeFeature({ baskets })`). */
5
+ export interface Basket {
6
+ id: string;
7
+ label: string;
8
+ /** CSS colour; the chrome dot and the row stripe use it. */
9
+ color: string;
10
+ }
11
+ /** Ids of the built-in baskets. */
12
+ export declare const BASKET_IDS: readonly ["red", "orange", "yellow", "green", "blue"];
13
+ /** The built-in baskets in the language of `t`; their colours are the `--sk-basket-<id>` CSS variables, which hosts override. Memoized per translator. */
14
+ export declare function defaultBaskets(t: Translate): readonly Basket[];
15
+ /** What carries a composite's meta: the node itself or a row read from it (`CompositeRow`). */
16
+ type MetaSource = Node | {
17
+ meta: Record<string, unknown>;
18
+ };
19
+ /** Id of the basket `source` (a composite node or its row) is in, or null. */
20
+ export declare function basketOf(source: MetaSource): string | null;
21
+ /** Whether the title of `source` (a composite node or its row) is hidden. */
22
+ export declare function titleHiddenOf(source: MetaSource): boolean;
23
+ /** The basket with id `id` among `baskets`; `undefined` for no id or an id the set does not offer. */
24
+ export declare function basketById(baskets: readonly Basket[], id: string | null | undefined): Basket | undefined;
25
+ //#endregion
26
+ export {};
27
+ //# sourceMappingURL=baskets.d.ts.map
@@ -0,0 +1,46 @@
1
+ import { createTranslator } from "../../i18n/index.js";
2
+ import { BASKET_KEY, TITLE_HIDDEN_KEY } from "./meta-keys.js";
3
+ //#region src/features/composites/baskets.ts
4
+ /** Ids of the built-in baskets. */
5
+ const BASKET_IDS = [
6
+ "red",
7
+ "orange",
8
+ "yellow",
9
+ "green",
10
+ "blue"
11
+ ];
12
+ /** The built-in baskets in the language of `t`; their colours are the `--sk-basket-<id>` CSS variables, which hosts override. Memoized per translator. */
13
+ function defaultBaskets(t) {
14
+ let baskets = DEFAULT_BASKETS.get(t);
15
+ if (!baskets) DEFAULT_BASKETS.set(t, baskets = BASKET_IDS.map((id) => ({
16
+ id,
17
+ label: t(`composites.basket.${id}`),
18
+ color: `var(--sk-basket-${id})`
19
+ })));
20
+ return baskets;
21
+ }
22
+ const DEFAULT_BASKETS = /* @__PURE__ */ new WeakMap();
23
+ /** The built-in baskets in the default language, for server-side and context-free code (`Composite`'s default option, an editor without a context). */
24
+ const fallbackBaskets = () => defaultBaskets(DEFAULT_TRANSLATE);
25
+ const DEFAULT_TRANSLATE = createTranslator();
26
+ function metaOf(source) {
27
+ const meta = "attrs" in source ? source.attrs.meta : source.meta;
28
+ return meta && typeof meta === "object" ? meta : {};
29
+ }
30
+ /** Id of the basket `source` (a composite node or its row) is in, or null. */
31
+ function basketOf(source) {
32
+ const basket = metaOf(source)[BASKET_KEY];
33
+ return typeof basket === "string" && basket ? basket : null;
34
+ }
35
+ /** Whether the title of `source` (a composite node or its row) is hidden. */
36
+ function titleHiddenOf(source) {
37
+ return metaOf(source)[TITLE_HIDDEN_KEY] === true;
38
+ }
39
+ /** The basket with id `id` among `baskets`; `undefined` for no id or an id the set does not offer. */
40
+ function basketById(baskets, id) {
41
+ return id ? baskets.find((basket) => basket.id === id) : void 0;
42
+ }
43
+ //#endregion
44
+ export { BASKET_IDS, basketById, basketOf, defaultBaskets, fallbackBaskets, titleHiddenOf };
45
+
46
+ //# sourceMappingURL=baskets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baskets.js","names":[],"sources":["../../../src/features/composites/baskets.ts"],"sourcesContent":["// Vue-free and server-importable: the colour baskets a Baustein can be put into, and how a node carries its basket and its hidden title.\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport { createTranslator, type Translate } from '../../i18n'\nimport { BASKET_KEY, TITLE_HIDDEN_KEY } from './meta-keys'\n\n/** A colour basket a Baustein can be put into; the host app defines the set (`compositeFeature({ baskets })`). */\nexport interface Basket {\n id: string\n label: string\n /** CSS colour; the chrome dot and the row stripe use it. */\n color: string\n}\n\n/** Ids of the built-in baskets. */\nexport const BASKET_IDS = ['red', 'orange', 'yellow', 'green', 'blue'] as const\n\n/** The built-in baskets in the language of `t`; their colours are the `--sk-basket-<id>` CSS variables, which hosts override. Memoized per translator. */\nexport function defaultBaskets(t: Translate): readonly Basket[] {\n let baskets = DEFAULT_BASKETS.get(t)\n if (!baskets) DEFAULT_BASKETS.set(t, baskets = BASKET_IDS.map(id => ({ id, label: t(`composites.basket.${id}`), color: `var(--sk-basket-${id})` })))\n return baskets\n}\n\nconst DEFAULT_BASKETS = new WeakMap<Translate, readonly Basket[]>()\n\n/** The built-in baskets in the default language, for server-side and context-free code (`Composite`'s default option, an editor without a context). */\nexport const fallbackBaskets = (): readonly Basket[] => defaultBaskets(DEFAULT_TRANSLATE)\n\nconst DEFAULT_TRANSLATE = createTranslator()\n\n/** What carries a composite's meta: the node itself or a row read from it (`CompositeRow`). */\ntype MetaSource = PMNode | { meta: Record<string, unknown> }\n\nfunction metaOf(source: MetaSource): Record<string, unknown> {\n const meta: unknown = 'attrs' in source ? source.attrs.meta : source.meta\n return meta && typeof meta === 'object' ? meta as Record<string, unknown> : {}\n}\n\n/** Id of the basket `source` (a composite node or its row) is in, or null. */\nexport function basketOf(source: MetaSource): string | null {\n const basket = metaOf(source)[BASKET_KEY]\n return typeof basket === 'string' && basket ? basket : null\n}\n\n/** Whether the title of `source` (a composite node or its row) is hidden. */\nexport function titleHiddenOf(source: MetaSource): boolean {\n return metaOf(source)[TITLE_HIDDEN_KEY] === true\n}\n\n/** The basket with id `id` among `baskets`; `undefined` for no id or an id the set does not offer. */\nexport function basketById(baskets: readonly Basket[], id: string | null | undefined): Basket | undefined {\n return id ? baskets.find(basket => basket.id === id) : undefined\n}\n"],"mappings":";;;;AAcA,MAAa,aAAa;CAAC;CAAO;CAAU;CAAU;CAAS;AAAM;;AAGrE,SAAgB,eAAe,GAAiC;CAC9D,IAAI,UAAU,gBAAgB,IAAI,CAAC;CACnC,IAAI,CAAC,SAAS,gBAAgB,IAAI,GAAG,UAAU,WAAW,KAAI,QAAO;EAAE;EAAI,OAAO,EAAE,qBAAqB,IAAI;EAAG,OAAO,mBAAmB,GAAG;CAAG,EAAE,CAAC;CACnJ,OAAO;AACT;AAEA,MAAM,kCAAkB,IAAI,QAAsC;;AAGlE,MAAa,wBAA2C,eAAe,iBAAiB;AAExF,MAAM,oBAAoB,iBAAiB;AAK3C,SAAS,OAAO,QAA6C;CAC3D,MAAM,OAAgB,WAAW,SAAS,OAAO,MAAM,OAAO,OAAO;CACrE,OAAO,QAAQ,OAAO,SAAS,WAAW,OAAkC,CAAC;AAC/E;;AAGA,SAAgB,SAAS,QAAmC;CAC1D,MAAM,SAAS,OAAO,MAAM,CAAC,CAAC;CAC9B,OAAO,OAAO,WAAW,YAAY,SAAS,SAAS;AACzD;;AAGA,SAAgB,cAAc,QAA6B;CACzD,OAAO,OAAO,MAAM,CAAC,CAAC,sBAAsB;AAC9C;;AAGA,SAAgB,WAAW,SAA4B,IAAmD;CACxG,OAAO,KAAK,QAAQ,MAAK,WAAU,OAAO,OAAO,EAAE,IAAI,KAAA;AACzD"}
@@ -0,0 +1,97 @@
1
+ import { basketOf } from "../baskets.js";
2
+ import { compositeBasketsOf } from "../nodes.js";
3
+ import { useUiKit } from "../../../vue/kit/use-ui-kit.js";
4
+ import { useEditorI18n } from "../../../vue/use-editor-i18n.js";
5
+ import { compositeOfRow } from "../rows.js";
6
+ import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, renderSlot, shallowRef, toDisplayString, unref, withCtx } from "vue";
7
+ //#region src/features/composites/components/CompositeBasketMenu.vue
8
+ const _hoisted_1 = ["aria-label"];
9
+ const _hoisted_2 = ["aria-checked", "onClick"];
10
+ const _hoisted_3 = { class: "truncate" };
11
+ const _hoisted_4 = ["aria-checked"];
12
+ const _hoisted_5 = { class: "truncate" };
13
+ /**
14
+ * Basket choice of a Baustein: the default slot (a button) opens a list of the editor's baskets (a dot in the basket's
15
+ * colour and its label) and „Kein Korb“. The menu is a popover, not a dropdown menu: a dropdown item cannot show a dot in
16
+ * an arbitrary CSS colour.
17
+ */
18
+ const option = "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm text-[var(--sk-fg)] transition-colors duration-150 hover:bg-[var(--sk-bg-elevated)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]";
19
+ const _sfc_main = /*@__PURE__*/ defineComponent({
20
+ __name: "CompositeBasketMenu",
21
+ props: {
22
+ editor: {},
23
+ row: {}
24
+ },
25
+ setup(__props) {
26
+ const props = __props;
27
+ const { Icon: UIcon, Popover: UPopover } = useUiKit();
28
+ const { t } = useEditorI18n();
29
+ const open = shallowRef(false);
30
+ function choose(basket) {
31
+ open.value = false;
32
+ const found = compositeOfRow(props.editor.state.doc, props.row);
33
+ if (found) props.editor.commands.setCompositeBasket(basket, found.pos);
34
+ }
35
+ return (_ctx, _cache) => {
36
+ return openBlock(), createBlock(unref(UPopover), {
37
+ open: open.value,
38
+ "onUpdate:open": _cache[1] || (_cache[1] = ($event) => open.value = $event),
39
+ content: {
40
+ side: "bottom",
41
+ align: "start",
42
+ sideOffset: 4,
43
+ onCloseAutoFocus: (event) => event.preventDefault()
44
+ },
45
+ ui: { content: "w-40 p-1" }
46
+ }, {
47
+ content: withCtx(() => [createElementVNode("div", {
48
+ role: "menu",
49
+ "aria-label": unref(t)("composites.basket.label")
50
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(compositeBasketsOf)(__props.editor), (basket) => {
51
+ return openBlock(), createElementBlock("button", {
52
+ key: basket.id,
53
+ type: "button",
54
+ role: "menuitemradio",
55
+ "aria-checked": unref(basketOf)(props.row) === basket.id,
56
+ class: normalizeClass(option),
57
+ onClick: ($event) => choose(basket.id)
58
+ }, [
59
+ createElementVNode("span", {
60
+ class: "size-2.5 shrink-0 rounded-full",
61
+ style: normalizeStyle({ backgroundColor: basket.color })
62
+ }, null, 4),
63
+ createElementVNode("span", _hoisted_3, toDisplayString(basket.label), 1),
64
+ unref(basketOf)(props.row) === basket.id ? (openBlock(), createBlock(unref(UIcon), {
65
+ key: 0,
66
+ name: "i-lucide-check",
67
+ class: "ml-auto size-3.5 shrink-0"
68
+ })) : createCommentVNode("v-if", true)
69
+ ], 8, _hoisted_2);
70
+ }), 128)), createElementVNode("button", {
71
+ type: "button",
72
+ role: "menuitemradio",
73
+ "aria-checked": unref(basketOf)(props.row) === null,
74
+ class: normalizeClass(option),
75
+ onClick: _cache[0] || (_cache[0] = ($event) => choose(null))
76
+ }, [
77
+ createVNode(unref(UIcon), {
78
+ name: "i-lucide-circle-dashed",
79
+ class: "size-3 shrink-0 text-[var(--sk-muted)]"
80
+ }),
81
+ createElementVNode("span", _hoisted_5, toDisplayString(unref(t)("composites.basket.none")), 1),
82
+ unref(basketOf)(props.row) === null ? (openBlock(), createBlock(unref(UIcon), {
83
+ key: 0,
84
+ name: "i-lucide-check",
85
+ class: "ml-auto size-3.5 shrink-0"
86
+ })) : createCommentVNode("v-if", true)
87
+ ], 8, _hoisted_4)], 8, _hoisted_1)]),
88
+ default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
89
+ _: 3
90
+ }, 8, ["open", "content"]);
91
+ };
92
+ }
93
+ });
94
+ //#endregion
95
+ export { _sfc_main as default };
96
+
97
+ //# sourceMappingURL=CompositeBasketMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompositeBasketMenu.js","names":["_openBlock","_createBlock","_unref","_withCtx","_createElementVNode","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle","_toDisplayString","_createCommentVNode","_createVNode","_renderSlot"],"sources":["../../../../src/features/composites/components/CompositeBasketMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Editor } from '@tiptap/core'\nimport { shallowRef } from 'vue'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { basketOf } from '../baskets'\nimport { compositeBasketsOf } from '../nodes'\nimport { compositeOfRow, type CompositeRow } from '../rows'\n\n/**\n * Basket choice of a Baustein: the default slot (a button) opens a list of the editor's baskets (a dot in the basket's\n * colour and its label) and „Kein Korb“. The menu is a popover, not a dropdown menu: a dropdown item cannot show a dot in\n * an arbitrary CSS colour.\n */\nconst props = defineProps<{ editor: Editor, row: CompositeRow }>()\n\nconst { Icon: UIcon, Popover: UPopover } = useUiKit()\nconst { t } = useEditorI18n()\n\nconst open = shallowRef(false)\n\n\nfunction choose(basket: string | null) {\n open.value = false\n const found = compositeOfRow(props.editor.state.doc, props.row)\n if (found) props.editor.commands.setCompositeBasket(basket, found.pos)\n}\n\nconst option = 'flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm text-[var(--sk-fg)] transition-colors duration-150 hover:bg-[var(--sk-bg-elevated)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]'\n</script>\n\n<template>\n <UPopover\n v-model:open=\"open\"\n :content=\"{ side: 'bottom', align: 'start', sideOffset: 4, onCloseAutoFocus: (event: Event) => event.preventDefault() }\"\n :ui=\"{ content: 'w-40 p-1' }\"\n >\n <slot />\n <template #content>\n <div role=\"menu\" :aria-label=\"t('composites.basket.label')\">\n <button\n v-for=\"basket in compositeBasketsOf(editor)\"\n :key=\"basket.id\"\n type=\"button\"\n role=\"menuitemradio\"\n :aria-checked=\"basketOf(props.row) === basket.id\"\n :class=\"option\"\n @click=\"choose(basket.id)\"\n >\n <span class=\"size-2.5 shrink-0 rounded-full\" :style=\"{ backgroundColor: basket.color }\" />\n <span class=\"truncate\">{{ basket.label }}</span>\n <UIcon v-if=\"basketOf(props.row) === basket.id\" name=\"i-lucide-check\" class=\"ml-auto size-3.5 shrink-0\" />\n </button>\n <button type=\"button\" role=\"menuitemradio\" :aria-checked=\"basketOf(props.row) === null\" :class=\"option\" @click=\"choose(null)\">\n <UIcon name=\"i-lucide-circle-dashed\" class=\"size-3 shrink-0 text-[var(--sk-muted)]\" />\n <span class=\"truncate\">{{ t('composites.basket.none') }}</span>\n <UIcon v-if=\"basketOf(props.row) === null\" name=\"i-lucide-check\" class=\"ml-auto size-3.5 shrink-0\" />\n </button>\n </div>\n </template>\n </UPopover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;AA4BA,MAAM,SAAS;;;;;;;;EAdf,MAAM,QAAQ;EAEd,MAAM,EAAE,MAAM,OAAO,SAAS,aAAa,SAAS;EACpD,MAAM,EAAE,MAAM,cAAc;EAE5B,MAAM,OAAO,WAAW,KAAK;EAG7B,SAAS,OAAO,QAAuB;GACrC,KAAK,QAAQ;GACb,MAAM,QAAQ,eAAe,MAAM,OAAO,MAAM,KAAK,MAAM,GAAG;GAC9D,IAAI,OAAO,MAAM,OAAO,SAAS,mBAAmB,QAAQ,MAAM,GAAG;EACvE;;GAME,OAAAA,UAAA,GAAAC,YA4BWC,MAAA,QAAA,GAAA;IA3BD,MAAM,KAAA;IAAA,iBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAI,QAAA;IACjB,SAAO;KAAA,MAAA;KAAA,OAAA;KAAA,YAAA;KAAA,mBAAsE,UAAiB,MAAM,eAAc;IAAA;IAClH,IAAI,EAAA,SAAA,WAAA;;IAGM,SAAOC,cAoBV,CAnBNC,mBAmBM,OAAA;KAnBD,MAAK;KAAQ,cAAYF,MAAA,CAAA,CAAC,CAAA,yBAAA;IAC7B,GAAA,EAAAF,UAAA,IAAA,GAAAK,mBAYSC,UAAA,MAAAC,WAXUL,MAAA,kBAAA,CAAkB,CAAC,QAAA,MAAM,IAAnC,WAAM;KADf,OAAAF,UAAA,GAAAK,mBAYS,UAAA;MAVN,KAAK,OAAO;MACb,MAAK;MACL,MAAK;MACJ,gBAAcH,MAAA,QAAA,CAAQ,CAAC,MAAM,GAAG,MAAM,OAAO;MAC7C,OAAKM,eAAE,MAAM;MACb,UAAK,WAAE,OAAO,OAAO,EAAE;;MAExBJ,mBAA0F,QAAA;OAApF,OAAM;OAAkC,OAAKK,eAAA,EAAA,iBAAqB,OAAO,MAAK,CAAA;;MACpFL,mBAAgD,QAAhD,YAAgDM,gBAAtB,OAAO,KAAK,GAAA,CAAA;MACzBR,MAAA,QAAA,CAAQ,CAAC,MAAM,GAAG,MAAM,OAAO,MAA5CF,UAAA,GAAAC,YAA0GC,MAAA,KAAA,GAAA;;OAA1D,MAAK;OAAiB,OAAM;;;IAE9E,CAAA,GAAA,GAAA,IAAAE,mBAIS,UAAA;KAJD,MAAK;KAAS,MAAK;KAAiB,gBAAcF,MAAA,QAAA,CAAQ,CAAC,MAAM,GAAG,MAAA;KAAa,OAAKM,eAAE,MAAM;KAAG,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,OAAM,IAAA;;KACpHI,YAAsFV,MAAA,KAAA,GAAA;MAA/E,MAAK;MAAyB,OAAM;;KAC3CE,mBAA+D,QAA/D,YAA+DM,gBAArCR,MAAA,CAAA,CAAC,CAAA,wBAAA,CAAA,GAAA,CAAA;KACdA,MAAA,QAAA,CAAQ,CAAC,MAAM,GAAG,MAAA,QAA/BF,UAAA,GAAAC,YAAqGC,MAAA,KAAA,GAAA;;MAA1D,MAAK;MAAiB,OAAM;;;IAnB7E,SAAAC,cAAQ,CAARU,WAAQ,KAAA,QAAA,SAAA,CAAA,CAAA"}
@@ -1,4 +1,6 @@
1
1
  import { startBlockDrag } from "../../../core/block-drag.js";
2
+ import { basketById, basketOf, titleHiddenOf } from "../baskets.js";
3
+ import { compositeBasketsOf } from "../nodes.js";
2
4
  import { useUiKit } from "../../../vue/kit/use-ui-kit.js";
3
5
  import { useEditorSettings } from "../../../vue/settings.js";
4
6
  import { useEditorI18n } from "../../../vue/use-editor-i18n.js";
@@ -9,9 +11,10 @@ import { rowStatus } from "../meta-display.js";
9
11
  import { useStoreRef } from "../../../vue/store-ref.js";
10
12
  import { useCompositeAnchors } from "../use-composite-anchors.js";
11
13
  import { useCompositeRows } from "../use-composite-rows.js";
12
- import _sfc_main$1 from "./CompositeDetails.js";
13
- import _sfc_main$2 from "./CompositeStatusMenu.js";
14
- import _sfc_main$3 from "./CompositeTagsEditor.js";
14
+ import _sfc_main$1 from "./CompositeBasketMenu.js";
15
+ import _sfc_main$2 from "./CompositeDetails.js";
16
+ import _sfc_main$3 from "./CompositeStatusMenu.js";
17
+ import _sfc_main$4 from "./CompositeTagsEditor.js";
15
18
  import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, shallowRef, toDisplayString, unref, watch, withCtx, withKeys, withModifiers } from "vue";
16
19
  //#region src/features/composites/components/CompositeChrome.vue
17
20
  const _hoisted_1 = { class: "absolute left-0 top-0 h-0 w-0" };
@@ -22,17 +25,24 @@ const _hoisted_2 = [
22
25
  "onDragstart"
23
26
  ];
24
27
  const _hoisted_3 = ["onMouseenter"];
25
- const _hoisted_4 = [
28
+ const _hoisted_4 = ["aria-label", "title"];
29
+ const _hoisted_5 = [
30
+ "aria-label",
31
+ "title",
32
+ "onClick"
33
+ ];
34
+ const _hoisted_6 = ["title"];
35
+ const _hoisted_7 = [
26
36
  "aria-expanded",
27
37
  "aria-label",
28
38
  "title",
29
39
  "onClick"
30
40
  ];
31
- const _hoisted_5 = ["aria-label"];
32
- const _hoisted_6 = { class: "truncate" };
33
- const _hoisted_7 = ["aria-label", "onClick"];
34
- const _hoisted_8 = ["aria-label", "title"];
35
- const _hoisted_9 = { class: "w-64 p-3" };
41
+ const _hoisted_8 = ["aria-label"];
42
+ const _hoisted_9 = { class: "truncate" };
43
+ const _hoisted_10 = ["aria-label", "onClick"];
44
+ const _hoisted_11 = ["aria-label", "title"];
45
+ const _hoisted_12 = { class: "w-64 p-3" };
36
46
  /**
37
47
  * Chrome of every composite, laid over the editor (mounted by the composites feature): on the title line the status
38
48
  * chip and one chip per tag (with a `+` chip to add tags), and on the front the kind icon. The icon is a button that
@@ -102,7 +112,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
102
112
  }
103
113
  /** Chips start right after the title's last character and run on to the editor's right edge. */
104
114
  const expanded = useStoreRef(() => props.editor.storage.composite.expanded);
115
+ const revealedTitles = useStoreRef(() => props.editor.storage.composite.revealedTitles);
105
116
  const placed = computed(() => {
117
+ const baskets = compositeBasketsOf(props.editor);
106
118
  let hiddenUntil = -1;
107
119
  return rows.value.flatMap((row) => {
108
120
  if (row.pos < hiddenUntil) return [];
@@ -111,19 +123,23 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
111
123
  if (!open) hiddenUntil = row.end;
112
124
  const anchor = anchors.value.get(row.key);
113
125
  if (!anchor) return [];
114
- const left = anchor.lineEnd + (anchor.titleEmpty ? 116 : 12);
126
+ const titleHidden = titleHiddenOf(row);
127
+ const inStrip = titleHidden && !(row.id && revealedTitles.value.has(row.id)) && anchor.toggleSize > 0;
128
+ const left = inStrip ? anchor.toggleLeft + anchor.toggleSize + 6 : anchor.lineEnd + (anchor.titleEmpty ? 116 : 12);
115
129
  return [{
116
130
  row,
117
131
  anchor,
118
132
  left,
119
- top: anchor.lastCenter - ROW_HEIGHT / 2,
133
+ top: (inStrip ? anchor.toggleTop + anchor.toggleSize / 2 : anchor.lastCenter) - ROW_HEIGHT / 2,
120
134
  width: Math.max((frame.value?.right ?? anchor.right) - left, 120),
121
135
  status: rowStatus(row, t),
122
136
  derived: derived && {
123
137
  stale: derived.stale,
124
138
  open,
125
139
  toggleable: !!row.id
126
- }
140
+ },
141
+ basket: basketById(baskets, basketOf(row)) ?? null,
142
+ titleHidden
127
143
  }];
128
144
  });
129
145
  });
@@ -133,6 +149,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
133
149
  function removeTag(row, tag) {
134
150
  setCompositeTags(props.editor, row, row.tags.filter((candidate) => candidate !== tag));
135
151
  }
152
+ function toggleTitleHidden(row) {
153
+ const found = compositeOfRow(props.editor.state.doc, row);
154
+ if (found) props.editor.commands.setCompositeTitleHidden(!titleHiddenOf(row), found.pos);
155
+ }
136
156
  const chipButton = `${chip} transition-colors duration-150 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]`;
137
157
  /** Scale and fade in from the icon (`transform-origin` is Reka's), a bit longer than Nuxt UI's default; `composites.css` defines the keyframes and the reduced-motion override. */
138
158
  const detailsPopoverUi = { content: "composite-popover data-[state=open]:animate-[composite-pop-in_160ms_var(--ease-out)] data-[state=closed]:animate-[composite-pop-out_120ms_var(--ease-out)]" };
@@ -150,7 +170,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
150
170
  },
151
171
  ui: detailsPopoverUi
152
172
  }, {
153
- content: withCtx(() => [createVNode(_sfc_main$1, {
173
+ content: withCtx(() => [createVNode(_sfc_main$2, {
154
174
  editor: __props.editor,
155
175
  row: item.row,
156
176
  editable: editable.value
@@ -184,7 +204,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
184
204
  class: "size-3.5"
185
205
  }, null, 8, ["name"]))], 46, _hoisted_2)]),
186
206
  _: 2
187
- }, 1024)) : createCommentVNode("v-if", true), item.status || item.derived || item.row.tagsVisible && (item.row.tags.length || editable.value) ? (openBlock(), createElementBlock("div", {
207
+ }, 1024)) : createCommentVNode("v-if", true), editable.value || item.basket || item.status || item.derived || item.row.tagsVisible && item.row.tags.length ? (openBlock(), createElementBlock("div", {
188
208
  key: 1,
189
209
  class: "absolute z-10 flex items-center gap-px overflow-hidden rounded-md bg-[var(--sk-bg)]",
190
210
  style: normalizeStyle({
@@ -196,7 +216,43 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
196
216
  onMouseenter: ($event) => chipsHoveredKey.value = item.row.key,
197
217
  onMouseleave: _cache[1] || (_cache[1] = ($event) => chipsHoveredKey.value = null)
198
218
  }, [
199
- item.derived ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
219
+ editable.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(_sfc_main$1, {
220
+ editor: __props.editor,
221
+ row: item.row
222
+ }, {
223
+ default: withCtx(() => [createElementVNode("button", {
224
+ type: "button",
225
+ class: normalizeClass(chipButton),
226
+ "aria-label": unref(t)("composites.basket.label"),
227
+ title: item.basket ? `${unref(t)("composites.basket.label")}: ${item.basket.label}` : unref(t)("composites.basket.label")
228
+ }, [item.basket ? (openBlock(), createElementBlock("span", {
229
+ key: 0,
230
+ class: "size-2.5 rounded-full",
231
+ style: normalizeStyle({ backgroundColor: item.basket.color })
232
+ }, null, 4)) : (openBlock(), createBlock(unref(UIcon), {
233
+ key: 1,
234
+ name: "i-lucide-circle-dashed",
235
+ class: "size-3.5"
236
+ }))], 8, _hoisted_4)]),
237
+ _: 2
238
+ }, 1032, ["editor", "row"]), createElementVNode("button", {
239
+ type: "button",
240
+ class: normalizeClass(chipButton),
241
+ "aria-label": unref(t)(item.titleHidden ? "composites.titleHidden.show" : "composites.titleHidden.hide"),
242
+ title: unref(t)(item.titleHidden ? "composites.titleHidden.show" : "composites.titleHidden.hide"),
243
+ onClick: ($event) => toggleTitleHidden(item.row)
244
+ }, [createVNode(unref(UIcon), {
245
+ name: item.titleHidden ? "i-lucide-eye" : "i-lucide-eye-off",
246
+ class: "size-3.5"
247
+ }, null, 8, ["name"])], 8, _hoisted_5)], 64)) : item.basket ? (openBlock(), createElementBlock("span", {
248
+ key: 1,
249
+ class: normalizeClass(chip),
250
+ title: item.basket.label
251
+ }, [createElementVNode("span", {
252
+ class: "size-2.5 rounded-full",
253
+ style: normalizeStyle({ backgroundColor: item.basket.color })
254
+ }, null, 4)], 8, _hoisted_6)) : createCommentVNode("v-if", true),
255
+ item.derived ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
200
256
  item.derived.toggleable ? (openBlock(), createElementBlock("button", {
201
257
  key: 0,
202
258
  type: "button",
@@ -208,7 +264,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
208
264
  }, [createVNode(unref(UIcon), {
209
265
  name: item.derived.open ? "i-lucide-chevron-down" : "i-lucide-chevron-right",
210
266
  class: "size-3.5"
211
- }, null, 8, ["name"])], 8, _hoisted_4)) : createCommentVNode("v-if", true),
267
+ }, null, 8, ["name"])], 8, _hoisted_7)) : createCommentVNode("v-if", true),
212
268
  createElementVNode("span", { class: normalizeClass(chip) }, [createVNode(unref(UIcon), {
213
269
  name: "i-lucide-git-branch",
214
270
  class: "size-3.5"
@@ -221,7 +277,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
221
277
  class: "size-3.5"
222
278
  }), createTextVNode(toDisplayString(unref(t)("composites.derivation.stale")), 1)], 2)) : createCommentVNode("v-if", true)
223
279
  ], 64)) : createCommentVNode("v-if", true),
224
- item.status ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [editable.value ? (openBlock(), createBlock(_sfc_main$2, {
280
+ item.status ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [editable.value ? (openBlock(), createBlock(_sfc_main$3, {
225
281
  key: 0,
226
282
  editor: __props.editor,
227
283
  row: item.row
@@ -233,7 +289,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
233
289
  }, [createVNode(unref(UIcon), {
234
290
  name: item.status.icon,
235
291
  class: normalizeClass(["size-3.5", item.status.color])
236
- }, null, 8, ["name", "class"]), createTextVNode(toDisplayString(item.status.label), 1)], 8, _hoisted_5)]),
292
+ }, null, 8, ["name", "class"]), createTextVNode(toDisplayString(item.status.label), 1)], 8, _hoisted_8)]),
237
293
  _: 2
238
294
  }, 1032, ["editor", "row"])) : (openBlock(), createElementBlock("span", {
239
295
  key: 1,
@@ -246,7 +302,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
246
302
  return openBlock(), createElementBlock("span", {
247
303
  key: tag,
248
304
  class: normalizeClass([chip, "group max-w-40 gap-0"])
249
- }, [createElementVNode("span", _hoisted_6, "#" + toDisplayString(tag), 1), editable.value ? (openBlock(), createElementBlock("button", {
305
+ }, [createElementVNode("span", _hoisted_9, "#" + toDisplayString(tag), 1), editable.value ? (openBlock(), createElementBlock("button", {
250
306
  key: 0,
251
307
  type: "button",
252
308
  class: "flex h-4 w-0 shrink-0 items-center justify-center overflow-hidden rounded-sm opacity-0 transition-all duration-150 group-hover:ml-1 group-hover:w-4 group-hover:opacity-100 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:ml-1 focus-visible:w-4 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-[var(--sk-primary)]",
@@ -255,10 +311,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
255
311
  }, [createVNode(unref(UIcon), {
256
312
  name: "i-lucide-x",
257
313
  class: "size-3"
258
- })], 8, _hoisted_7)) : createCommentVNode("v-if", true)], 2);
314
+ })], 8, _hoisted_10)) : createCommentVNode("v-if", true)], 2);
259
315
  }), 128)),
260
316
  editable.value && item.row.tagsVisible ? (openBlock(), createBlock(unref(UPopover), {
261
- key: 2,
317
+ key: 4,
262
318
  content: {
263
319
  side: "bottom",
264
320
  align: "start",
@@ -266,7 +322,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
266
322
  onCloseAutoFocus: (event) => event.preventDefault()
267
323
  }
268
324
  }, {
269
- content: withCtx(() => [createElementVNode("div", _hoisted_9, [createVNode(_sfc_main$3, {
325
+ content: withCtx(() => [createElementVNode("div", _hoisted_12, [createVNode(_sfc_main$4, {
270
326
  editor: __props.editor,
271
327
  row: item.row
272
328
  }, null, 8, ["editor", "row"])])]),
@@ -278,7 +334,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
278
334
  }, [createVNode(unref(UIcon), {
279
335
  name: "i-lucide-plus",
280
336
  class: "size-3.5"
281
- })], 8, _hoisted_8)]),
337
+ })], 8, _hoisted_11)]),
282
338
  _: 2
283
339
  }, 1032, ["content"])) : createCommentVNode("v-if", true)
284
340
  ], 44, _hoisted_3)) : createCommentVNode("v-if", true)], 64);