@ecsplico/editor 3.1.1 → 3.3.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 (267) hide show
  1. package/CHANGELOG.md +42 -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 +1 -1
  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 +1 -1
  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/CompositeView.js +21 -2
  96. package/dist/features/composites/components/CompositeView.js.map +1 -1
  97. package/dist/features/composites/components/DerivationBadge.js +12 -3
  98. package/dist/features/composites/components/DerivationBadge.js.map +1 -1
  99. package/dist/features/composites/components/FocusChip.js +53 -0
  100. package/dist/features/composites/components/FocusChip.js.map +1 -0
  101. package/dist/features/composites/components/FocusChip.vue.d.ts +14 -0
  102. package/dist/features/composites/components/SettingsEditingTab.js +40 -4
  103. package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
  104. package/dist/features/composites/derivation.d.ts +2 -1
  105. package/dist/features/composites/derivation.js +5 -1
  106. package/dist/features/composites/derivation.js.map +1 -1
  107. package/dist/features/composites/derived-chrome.js +13 -3
  108. package/dist/features/composites/derived-chrome.js.map +1 -1
  109. package/dist/features/composites/feature.d.ts +7 -1
  110. package/dist/features/composites/feature.js +107 -23
  111. package/dist/features/composites/feature.js.map +1 -1
  112. package/dist/features/composites/focus.d.ts +38 -0
  113. package/dist/features/composites/focus.js +86 -0
  114. package/dist/features/composites/focus.js.map +1 -0
  115. package/dist/features/composites/index.d.ts +7 -3
  116. package/dist/features/composites/index.js +7 -3
  117. package/dist/features/composites/kinds.d.ts +6 -1
  118. package/dist/features/composites/kinds.js.map +1 -1
  119. package/dist/features/composites/merge.d.ts +24 -0
  120. package/dist/features/composites/merge.js +47 -0
  121. package/dist/features/composites/merge.js.map +1 -0
  122. package/dist/features/composites/meta-keys.d.ts +4 -0
  123. package/dist/features/composites/meta-keys.js +8 -4
  124. package/dist/features/composites/meta-keys.js.map +1 -1
  125. package/dist/features/composites/nodes.d.ts +15 -2
  126. package/dist/features/composites/nodes.js +61 -5
  127. package/dist/features/composites/nodes.js.map +1 -1
  128. package/dist/features/composites/outline.d.ts +4 -0
  129. package/dist/features/composites/outline.js +3 -0
  130. package/dist/features/composites/outline.js.map +1 -1
  131. package/dist/features/composites/react/CompositeBasketMenu.js +88 -0
  132. package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -0
  133. package/dist/features/composites/react/CompositeChrome.js +52 -4
  134. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  135. package/dist/features/composites/react/CompositeView.js +15 -2
  136. package/dist/features/composites/react/CompositeView.js.map +1 -1
  137. package/dist/features/composites/react/DerivationBadge.js +10 -1
  138. package/dist/features/composites/react/DerivationBadge.js.map +1 -1
  139. package/dist/features/composites/react/FocusChip.d.ts +11 -0
  140. package/dist/features/composites/react/FocusChip.js +50 -0
  141. package/dist/features/composites/react/FocusChip.js.map +1 -0
  142. package/dist/features/composites/react/SettingsEditingTab.js +36 -1
  143. package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
  144. package/dist/features/composites/react.d.ts +2 -1
  145. package/dist/features/composites/react.js +3 -1
  146. package/dist/features/composites/react.js.map +1 -1
  147. package/dist/features/composites/schema.d.ts +5 -3
  148. package/dist/features/composites/schema.js +8 -4
  149. package/dist/features/composites/schema.js.map +1 -1
  150. package/dist/features/composites/split.d.ts +62 -0
  151. package/dist/features/composites/split.js +172 -0
  152. package/dist/features/composites/split.js.map +1 -0
  153. package/dist/features/composites/vue.d.ts +4 -3
  154. package/dist/features/composites/vue.js +7 -5
  155. package/dist/features/composites/vue.js.map +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 +21 -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 +7 -0
  185. package/dist/i18n/de/tree.js.map +1 -1
  186. package/dist/i18n/de.d.ts +57 -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 +21 -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 +7 -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 +1 -1
  223. package/dist/nuxt/module.d.ts +114 -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 +5 -1
  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 +4 -75
  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 +41 -0
  245. package/dist/tree/DocumentTree.js +246 -80
  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 +164 -32
  250. package/dist/tree/react/DocumentTree.js.map +1 -1
  251. package/dist/tree/tree-host.js +41 -2
  252. package/dist/tree/tree-host.js.map +1 -1
  253. package/dist/tree/tree-items.js +53 -5
  254. package/dist/tree/tree-items.js.map +1 -1
  255. package/dist/tree/tree-model.js +122 -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 +9 -1
  265. package/dist/vue/compose.js +5 -1
  266. package/dist/vue/compose.js.map +1 -1
  267. package/package.json +21 -1
@@ -1,4 +1,25 @@
1
1
  /* Styles of the composite feature (`@ecsplico/editor/composites`); import after `core.css`. */
2
+ /* Colour baskets (`compositeFeature({ baskets })`): the default set's colours, light and dark like `tokens.css` (the host sets
3
+ `.dark`). Declared under `:where()` (specificity 0), a host's rule always wins; a custom basket brings its own `color`.
4
+ `--sk-kind-tone-mix` is how strongly a kind's tone (`CompositeKind.chrome.tone`) tints the Baustein surface. */
5
+ :where(:root) {
6
+ --sk-kind-tone-mix: 8%;
7
+ --sk-basket-red: #ef4444;
8
+ --sk-basket-orange: #f97316;
9
+ --sk-basket-yellow: #eab308;
10
+ --sk-basket-green: #22c55e;
11
+ --sk-basket-blue: #3b82f6;
12
+ }
13
+
14
+ :where(.dark) {
15
+ --sk-kind-tone-mix: 14%;
16
+ --sk-basket-red: #f87171;
17
+ --sk-basket-orange: #fb923c;
18
+ --sk-basket-yellow: #facc15;
19
+ --sk-basket-green: #4ade80;
20
+ --sk-basket-blue: #60a5fa;
21
+ }
22
+
2
23
  /* Composite block: title, then description and tags row (data, hidden: the chips and the details popover of
3
24
  `CompositeChrome` show and edit them), then the body. */
4
25
  @layer components {
@@ -8,6 +29,22 @@
8
29
  padding-left: 1.25rem;
9
30
  border-left: 2px solid var(--sk-border);
10
31
  }
32
+ /* Kind tone: the node view sets `data-kind-tone` and `--sk-kind-tone` on a Baustein whose kind has `chrome.tone`; kinds without one are untouched.
33
+ Declared before the basket stripe, which wins on the border when both apply. */
34
+ .tiptap .composite[data-kind-tone] {
35
+ background: color-mix(in oklab, var(--sk-kind-tone) var(--sk-kind-tone-mix), transparent);
36
+ border-left-color: var(--sk-kind-tone);
37
+ }
38
+ /* The node view sets `--sk-basket-color` of a composite in a colour basket (`compositeFeature({ baskets })`); the colours of the default set are the tokens above. */
39
+ /* Basket stripe: the border takes the basket's colour; the inset shadow thickens it at every nesting depth without moving content. */
40
+ .tiptap .composite[data-basket] {
41
+ border-left-color: var(--sk-basket-color, var(--sk-border));
42
+ box-shadow: inset 2px 0 0 var(--sk-basket-color, transparent);
43
+ }
44
+ /* Hidden title (`meta.titleHidden`, until a caret enters it): the title is gone and a strip keeps the chrome row (basket, show
45
+ title, status and tags; `CompositeChrome`) and the kind icon clear of the body. */
46
+ .tiptap .composite[data-title-hidden] { padding-top: 1.75rem; }
47
+ .tiptap .composite[data-title-hidden] > .composite__content > .composite-title { display: none; }
11
48
  .tiptap .composite .composite { margin: 1em 0; }
12
49
  .tiptap .composite .composite .composite { margin: 0.75em 0; padding-left: 1rem; border-left-width: 1px; }
13
50
  /* Derived Baustein (has a `meta.derivation`) that is not opened: a short faded preview. The content stays laid out and
@@ -45,6 +82,10 @@
45
82
  /* Description and tags rows are data only: the chips and the details popover of `CompositeChrome` show and edit them. */
46
83
  .tiptap .composite-description,
47
84
  .tiptap .composite-tags { display: none; }
85
+ /* Focus mode (`focusComposite`): the decorations of `CompositeFocus` hide every sibling of the focused Baustein
86
+ (`sk-focus-target`) and of each ancestor (`sk-focus-ancestor`). An ancestor keeps its title (its description and tags
87
+ rows are hidden above anyway; its title, description and tags are not siblings in the sense of the decorations). */
88
+ .tiptap .sk-focus-hidden { display: none !important; }
48
89
  /* Placeholder extension marks an empty title `is-empty`; the text is the kind's, set by CompositeView. */
49
90
  .tiptap .composite-title.is-empty::before {
50
91
  color: var(--sk-fg-dimmed);
@@ -1,63 +1,83 @@
1
+ import { findBlockById } from "../core/schema/block-ids.js";
2
+ import { blockTransferOf, readBlockTransfer, writeBlockTransfer } from "../core/block-transfer.js";
3
+ import { basketById } from "../features/composites/baskets.js";
1
4
  import { useUiKit } from "../vue/kit/use-ui-kit.js";
2
5
  import { useEditorSettings } from "../vue/settings.js";
3
6
  import { useEditorI18n } from "../vue/use-editor-i18n.js";
4
- import { DRAG_MIME } from "./tree-items.js";
7
+ import { DRAG_MIME, focusCrumbs, itemBasket } from "./tree-items.js";
5
8
  import { rowOf } from "./tree-model.js";
6
9
  import { useTreeModel } from "./use-tree-model.js";
7
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeModels, normalizeClass, openBlock, renderSlot, toDisplayString, unref, useModel, withCtx, withKeys, withModifiers } from "vue";
10
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeModels, normalizeClass, normalizeStyle, openBlock, renderList, renderSlot, toDisplayString, unref, useModel, withCtx, withKeys, withModifiers } from "vue";
8
11
  //#region src/tree/DocumentTree.vue
9
12
  const _hoisted_1 = { class: "flex flex-col gap-2" };
10
- const _hoisted_2 = { class: "flex items-center justify-end" };
11
- const _hoisted_3 = { class: "inline-flex" };
12
- const _hoisted_4 = {
13
+ const _hoisted_2 = { class: "flex items-center gap-1" };
14
+ const _hoisted_3 = ["aria-label"];
15
+ const _hoisted_4 = ["aria-checked", "onClick"];
16
+ const _hoisted_5 = { class: "truncate" };
17
+ const _hoisted_6 = { class: "truncate" };
18
+ const _hoisted_7 = { class: "flex items-center justify-end" };
19
+ const _hoisted_8 = { class: "inline-flex" };
20
+ const _hoisted_9 = {
13
21
  key: 0,
14
22
  class: "flex items-center"
15
23
  };
16
- const _hoisted_5 = {
24
+ const _hoisted_10 = {
17
25
  key: 1,
18
26
  class: "flex flex-col gap-1"
19
27
  };
20
- const _hoisted_6 = {
28
+ const _hoisted_11 = {
21
29
  key: 0,
22
30
  class: "px-0.5 text-xs text-[var(--sk-danger)]",
23
31
  role: "alert"
24
32
  };
25
- const _hoisted_7 = {
33
+ const _hoisted_12 = {
26
34
  key: 2,
35
+ class: "flex flex-wrap items-center gap-0.5 text-xs"
36
+ };
37
+ const _hoisted_13 = {
38
+ key: 0,
39
+ class: "min-w-0 truncate px-1.5 font-medium",
40
+ "aria-current": "location"
41
+ };
42
+ const _hoisted_14 = {
43
+ key: 3,
27
44
  class: "px-2.5 py-1.5 text-sm text-[var(--sk-muted)]"
28
45
  };
29
- const _hoisted_8 = { class: "w-full" };
30
- const _hoisted_9 = [
46
+ const _hoisted_15 = { class: "w-full" };
47
+ const _hoisted_16 = [
31
48
  "draggable",
32
49
  "onDragstart",
33
50
  "onDragover",
34
51
  "onDragleave",
35
52
  "onDrop"
36
53
  ];
37
- const _hoisted_10 = {
54
+ const _hoisted_17 = {
38
55
  key: 1,
39
56
  class: "size-3.5 shrink-0"
40
57
  };
41
- const _hoisted_11 = {
58
+ const _hoisted_18 = {
42
59
  key: 2,
43
60
  class: "flex min-w-0 flex-1 flex-col gap-0.5"
44
61
  };
45
- const _hoisted_12 = ["title"];
46
- const _hoisted_13 = { class: "rounded-sm bg-[color-mix(in_oklab,var(--sk-primary)_20%,transparent)] text-inherit" };
47
- const _hoisted_14 = { class: "flex opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 has-data-[state=open]:opacity-100" };
48
- const _hoisted_15 = {
62
+ const _hoisted_19 = ["title", "aria-label"];
63
+ const _hoisted_20 = ["title"];
64
+ const _hoisted_21 = { class: "rounded-sm bg-[color-mix(in_oklab,var(--sk-primary)_20%,transparent)] text-inherit" };
65
+ const _hoisted_22 = { class: "flex opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 has-data-[state=open]:opacity-100" };
66
+ const _hoisted_23 = {
49
67
  key: 0,
50
68
  class: "px-2 pt-0.5 text-xs text-[var(--sk-danger)]",
51
69
  role: "status"
52
70
  };
53
- const _hoisted_16 = {
54
- key: 4,
71
+ const _hoisted_24 = {
72
+ key: 5,
55
73
  class: "px-2.5 py-1.5 text-sm text-[var(--sk-muted)]"
56
74
  };
57
- const _hoisted_17 = {
58
- key: 5,
75
+ const _hoisted_25 = {
76
+ key: 6,
59
77
  class: "px-2.5 py-1.5 text-sm text-[var(--sk-muted)]"
60
78
  };
79
+ const basketOption = "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)]";
80
+ /** The breadcrumb of the focus: the document (first crumb, leaves focus) and the Bausteine down to the focused one. */
61
81
  const _sfc_main = /*@__PURE__*/ defineComponent({
62
82
  __name: "DocumentTree",
63
83
  props: /*@__PURE__*/ mergeModels({
@@ -73,7 +93,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
73
93
  /** The folder new documents, folders and host imports go to. Reset to `''` when it is deleted or moved away. */
74
94
  const selectedFolder = useModel(__props, "selectedFolder");
75
95
  const { t } = useEditorI18n();
76
- const { Button: UButton, DropdownMenu: UDropdownMenu, Icon: UIcon, Input: UInput, Tooltip: UTooltip, Tree: UTree } = useUiKit();
96
+ const { Button: UButton, DropdownMenu: UDropdownMenu, Icon: UIcon, Input: UInput, Popover: UPopover, Tooltip: UTooltip, Tree: UTree } = useUiKit();
77
97
  const { model, state } = useTreeModel({
78
98
  store: () => props.store,
79
99
  editor: () => props.editor,
@@ -85,6 +105,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
85
105
  settings.value.blocks.treeRoot = settings.value.blocks.treeRoot === "file" ? "folders" : "file";
86
106
  }
87
107
  const row = (item) => rowOf(state.value, item, t);
108
+ /** The basket `item` is in, when the open editor offers it (the row shows its colour as a dot). */
109
+ const basketOf = (item) => itemBasket(item, state.value.baskets);
110
+ /** The basket filter button needs a live editor that offers baskets. */
111
+ const showBasketFilter = computed(() => state.value.hasEditor && state.value.baskets.length > 0);
112
+ /** The chosen baskets the open editor offers (an unknown id never filters, see `TreeModel`). */
113
+ const shownBaskets = computed(() => state.value.basketFilter.filter((id) => basketById(state.value.baskets, id)));
114
+ const breadcrumb = computed(() => focusCrumbs(state.value.focusPath));
88
115
  /** Why dropping the drag on `item` is refused, while the pointer is over it. */
89
116
  function refusal(item) {
90
117
  const drop = row(item).drop;
@@ -145,50 +172,124 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
145
172
  if (!payload) return event.preventDefault();
146
173
  if (!event.dataTransfer) return model.value.dragEnd();
147
174
  event.dataTransfer.setData(DRAG_MIME, JSON.stringify(payload));
148
- event.dataTransfer.effectAllowed = "move";
175
+ const editor = props.editor;
176
+ const found = payload.type === "composite" && editor && !editor.isDestroyed ? findBlockById(editor.state.doc, payload.blockId) : null;
177
+ const transfer = found && editor ? blockTransferOf(editor, found.pos) : null;
178
+ if (transfer) writeBlockTransfer(event.dataTransfer, transfer);
179
+ event.dataTransfer.effectAllowed = transfer ? "copyMove" : "move";
149
180
  }
181
+ /** A drag of this tree's own rows is running (a foreign drag is not). */
182
+ const ownDrag = () => !!state.value.drag && state.value.drag.source.type !== "foreign-block";
150
183
  function onDragOver(event, item) {
151
- const verdict = model.value.dragOver(item);
184
+ const foreign = !ownDrag() && !!event.dataTransfer?.types.includes("application/x-tip-block");
185
+ const verdict = foreign ? model.value.foreignDragOver(item) : model.value.dragOver(item);
152
186
  if (!verdict) return;
153
187
  if (verdict.ok) event.preventDefault();
154
- if (event.dataTransfer) event.dataTransfer.dropEffect = verdict.ok ? "move" : "none";
188
+ if (event.dataTransfer) event.dataTransfer.dropEffect = verdict.ok ? foreign ? "copy" : "move" : "none";
155
189
  }
156
190
  function onDragLeave(event, item) {
157
191
  if (!event.currentTarget.contains(event.relatedTarget)) model.value.dragLeave(item);
158
192
  }
159
193
  function onDrop(event, item) {
160
- if (!state.value.drag) return;
194
+ if (ownDrag()) {
195
+ event.preventDefault();
196
+ return model.value.drop(item);
197
+ }
198
+ const payload = event.dataTransfer ? readBlockTransfer(event.dataTransfer) : null;
199
+ if (!payload) return;
161
200
  event.preventDefault();
162
- return model.value.drop(item);
201
+ return model.value.dropForeign(item, payload, event.shiftKey, event.clientX, event.clientY);
163
202
  }
164
203
  return (_ctx, _cache) => {
165
204
  return openBlock(), createElementBlock("div", _hoisted_1, [
166
- createVNode(unref(UInput), {
167
- "model-value": unref(state).filterText,
168
- icon: "i-lucide-search",
169
- size: "sm",
170
- placeholder: unref(t)("tree.filterText.placeholder"),
171
- "aria-label": unref(t)("tree.filterText.placeholder"),
172
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => unref(model).setFilterText($event)),
173
- onKeydown: _cache[2] || (_cache[2] = withKeys(($event) => unref(model).setFilterText(""), ["esc"]))
174
- }, createSlots({ _: 2 }, [unref(state).filterText ? {
175
- name: "trailing",
176
- fn: withCtx(() => [createVNode(unref(UButton), {
177
- icon: "i-lucide-x",
178
- size: "xs",
179
- color: "neutral",
180
- variant: "link",
181
- "aria-label": unref(t)("tree.filterText.clear"),
182
- onClick: _cache[0] || (_cache[0] = ($event) => unref(model).setFilterText(""))
183
- }, null, 8, ["aria-label"])]),
184
- key: "0"
185
- } : void 0]), 1032, [
186
- "model-value",
187
- "placeholder",
188
- "aria-label"
205
+ createElementVNode("div", _hoisted_2, [
206
+ createVNode(unref(UInput), {
207
+ "model-value": unref(state).filterText,
208
+ class: "min-w-0 flex-1",
209
+ icon: "i-lucide-search",
210
+ size: "sm",
211
+ placeholder: unref(t)("tree.filterText.placeholder"),
212
+ "aria-label": unref(t)("tree.filterText.placeholder"),
213
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => unref(model).setFilterText($event)),
214
+ onKeydown: _cache[2] || (_cache[2] = withKeys(($event) => unref(model).setFilterText(""), ["esc"]))
215
+ }, createSlots({ _: 2 }, [unref(state).filterText ? {
216
+ name: "trailing",
217
+ fn: withCtx(() => [createVNode(unref(UButton), {
218
+ icon: "i-lucide-x",
219
+ size: "xs",
220
+ color: "neutral",
221
+ variant: "link",
222
+ "aria-label": unref(t)("tree.filterText.clear"),
223
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(model).setFilterText(""))
224
+ }, null, 8, ["aria-label"])]),
225
+ key: "0"
226
+ } : void 0]), 1032, [
227
+ "model-value",
228
+ "placeholder",
229
+ "aria-label"
230
+ ]),
231
+ createCommentVNode(" A popover, not a dropdown menu: a menu item cannot show a dot in an arbitrary CSS colour. "),
232
+ showBasketFilter.value ? (openBlock(), createBlock(unref(UPopover), {
233
+ key: 0,
234
+ content: {
235
+ side: "bottom",
236
+ align: "end",
237
+ sideOffset: 4,
238
+ onCloseAutoFocus: (event) => event.preventDefault()
239
+ },
240
+ ui: { content: "w-44 p-1" }
241
+ }, {
242
+ content: withCtx(() => [createElementVNode("div", {
243
+ role: "menu",
244
+ "aria-label": unref(t)("tree.basketFilter.label")
245
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(state).baskets, (basket) => {
246
+ return openBlock(), createElementBlock("button", {
247
+ key: basket.id,
248
+ type: "button",
249
+ role: "menuitemcheckbox",
250
+ "aria-checked": shownBaskets.value.includes(basket.id),
251
+ class: normalizeClass(basketOption),
252
+ onClick: ($event) => unref(model).setBasketShown(basket.id, !shownBaskets.value.includes(basket.id))
253
+ }, [
254
+ createElementVNode("span", {
255
+ class: "size-2.5 shrink-0 rounded-full",
256
+ style: normalizeStyle({ backgroundColor: basket.color })
257
+ }, null, 4),
258
+ createElementVNode("span", _hoisted_5, toDisplayString(basket.label), 1),
259
+ shownBaskets.value.includes(basket.id) ? (openBlock(), createBlock(unref(UIcon), {
260
+ key: 0,
261
+ name: "i-lucide-check",
262
+ class: "ml-auto size-3.5 shrink-0"
263
+ })) : createCommentVNode("v-if", true)
264
+ ], 8, _hoisted_4);
265
+ }), 128)), shownBaskets.value.length ? (openBlock(), createElementBlock("button", {
266
+ key: 0,
267
+ type: "button",
268
+ role: "menuitem",
269
+ class: normalizeClass(basketOption),
270
+ onClick: _cache[3] || (_cache[3] = ($event) => unref(model).clearBasketFilter())
271
+ }, [createVNode(unref(UIcon), {
272
+ name: "i-lucide-filter-x",
273
+ class: "size-3.5 shrink-0 text-[var(--sk-muted)]"
274
+ }), createElementVNode("span", _hoisted_6, toDisplayString(unref(t)("tree.basketFilter.reset")), 1)])) : createCommentVNode("v-if", true)], 8, _hoisted_3)]),
275
+ default: withCtx(() => [createVNode(unref(UButton), {
276
+ icon: "i-lucide-paint-bucket",
277
+ size: "xs",
278
+ color: shownBaskets.value.length ? "primary" : "neutral",
279
+ variant: shownBaskets.value.length ? "soft" : "ghost",
280
+ title: unref(t)("tree.basketFilter.label"),
281
+ "aria-label": unref(t)("tree.basketFilter.label")
282
+ }, null, 8, [
283
+ "color",
284
+ "variant",
285
+ "title",
286
+ "aria-label"
287
+ ])]),
288
+ _: 1
289
+ }, 8, ["content"])) : createCommentVNode("v-if", true)
189
290
  ]),
190
- createElementVNode("div", _hoisted_2, [createVNode(unref(UTooltip), { text: canUseFileRoot.value ? "" : unref(t)("tree.root.unavailable") }, {
191
- default: withCtx(() => [createCommentVNode(" A disabled button swallows pointer events, so the tooltip hangs on the wrapper. "), createElementVNode("span", _hoisted_3, [createVNode(unref(UButton), {
291
+ createElementVNode("div", _hoisted_7, [createVNode(unref(UTooltip), { text: canUseFileRoot.value ? "" : unref(t)("tree.root.unavailable") }, {
292
+ default: withCtx(() => [createCommentVNode(" A disabled button swallows pointer events, so the tooltip hangs on the wrapper. "), createElementVNode("span", _hoisted_8, [createVNode(unref(UButton), {
192
293
  icon: unref(state).virtual ? "i-lucide-file-stack" : "i-lucide-folder-tree",
193
294
  label: unref(t)(unref(state).virtual ? "tree.root.file" : "tree.root.folders"),
194
295
  size: "xs",
@@ -206,7 +307,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
206
307
  ])])]),
207
308
  _: 1
208
309
  }, 8, ["text"])]),
209
- unref(state).view.hasKindFilters ? (openBlock(), createElementBlock("div", _hoisted_4, [createVNode(unref(UButton), {
310
+ unref(state).view.hasKindFilters ? (openBlock(), createElementBlock("div", _hoisted_9, [createVNode(unref(UButton), {
210
311
  icon: "i-lucide-filter-x",
211
312
  label: unref(t)("tree.filter.reset"),
212
313
  size: "xs",
@@ -214,7 +315,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
214
315
  variant: "subtle",
215
316
  onClick: unref(model).clearAllFilters
216
317
  }, null, 8, ["label", "onClick"])])) : createCommentVNode("v-if", true),
217
- unref(state).creatingFolder ? (openBlock(), createElementBlock("div", _hoisted_5, [createVNode(unref(UInput), {
318
+ unref(state).creatingFolder ? (openBlock(), createElementBlock("div", _hoisted_10, [createVNode(unref(UInput), {
218
319
  "model-value": unref(state).creatingFolder.draft,
219
320
  size: "sm",
220
321
  autofocus: "",
@@ -223,7 +324,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
223
324
  placeholder: unref(state).creatingFolder.parent ? unref(t)("tree.folder.placeholderIn", { parent: unref(state).creatingFolder.parent }) : unref(t)("tree.folder.placeholder"),
224
325
  "aria-label": unref(t)("tree.folder.name"),
225
326
  "aria-invalid": !!unref(state).creatingFolder.error,
226
- "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => unref(model).setFolderDraft($event)),
327
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => unref(model).setFolderDraft($event)),
227
328
  onKeydown: [withKeys(unref(model).commitCreateFolder, ["enter"]), withKeys(unref(model).cancelCreateFolder, ["esc"])],
228
329
  onBlur: unref(model).cancelCreateFolder
229
330
  }, null, 8, [
@@ -235,9 +336,35 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
235
336
  "aria-invalid",
236
337
  "onKeydown",
237
338
  "onBlur"
238
- ]), unref(state).creatingFolder.error ? (openBlock(), createElementBlock("p", _hoisted_6, toDisplayString(unref(state).creatingFolder.error), 1)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
239
- !unref(state).tree && !unref(state).virtual ? (openBlock(), createElementBlock("p", _hoisted_7, toDisplayString(unref(state).tree === null ? unref(t)("tree.loadFailed") : unref(t)("tree.loading")), 1)) : (openBlock(), createBlock(unref(UTree), {
240
- key: 3,
339
+ ]), unref(state).creatingFolder.error ? (openBlock(), createElementBlock("p", _hoisted_11, toDisplayString(unref(state).creatingFolder.error), 1)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
340
+ breadcrumb.value.crumbs.length ? (openBlock(), createElementBlock("div", _hoisted_12, [createVNode(unref(UButton), {
341
+ icon: "i-lucide-corner-up-left",
342
+ label: breadcrumb.value.document?.label ?? unref(t)("tree.focus.root"),
343
+ size: "xs",
344
+ color: "neutral",
345
+ variant: "ghost",
346
+ title: unref(t)("tree.focus.leave"),
347
+ "aria-label": unref(t)("tree.focus.leave"),
348
+ onClick: _cache[5] || (_cache[5] = ($event) => unref(model).defocus())
349
+ }, null, 8, [
350
+ "label",
351
+ "title",
352
+ "aria-label"
353
+ ]), (openBlock(true), createElementBlock(Fragment, null, renderList(breadcrumb.value.crumbs, (crumb, index) => {
354
+ return openBlock(), createElementBlock(Fragment, { key: crumb.key }, [createVNode(unref(UIcon), {
355
+ name: "i-lucide-chevron-right",
356
+ class: "size-3 shrink-0 text-[var(--sk-muted)]"
357
+ }), index === breadcrumb.value.crumbs.length - 1 ? (openBlock(), createElementBlock("span", _hoisted_13, toDisplayString(crumb.label), 1)) : (openBlock(), createBlock(unref(UButton), {
358
+ key: 1,
359
+ label: crumb.label,
360
+ size: "xs",
361
+ color: "neutral",
362
+ variant: "ghost",
363
+ onClick: ($event) => unref(model).focus(crumb.key)
364
+ }, null, 8, ["label", "onClick"]))], 64);
365
+ }), 128))])) : createCommentVNode("v-if", true),
366
+ !unref(state).tree && !unref(state).virtual ? (openBlock(), createElementBlock("p", _hoisted_14, toDisplayString(unref(state).tree === null ? unref(t)("tree.loadFailed") : unref(t)("tree.loading")), 1)) : (openBlock(), createBlock(unref(UTree), {
367
+ key: 4,
241
368
  expanded: unref(state).view.open,
242
369
  items: unref(state).view.items,
243
370
  "get-key": (item) => item.key,
@@ -245,31 +372,33 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
245
372
  "aria-label": unref(t)("tree.aria"),
246
373
  "onUpdate:expanded": onExpanded
247
374
  }, {
248
- "item-wrapper": withCtx(({ item }) => [createElementVNode("div", _hoisted_8, [createElementVNode("div", {
375
+ "item-wrapper": withCtx(({ item }) => [createElementVNode("div", _hoisted_15, [createElementVNode("div", {
249
376
  class: normalizeClass(["group flex w-full cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-sm select-none hover:bg-[color-mix(in_oklab,var(--sk-bg-elevated)_60%,transparent)]", [
250
377
  row(item).active && "bg-[color-mix(in_oklab,var(--sk-primary)_10%,transparent)] font-medium text-[var(--sk-primary)]",
251
378
  row(item).selected && "bg-[var(--sk-bg-elevated)]",
252
379
  row(item).drop?.ok && "ring-1 ring-[var(--sk-primary)]",
253
- refusal(item) && "bg-[color-mix(in_oklab,var(--sk-danger)_10%,transparent)] ring-1 ring-[var(--sk-danger)]"
380
+ refusal(item) && "bg-[color-mix(in_oklab,var(--sk-danger)_10%,transparent)] ring-1 ring-[var(--sk-danger)]",
381
+ row(item).dimmed && "opacity-60"
254
382
  ]]),
255
383
  draggable: unref(model).isDraggable(item),
256
384
  onDragstart: ($event) => onDragStart($event, item),
257
385
  onDragover: ($event) => onDragOver($event, item),
258
386
  onDragleave: ($event) => onDragLeave($event, item),
259
387
  onDrop: ($event) => onDrop($event, item),
260
- onDragend: _cache[10] || (_cache[10] = (...args) => unref(model).dragEnd && unref(model).dragEnd(...args))
388
+ onDragend: _cache[12] || (_cache[12] = (...args) => unref(model).dragEnd && unref(model).dragEnd(...args))
261
389
  }, [
262
390
  row(item).expandable ? (openBlock(), createBlock(unref(UIcon), {
263
391
  key: 0,
264
392
  name: "i-lucide-chevron-right",
265
393
  class: normalizeClass(["size-3.5 shrink-0 text-[var(--sk-muted)] transition-transform", row(item).open && "rotate-90"]),
266
394
  onClick: ($event) => onChevronClick($event, item)
267
- }, null, 8, ["class", "onClick"])) : item.type === "composite" || item.type === "heading" ? (openBlock(), createElementBlock("span", _hoisted_10)) : createCommentVNode("v-if", true),
395
+ }, null, 8, ["class", "onClick"])) : item.type === "composite" || item.type === "heading" ? (openBlock(), createElementBlock("span", _hoisted_17)) : createCommentVNode("v-if", true),
268
396
  createVNode(unref(UIcon), {
269
397
  name: item.icon,
270
- class: "size-4 shrink-0"
271
- }, null, 8, ["name"]),
272
- row(item).renaming ? (openBlock(), createElementBlock("div", _hoisted_11, [createVNode(unref(UInput), {
398
+ class: "size-4 shrink-0",
399
+ style: normalizeStyle(item.tone ? { color: item.tone } : void 0)
400
+ }, null, 8, ["name", "style"]),
401
+ row(item).renaming ? (openBlock(), createElementBlock("div", _hoisted_18, [createVNode(unref(UInput), {
273
402
  "model-value": row(item).renaming.draft,
274
403
  size: "xs",
275
404
  class: "min-w-0",
@@ -278,11 +407,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
278
407
  highlight: !!row(item).renaming.error,
279
408
  "aria-label": unref(t)("tree.folder.name"),
280
409
  "aria-invalid": !!row(item).renaming.error,
281
- "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => unref(model).setRenameDraft($event)),
282
- onFocus: _cache[5] || (_cache[5] = ($event) => $event.target.select()),
283
- onClick: _cache[6] || (_cache[6] = withModifiers(() => {}, ["stop"])),
410
+ "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => unref(model).setRenameDraft($event)),
411
+ onFocus: _cache[7] || (_cache[7] = ($event) => $event.target.select()),
412
+ onClick: _cache[8] || (_cache[8] = withModifiers(() => {}, ["stop"])),
284
413
  onKeydown: [
285
- _cache[7] || (_cache[7] = withModifiers(() => {}, ["stop"])),
414
+ _cache[9] || (_cache[9] = withModifiers(() => {}, ["stop"])),
286
415
  withKeys(unref(model).commitRename, ["enter"]),
287
416
  withKeys(unref(model).cancelRename, ["esc"])
288
417
  ],
@@ -299,25 +428,34 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
299
428
  key: 0,
300
429
  class: "text-xs text-[var(--sk-danger)]",
301
430
  role: "alert",
302
- onClick: _cache[8] || (_cache[8] = withModifiers(() => {}, ["stop"]))
431
+ onClick: _cache[10] || (_cache[10] = withModifiers(() => {}, ["stop"]))
303
432
  }, toDisplayString(row(item).renaming.error), 1)) : createCommentVNode("v-if", true)])) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
433
+ basketOf(item) ? (openBlock(), createElementBlock("span", {
434
+ key: 0,
435
+ class: "size-2 shrink-0 rounded-full",
436
+ style: normalizeStyle({ backgroundColor: basketOf(item).color }),
437
+ title: basketOf(item).label,
438
+ "aria-label": basketOf(item).label,
439
+ role: "img",
440
+ "data-basket-dot": ""
441
+ }, null, 12, _hoisted_19)) : createCommentVNode("v-if", true),
304
442
  createElementVNode("span", {
305
443
  class: "min-w-0 flex-1 truncate",
306
444
  title: item.label
307
445
  }, [labelParts(item) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
308
446
  createTextVNode(toDisplayString(labelParts(item)[0]), 1),
309
- createElementVNode("mark", _hoisted_13, toDisplayString(labelParts(item)[1]), 1),
447
+ createElementVNode("mark", _hoisted_21, toDisplayString(labelParts(item)[1]), 1),
310
448
  createTextVNode(toDisplayString(labelParts(item)[2]), 1)
311
- ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(item.label), 1)], 64))], 8, _hoisted_12),
449
+ ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(item.label), 1)], 64))], 8, _hoisted_20),
312
450
  item.hasSummary ? (openBlock(), createBlock(unref(UIcon), {
313
- key: 0,
451
+ key: 1,
314
452
  name: "i-lucide-text-quote",
315
453
  class: "size-3.5 shrink-0 text-[var(--sk-muted)]",
316
454
  title: unref(t)("tree.summary")
317
455
  }, null, 8, ["title"])) : createCommentVNode("v-if", true),
318
456
  createElementVNode("div", {
319
457
  class: "flex shrink-0",
320
- onClick: _cache[9] || (_cache[9] = withModifiers(() => {}, ["stop"]))
458
+ onClick: _cache[11] || (_cache[11] = withModifiers(() => {}, ["stop"]))
321
459
  }, [row(item).showFilter ? (openBlock(), createBlock(unref(UDropdownMenu), {
322
460
  key: 0,
323
461
  items: filterMenu(item),
@@ -339,9 +477,37 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
339
477
  "aria-label"
340
478
  ])]),
341
479
  _: 2
342
- }, 1032, ["items"])) : createCommentVNode("v-if", true), createElementVNode("div", _hoisted_14, [
343
- addMenu(item).length ? (openBlock(), createBlock(unref(UDropdownMenu), {
480
+ }, 1032, ["items"])) : createCommentVNode("v-if", true), createElementVNode("div", _hoisted_22, [
481
+ item.type === "composite" && item.blockId ? (openBlock(), createBlock(unref(UButton), {
344
482
  key: 0,
483
+ icon: "i-lucide-focus",
484
+ size: "xs",
485
+ color: "neutral",
486
+ variant: "ghost",
487
+ title: unref(t)("tree.focus.enter"),
488
+ "aria-label": unref(t)("tree.focus.enter"),
489
+ onClick: ($event) => unref(model).focus(item.key)
490
+ }, null, 8, [
491
+ "title",
492
+ "aria-label",
493
+ "onClick"
494
+ ])) : createCommentVNode("v-if", true),
495
+ unref(model).canMerge(item) ? (openBlock(), createBlock(unref(UButton), {
496
+ key: 1,
497
+ icon: "i-lucide-merge",
498
+ size: "xs",
499
+ color: "neutral",
500
+ variant: "ghost",
501
+ title: unref(t)("tree.merge"),
502
+ "aria-label": unref(t)("tree.merge"),
503
+ onClick: ($event) => unref(model).merge(item)
504
+ }, null, 8, [
505
+ "title",
506
+ "aria-label",
507
+ "onClick"
508
+ ])) : createCommentVNode("v-if", true),
509
+ addMenu(item).length ? (openBlock(), createBlock(unref(UDropdownMenu), {
510
+ key: 2,
345
511
  items: addMenu(item),
346
512
  content: {
347
513
  align: "start",
@@ -361,9 +527,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
361
527
  item.type === "document" ? renderSlot(_ctx.$slots, "document-actions", {
362
528
  id: item.id,
363
529
  title: item.label
364
- }, void 0, void 0, 1) : createCommentVNode("v-if", true),
530
+ }, void 0, void 0, 3) : createCommentVNode("v-if", true),
365
531
  item.type === "document" || item.type === "folder" ? (openBlock(), createBlock(unref(UButton), {
366
- key: 2,
532
+ key: 4,
367
533
  icon: "i-lucide-trash-2",
368
534
  size: "xs",
369
535
  color: "error",
@@ -374,7 +540,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
374
540
  }, null, 8, ["aria-label", "onClick"])) : createCommentVNode("v-if", true)
375
541
  ])])
376
542
  ], 64))
377
- ], 42, _hoisted_9), refusal(item) ? (openBlock(), createElementBlock("p", _hoisted_15, toDisplayString(refusal(item)), 1)) : createCommentVNode("v-if", true)])]),
543
+ ], 42, _hoisted_16), refusal(item) ? (openBlock(), createElementBlock("p", _hoisted_23, toDisplayString(refusal(item)), 1)) : createCommentVNode("v-if", true)])]),
378
544
  _: 3
379
545
  }, 8, [
380
546
  "expanded",
@@ -382,8 +548,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
382
548
  "get-key",
383
549
  "aria-label"
384
550
  ])),
385
- unref(state).view.noMatches ? (openBlock(), createElementBlock("p", _hoisted_16, toDisplayString(unref(t)("tree.noMatches")), 1)) : createCommentVNode("v-if", true),
386
- unref(state).view.isEmpty ? (openBlock(), createElementBlock("p", _hoisted_17, toDisplayString(unref(t)("tree.empty")), 1)) : createCommentVNode("v-if", true)
551
+ unref(state).view.noMatches ? (openBlock(), createElementBlock("p", _hoisted_24, toDisplayString(unref(t)("tree.noMatches")), 1)) : createCommentVNode("v-if", true),
552
+ unref(state).view.isEmpty ? (openBlock(), createElementBlock("p", _hoisted_25, toDisplayString(unref(t)("tree.empty")), 1)) : createCommentVNode("v-if", true)
387
553
  ]);
388
554
  };
389
555
  }