@ecsplico/editor 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +4 -3
  3. package/dist/adapters/anchors.d.ts +80 -0
  4. package/dist/adapters/anchors.js +270 -0
  5. package/dist/adapters/anchors.js.map +1 -0
  6. package/dist/adapters/comments/client.d.ts +64 -0
  7. package/dist/adapters/comments/client.js +536 -0
  8. package/dist/adapters/comments/client.js.map +1 -0
  9. package/dist/adapters/comments/drizzle.d.ts +430 -0
  10. package/dist/adapters/comments/drizzle.js +236 -0
  11. package/dist/adapters/comments/drizzle.js.map +1 -0
  12. package/dist/adapters/comments/errors.d.ts +9 -0
  13. package/dist/adapters/comments/errors.js +19 -0
  14. package/dist/adapters/comments/errors.js.map +1 -0
  15. package/dist/adapters/comments/json.d.ts +19 -0
  16. package/dist/adapters/comments/json.js +94 -0
  17. package/dist/adapters/comments/json.js.map +1 -0
  18. package/dist/adapters/comments/record.js +78 -0
  19. package/dist/adapters/comments/record.js.map +1 -0
  20. package/dist/adapters/comments/server.d.ts +23 -0
  21. package/dist/adapters/comments/server.js +102 -0
  22. package/dist/adapters/comments/server.js.map +1 -0
  23. package/dist/adapters/comments/types.d.ts +109 -0
  24. package/dist/adapters/documents.js +108 -0
  25. package/dist/adapters/documents.js.map +1 -0
  26. package/dist/adapters/drizzle.d.ts +293 -0
  27. package/dist/adapters/drizzle.js +157 -0
  28. package/dist/adapters/drizzle.js.map +1 -0
  29. package/dist/adapters/files.js +30 -0
  30. package/dist/adapters/files.js.map +1 -0
  31. package/dist/adapters/forge.d.ts +58 -0
  32. package/dist/adapters/forge.js +91 -0
  33. package/dist/adapters/forge.js.map +1 -0
  34. package/dist/adapters/index.d.ts +13 -0
  35. package/dist/adapters/index.js +0 -0
  36. package/dist/adapters/json.d.ts +24 -0
  37. package/dist/adapters/json.js +128 -0
  38. package/dist/adapters/json.js.map +1 -0
  39. package/dist/adapters/nitro.d.ts +61 -0
  40. package/dist/adapters/nitro.js +212 -0
  41. package/dist/adapters/nitro.js.map +1 -0
  42. package/dist/adapters/routes.js +16 -0
  43. package/dist/adapters/routes.js.map +1 -0
  44. package/dist/adapters/shared.d.ts +37 -0
  45. package/dist/adapters/shared.js +32 -0
  46. package/dist/adapters/shared.js.map +1 -0
  47. package/dist/adapters/vue.d.ts +67 -0
  48. package/dist/adapters/vue.js +187 -0
  49. package/dist/adapters/vue.js.map +1 -0
  50. package/dist/code/CodeSurface.vue.d.ts +3 -3
  51. package/dist/core/doc-anchors.d.ts +5 -0
  52. package/dist/core/doc-anchors.js +4 -3
  53. package/dist/core/doc-anchors.js.map +1 -1
  54. package/dist/core/editor-ui.js +57 -1
  55. package/dist/core/editor-ui.js.map +1 -1
  56. package/dist/core/surface-session.js +139 -0
  57. package/dist/core/surface-session.js.map +1 -0
  58. package/dist/document/DocumentSurface.d.ts +1 -1
  59. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  60. package/dist/features/ai/agent-op-review.d.ts +2 -2
  61. package/dist/features/ai/agent-op-review.js.map +1 -1
  62. package/dist/features/ai/agent-ops.d.ts +1 -1
  63. package/dist/features/ai/agent-ops.js +9 -6
  64. package/dist/features/ai/agent-ops.js.map +1 -1
  65. package/dist/features/ai/ai-apply.d.ts +1 -1
  66. package/dist/features/ai/ai-review.js +10 -1
  67. package/dist/features/ai/ai-review.js.map +1 -1
  68. package/dist/features/ai/components/AiSelectionMenu.js +78 -252
  69. package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
  70. package/dist/features/ai/components/AiSelectionMenu.vue.d.ts +2 -1
  71. package/dist/features/ai/components/AiSidebar.js +2 -2
  72. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  73. package/dist/features/ai/components/DocumentChatOps.js +1 -0
  74. package/dist/features/ai/components/DocumentChatOps.js.map +1 -1
  75. package/dist/features/ai/components/ModelQuickSwitch.js +1 -1
  76. package/dist/features/ai/components/SettingsAiTab.js +1 -1
  77. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  78. package/dist/features/ai/document-chat.d.ts +3 -2
  79. package/dist/features/ai/document-chat.js +16 -19
  80. package/dist/features/ai/document-chat.js.map +1 -1
  81. package/dist/features/ai/index.d.ts +5 -3
  82. package/dist/features/ai/index.js +4 -2
  83. package/dist/features/ai/protocol/agent-ops.d.ts +22 -17
  84. package/dist/features/ai/protocol/agent-ops.js +65 -39
  85. package/dist/features/ai/protocol/agent-ops.js.map +1 -1
  86. package/dist/features/ai/protocol/block-lines.d.ts +89 -0
  87. package/dist/features/ai/protocol/block-lines.js +177 -0
  88. package/dist/features/ai/protocol/block-lines.js.map +1 -0
  89. package/dist/features/ai/protocol/chat.js +10 -10
  90. package/dist/features/ai/protocol/chat.js.map +1 -1
  91. package/dist/features/ai/protocol/index.d.ts +3 -2
  92. package/dist/features/ai/protocol/index.js +3 -2
  93. package/dist/features/ai/react/AiSelectionMenu.d.ts +3 -2
  94. package/dist/features/ai/react/AiSelectionMenu.js +64 -255
  95. package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
  96. package/dist/features/ai/react/AiSidebar.js +2 -2
  97. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  98. package/dist/features/ai/react/DocumentChatOps.js +1 -0
  99. package/dist/features/ai/react/DocumentChatOps.js.map +1 -1
  100. package/dist/features/ai/react/ModelQuickSwitch.js +1 -1
  101. package/dist/features/ai/react/SettingsAiTab.js +1 -1
  102. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  103. package/dist/features/ai/react/use-ai-selection-flow.js +34 -0
  104. package/dist/features/ai/react/use-ai-selection-flow.js.map +1 -0
  105. package/dist/features/ai/selection-flow.d.ts +133 -0
  106. package/dist/features/ai/selection-flow.js +283 -0
  107. package/dist/features/ai/selection-flow.js.map +1 -0
  108. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  109. package/dist/features/ai/use-document-chat.d.ts +1 -1
  110. package/dist/features/authors/components/AuthorColorsPanel.js +1 -1
  111. package/dist/features/authors/feature.js +1 -1
  112. package/dist/features/authors/index.js +1 -1
  113. package/dist/features/authors/react/AuthorColorsPanel.js +1 -1
  114. package/dist/features/comments/components/CommentBubble.js +1 -1
  115. package/dist/features/comments/components/CommentComposer.js +1 -1
  116. package/dist/features/comments/components/CommentThreadView.js +5 -2
  117. package/dist/features/comments/components/CommentThreadView.js.map +1 -1
  118. package/dist/features/comments/components/CommentsMargin.js +108 -230
  119. package/dist/features/comments/components/CommentsMargin.js.map +1 -1
  120. package/dist/features/comments/components/CommentsOverlay.js +1 -1
  121. package/dist/features/comments/feature.js +1 -1
  122. package/dist/features/comments/index.d.ts +4 -2
  123. package/dist/features/comments/index.js +4 -2
  124. package/dist/features/comments/margin-controller.d.ts +44 -0
  125. package/dist/features/comments/margin-controller.js +132 -0
  126. package/dist/features/comments/margin-controller.js.map +1 -0
  127. package/dist/features/comments/margin-layout.d.ts +55 -0
  128. package/dist/features/comments/margin-layout.js +79 -0
  129. package/dist/features/comments/margin-layout.js.map +1 -0
  130. package/dist/features/comments/model.d.ts +8 -0
  131. package/dist/features/comments/model.js +60 -34
  132. package/dist/features/comments/model.js.map +1 -1
  133. package/dist/features/comments/react/CommentBubble.js +1 -1
  134. package/dist/features/comments/react/CommentComposer.js +1 -1
  135. package/dist/features/comments/react/CommentThreadView.js +2 -2
  136. package/dist/features/comments/react/CommentThreadView.js.map +1 -1
  137. package/dist/features/comments/react/CommentsMargin.d.ts +0 -5
  138. package/dist/features/comments/react/CommentsMargin.js +85 -251
  139. package/dist/features/comments/react/CommentsMargin.js.map +1 -1
  140. package/dist/features/comments/react/CommentsOverlay.js +1 -1
  141. package/dist/features/comments/react/use-comments.js +1 -1
  142. package/dist/features/comments/react/use-margin-layout.js +45 -0
  143. package/dist/features/comments/react/use-margin-layout.js.map +1 -0
  144. package/dist/features/comments/react.d.ts +1 -1
  145. package/dist/features/comments/schema.d.ts +23 -0
  146. package/dist/features/comments/schema.js.map +1 -1
  147. package/dist/features/comments/snapshot-equality.js +40 -0
  148. package/dist/features/comments/snapshot-equality.js.map +1 -0
  149. package/dist/features/comments/thread-anchor.js +33 -0
  150. package/dist/features/comments/thread-anchor.js.map +1 -0
  151. package/dist/features/comments/use-comments.d.ts +3 -1
  152. package/dist/features/comments/use-comments.js +1 -0
  153. package/dist/features/comments/use-comments.js.map +1 -1
  154. package/dist/features/comments/use-margin-layout.js +29 -0
  155. package/dist/features/comments/use-margin-layout.js.map +1 -0
  156. package/dist/features/comments/vue.d.ts +1 -1
  157. package/dist/features/composites/accepted-children.d.ts +21 -0
  158. package/dist/features/composites/accepted-children.js +126 -0
  159. package/dist/features/composites/accepted-children.js.map +1 -0
  160. package/dist/features/composites/components/CompositeDetails.js +1 -1
  161. package/dist/features/composites/components/CompositeInspector.js +38 -164
  162. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  163. package/dist/features/composites/feature.d.ts +2 -1
  164. package/dist/features/composites/feature.js +8 -2
  165. package/dist/features/composites/feature.js.map +1 -1
  166. package/dist/features/composites/index.d.ts +5 -3
  167. package/dist/features/composites/index.js +8 -6
  168. package/dist/features/composites/inspector-model.d.ts +97 -0
  169. package/dist/features/composites/inspector-model.js +255 -0
  170. package/dist/features/composites/inspector-model.js.map +1 -0
  171. package/dist/features/composites/kinds.d.ts +11 -0
  172. package/dist/features/composites/kinds.js +17 -2
  173. package/dist/features/composites/kinds.js.map +1 -1
  174. package/dist/features/composites/outline.d.ts +18 -5
  175. package/dist/features/composites/outline.js +44 -12
  176. package/dist/features/composites/outline.js.map +1 -1
  177. package/dist/features/composites/react/CompositeDetails.js +1 -1
  178. package/dist/features/composites/react/CompositeInspector.d.ts +1 -1
  179. package/dist/features/composites/react/CompositeInspector.js +21 -180
  180. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  181. package/dist/features/composites/react/CompositeStatusMenu.d.ts +1 -1
  182. package/dist/features/composites/react/CompositeView.js +1 -1
  183. package/dist/features/composites/react/use-composite-inspector.js +29 -0
  184. package/dist/features/composites/react/use-composite-inspector.js.map +1 -0
  185. package/dist/features/composites/schema.d.ts +2 -2
  186. package/dist/features/composites/schema.js +2 -2
  187. package/dist/features/composites/schema.js.map +1 -1
  188. package/dist/features/composites/use-composite-anchors.d.ts +1 -1
  189. package/dist/features/composites/use-composite-inspector.js +41 -0
  190. package/dist/features/composites/use-composite-inspector.js.map +1 -0
  191. package/dist/features/composites/use-composite-rows.d.ts +1 -1
  192. package/dist/features/media/index.d.ts +1 -1
  193. package/dist/features/media/vue.d.ts +1 -1
  194. package/dist/features/mentions/index.d.ts +3 -3
  195. package/dist/features/mentions/index.js +3 -3
  196. package/dist/features/mentions/schema.d.ts +1 -1
  197. package/dist/features/mentions/schema.js +1 -1
  198. package/dist/features/themes/index.d.ts +1 -1
  199. package/dist/features/themes/index.js +1 -1
  200. package/dist/features/transcript/feature.js +1 -1
  201. package/dist/features/transcript/index.js +2 -2
  202. package/dist/i18n/de/ai.js +2 -0
  203. package/dist/i18n/de/ai.js.map +1 -1
  204. package/dist/i18n/de/composites.js +8 -1
  205. package/dist/i18n/de/composites.js.map +1 -1
  206. package/dist/i18n/de/tree.js +14 -1
  207. package/dist/i18n/de/tree.js.map +1 -1
  208. package/dist/i18n/de.d.ts +22 -0
  209. package/dist/i18n/en/ai.js +2 -0
  210. package/dist/i18n/en/ai.js.map +1 -1
  211. package/dist/i18n/en/composites.js +8 -1
  212. package/dist/i18n/en/composites.js.map +1 -1
  213. package/dist/i18n/en/tree.js +14 -1
  214. package/dist/i18n/en/tree.js.map +1 -1
  215. package/dist/integrations/composite-ai/composite-fill.js +2 -2
  216. package/dist/integrations/composite-ai/composite-summary.js +2 -2
  217. package/dist/integrations/composite-ai/index.js +2 -2
  218. package/dist/integrations/transcript-ai/transcript-cleanup.js +1 -1
  219. package/dist/markdown/MarkdownSurface.d.ts +1 -1
  220. package/dist/markdown/MarkdownSurface.js +2 -2
  221. package/dist/markdown/MarkdownSurface.vue.d.ts +9 -9
  222. package/dist/markdown/index.d.ts +2 -2
  223. package/dist/nuxt/runtime/server/routes/collab/[id].js +1 -1
  224. package/dist/react/EditorSurface.d.ts +1 -1
  225. package/dist/react/EditorSurface.js +43 -149
  226. package/dist/react/EditorSurface.js.map +1 -1
  227. package/dist/react/EditorToolbar.js +3 -40
  228. package/dist/react/EditorToolbar.js.map +1 -1
  229. package/dist/schema/advanced.js +2 -2
  230. package/dist/server/adapter.d.ts +2 -2
  231. package/dist/server/collab.js +1 -1
  232. package/dist/server/handlers/ai.d.ts +4 -2
  233. package/dist/server/handlers/ai.js +11 -9
  234. package/dist/server/handlers/ai.js.map +1 -1
  235. package/dist/server/handlers/context.d.ts +1 -1
  236. package/dist/server/handlers/editor.d.ts +1 -1
  237. package/dist/server/handlers/editor.js +2 -2
  238. package/dist/server/host.d.ts +1 -1
  239. package/dist/server/index.d.ts +2 -2
  240. package/dist/settings/index.d.ts +1 -1
  241. package/dist/styles/tokens.css +1 -1
  242. package/dist/tree/DocumentTree.js +159 -387
  243. package/dist/tree/DocumentTree.js.map +1 -1
  244. package/dist/tree/drop-rules.js +37 -0
  245. package/dist/tree/drop-rules.js.map +1 -0
  246. package/dist/tree/react/DocumentTree.d.ts +2 -2
  247. package/dist/tree/react/DocumentTree.js +135 -397
  248. package/dist/tree/react/DocumentTree.js.map +1 -1
  249. package/dist/tree/react/use-tree-model.js +129 -0
  250. package/dist/tree/react/use-tree-model.js.map +1 -0
  251. package/dist/tree/react.js +1 -1
  252. package/dist/tree/tree-host.js +100 -0
  253. package/dist/tree/tree-host.js.map +1 -0
  254. package/dist/tree/tree-items.js +22 -43
  255. package/dist/tree/tree-items.js.map +1 -1
  256. package/dist/tree/tree-model.js +580 -0
  257. package/dist/tree/tree-model.js.map +1 -0
  258. package/dist/tree/tree-rows.js +77 -0
  259. package/dist/tree/tree-rows.js.map +1 -0
  260. package/dist/tree/use-tree-model.js +94 -0
  261. package/dist/tree/use-tree-model.js.map +1 -0
  262. package/dist/tree/vue.js +1 -1
  263. package/dist/vue/AdvancedEditor.vue.d.ts +6 -6
  264. package/dist/vue/SimpleEditor.vue.d.ts +2 -2
  265. package/dist/vue/components/EditorSurface.js +27 -87
  266. package/dist/vue/components/EditorSurface.js.map +1 -1
  267. package/dist/vue/components/EditorSurface.vue.d.ts +6 -6
  268. package/dist/vue/components/EditorToolbar.js +7 -44
  269. package/dist/vue/components/EditorToolbar.js.map +1 -1
  270. package/dist/vue/context.d.ts +1 -1
  271. package/dist/vue/context.js +1 -1
  272. package/dist/vue/context.js.map +1 -1
  273. package/dist/vue/use-editor-ui.d.ts +1 -1
  274. package/dist/vue/use-notifier.d.ts +1 -1
  275. package/docs/integration.md +97 -4
  276. package/docs/llms.md +9 -1
  277. package/docs/usage.md +10 -5
  278. package/package.json +67 -5
@@ -1,16 +1,9 @@
1
1
  import { useUiKit } from "../vue/kit/use-ui-kit.js";
2
- import { useEditorSettings } from "../vue/settings.js";
3
2
  import { useEditorI18n } from "../vue/use-editor-i18n.js";
4
- import { revealBlockInEditor } from "../outline/heading-outline.js";
5
- import { compositeJSON, compositeKindsOf } from "../features/composites/nodes.js";
6
- import { moveBlockInto } from "../features/composites/outline.js";
7
- import { pickFiles } from "../features/media/upload.js";
8
- import { remapFolderPath } from "./folder-paths.js";
9
- import { DRAG_MIME, EMPTY_OUTLINE, ancestorKeys, applyNodeFilters, canDrop, collectFolderPaths, collectKeys, collectParentKeys, compositeInsertPos, dragPayloadOf, filterKinds, folderItem, folderNamesIn, holdsComposites, isDraggable, joinPath, outlineItems, parentPath, readOutline, virtualRootItem } from "./tree-items.js";
10
- import { useStoreRef } from "../vue/store-ref.js";
11
- import { useFileImport } from "../features/media/vue.js";
12
- import { useTreeView } from "./tree-view.js";
13
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, mergeModels, normalizeClass, openBlock, ref, renderSlot, shallowRef, toDisplayString, unref, useModel, watch, withCtx, withKeys, withModifiers } from "vue";
3
+ import { DRAG_MIME } from "./tree-items.js";
4
+ import { rowOf } from "./tree-model.js";
5
+ import { useTreeModel } from "./use-tree-model.js";
6
+ import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeModels, normalizeClass, openBlock, renderSlot, toDisplayString, unref, useModel, withCtx, withKeys, withModifiers } from "vue";
14
7
  //#region src/tree/DocumentTree.vue
15
8
  const _hoisted_1 = { class: "flex flex-col gap-2" };
16
9
  const _hoisted_2 = {
@@ -30,28 +23,38 @@ const _hoisted_5 = {
30
23
  key: 2,
31
24
  class: "px-2.5 py-1.5 text-sm text-[var(--sk-muted)]"
32
25
  };
33
- const _hoisted_6 = [
26
+ const _hoisted_6 = { class: "w-full" };
27
+ const _hoisted_7 = [
34
28
  "draggable",
35
29
  "onDragstart",
36
30
  "onDragover",
37
31
  "onDragleave",
38
32
  "onDrop"
39
33
  ];
40
- const _hoisted_7 = {
34
+ const _hoisted_8 = {
41
35
  key: 1,
42
36
  class: "size-3.5 shrink-0"
43
37
  };
44
- const _hoisted_8 = {
38
+ const _hoisted_9 = {
45
39
  key: 2,
46
40
  class: "flex min-w-0 flex-1 flex-col gap-0.5"
47
41
  };
48
- const _hoisted_9 = ["title"];
49
- const _hoisted_10 = { class: "flex opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 has-data-[state=open]:opacity-100" };
50
- const _hoisted_11 = {
42
+ const _hoisted_10 = ["title"];
43
+ const _hoisted_11 = { class: "rounded-sm bg-[color-mix(in_oklab,var(--sk-primary)_20%,transparent)] text-inherit" };
44
+ const _hoisted_12 = { class: "flex opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 has-data-[state=open]:opacity-100" };
45
+ const _hoisted_13 = {
46
+ key: 0,
47
+ class: "px-2 pt-0.5 text-xs text-[var(--sk-danger)]",
48
+ role: "status"
49
+ };
50
+ const _hoisted_14 = {
51
51
  key: 4,
52
52
  class: "px-2.5 py-1.5 text-sm text-[var(--sk-muted)]"
53
53
  };
54
- const OUTLINE_DEBOUNCE_MS = 150;
54
+ const _hoisted_15 = {
55
+ key: 5,
56
+ class: "px-2.5 py-1.5 text-sm text-[var(--sk-muted)]"
57
+ };
55
58
  const _sfc_main = /*@__PURE__*/ defineComponent({
56
59
  __name: "DocumentTree",
57
60
  props: /*@__PURE__*/ mergeModels({
@@ -66,357 +69,117 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
66
69
  const props = __props;
67
70
  /** The folder new documents, folders and host imports go to. Reset to `''` when it is deleted or moved away. */
68
71
  const selectedFolder = useModel(__props, "selectedFolder");
69
- const { expanded, nodeFilters, model } = useTreeView();
70
- const { expand } = model;
71
72
  const { t } = useEditorI18n();
72
- const { importFiles } = useFileImport(() => props.editor);
73
- const { settings } = useEditorSettings();
74
- const { Button: UButton, DropdownMenu: UDropdownMenu, Icon: UIcon, Input: UInput, Tree: UTree, notifier } = useUiKit();
75
- const notify = notifier();
76
- const tree = useStoreRef(() => props.store.tree);
77
- const storedDocuments = useStoreRef(() => props.store.documents);
78
- const documents = computed(() => storedDocuments.value ?? []);
79
- const activeId = useStoreRef(() => props.store.activeId);
80
- const editor = computed(() => props.editor);
81
- /** Virtual mode: block ID of the selected `folder`/`document` composite; `null` = the document itself. */
82
- const virtualTarget = ref(null);
83
- function selectItem(item) {
84
- if (renamingKey.value === item.key) return;
85
- if (item.key === "vroot") {
86
- virtualTarget.value = null;
87
- return;
88
- }
89
- if (item.type === "document") {
90
- selectedFolder.value = item.folder ?? "";
91
- props.store.open(item.id).catch(() => void 0);
92
- } else selectedFolder.value = item.path ?? "";
93
- }
94
- const fsItems = computed(() => tree.value ? [folderItem(tree.value, activeId.value, outlineItems$1.value, selectItem)] : []);
95
- const isEmpty = computed(() => !virtual.value && !!tree.value && !tree.value.folders.length && !tree.value.documents.length);
96
- const virtualRoot = computed(() => virtualRootItem(documents.value.find((d) => d.id === activeId.value)?.title ?? t("tree.rootFallback"), outlineItems$1.value, selectItem));
97
- const unfilteredItems = computed(() => virtual.value ? [virtualRoot.value] : fsItems.value);
98
- const items = computed(() => applyNodeFilters(unfilteredItems.value, nodeFilters.value));
99
- computed(() => settings.value.blocks.structure === "composite" && !!editor.value);
100
- const kinds = computed(() => editor.value ? compositeKindsOf(editor.value) : []);
101
- /**
102
- * What is loaded decides the view: a composite file (open document, composite structure) is the drawer's single root
103
- * when the `blocks.treeRoot` setting says so; otherwise (no document open, headings structure, or nesting files in
104
- * folders allowed) the drawer shows the folders of the store.
105
- */
106
- const virtual = computed(() => settings.value.blocks.treeRoot === "file" && settings.value.blocks.structure === "composite" && !!editor.value);
107
- watch(virtual, (isVirtual) => isVirtual && expand(["vroot"]), { immediate: true });
108
- const outline = shallowRef(EMPTY_OUTLINE);
109
- function refreshOutline() {
110
- outline.value = readOutline(editor.value, settings.value.blocks.structure, t);
73
+ const { Button: UButton, DropdownMenu: UDropdownMenu, Icon: UIcon, Input: UInput, Tree: UTree } = useUiKit();
74
+ const { model, state } = useTreeModel({
75
+ store: () => props.store,
76
+ editor: () => props.editor,
77
+ selectedFolder
78
+ });
79
+ const row = (item) => rowOf(state.value, item, t);
80
+ /** Why dropping the drag on `item` is refused, while the pointer is over it. */
81
+ function refusal(item) {
82
+ const drop = row(item).drop;
83
+ return drop && !drop.ok ? drop.reason : null;
111
84
  }
112
- let outlineTimer;
113
- watch(editor, (instance, _previous, onCleanup) => {
114
- refreshOutline();
115
- if (!instance) return;
116
- const onUpdate = () => {
117
- clearTimeout(outlineTimer);
118
- outlineTimer = setTimeout(refreshOutline, OUTLINE_DEBOUNCE_MS);
119
- };
120
- instance.on("update", onUpdate);
121
- onCleanup(() => {
122
- clearTimeout(outlineTimer);
123
- instance.off("update", onUpdate);
124
- });
125
- }, { immediate: true });
126
- watch(() => settings.value.blocks.structure, refreshOutline);
127
- function selectOutline(item) {
128
- revealOutlineItem(item);
129
- if (virtual.value && item.blockId && (item.kind === "folder" || item.kind === "document")) virtualTarget.value = item.blockId;
85
+ /** UTree reports the keys of the rows it wants open; the model decides what that changes. */
86
+ function onExpanded(next) {
87
+ const wanted = new Set(next);
88
+ const open = new Set(state.value.view.open);
89
+ for (const key of wanted) if (!open.has(key)) model.value.setOpen(key, true);
90
+ for (const key of open) if (!wanted.has(key)) model.value.setOpen(key, false);
130
91
  }
131
- function revealOutlineItem(item) {
132
- if (editor.value && !editor.value.isDestroyed) revealBlockInEditor(editor.value, {
133
- id: item.blockId ?? null,
134
- pos: item.pos
135
- });
92
+ /** The label split around the part the title filter matched, `null` when it did not match here. */
93
+ function labelParts(item) {
94
+ const match = row(item).match;
95
+ if (!match) return null;
96
+ const [at, length] = match;
97
+ return [
98
+ item.label.slice(0, at),
99
+ item.label.slice(at, at + length),
100
+ item.label.slice(at + length)
101
+ ];
136
102
  }
137
- const outlineItems$1 = computed(() => outlineItems(outline.value.nodes, kinds.value, selectOutline));
138
- const collapsedOutline = ref([]);
139
- const outlineParentKeys = computed(() => collectParentKeys(outlineItems$1.value, []));
140
- const treeExpanded = computed({
141
- get: () => [...expanded.value, ...outlineParentKeys.value.filter((key) => !collapsedOutline.value.includes(key))],
142
- set: (value) => {
143
- const open = new Set(value);
144
- expanded.value = value.filter((key) => !outlineParentKeys.value.includes(key));
145
- collapsedOutline.value = outlineParentKeys.value.filter((key) => !open.has(key));
146
- }
147
- });
148
103
  function onChevronClick(event, item) {
149
104
  if (item.type === "root" || item.type === "folder") return;
150
105
  event.stopPropagation();
151
- if (item.type === "composite" || item.type === "heading") {
152
- collapsedOutline.value = collapsedOutline.value.includes(item.key) ? collapsedOutline.value.filter((key) => key !== item.key) : [...collapsedOutline.value, item.key];
153
- return;
154
- }
155
- expanded.value = expanded.value.includes(item.key) ? expanded.value.filter((key) => key !== item.key) : [...expanded.value, item.key];
106
+ model.value.toggle(item.key);
156
107
  }
157
- /** The kinds `item`'s filter can hide below it. */
158
- const filterKinds$1 = (item) => filterKinds(item, {
159
- structure: settings.value.blocks.structure,
160
- activeId: activeId.value,
161
- kinds: kinds.value,
162
- t
163
- });
164
- const hiddenBelow = (item) => nodeFilters.value[item.key] ?? [];
165
- const isFiltered = (item) => hiddenBelow(item).length > 0;
166
- const showFilter = (item) => filterKinds$1(item).length > 0 && (item.type === "root" || item.type === "folder" || !!item.children?.length || isFiltered(item));
167
108
  function filterMenu(item) {
168
- const hidden = hiddenBelow(item);
109
+ const { filterKinds, hiddenKinds } = row(item);
169
110
  const groups = [[{
170
111
  type: "label",
171
112
  label: t("tree.filter.show")
172
- }, ...filterKinds$1(item).map((kind) => ({
113
+ }, ...filterKinds.map((kind) => ({
173
114
  label: kind.label,
174
115
  icon: kind.icon,
175
116
  type: "checkbox",
176
- checked: !hidden.includes(kind.id),
177
- onUpdateChecked: (visible) => model.setKindHidden(item.key, kind.id, !visible),
117
+ checked: !hiddenKinds.includes(kind.id),
118
+ onUpdateChecked: (visible) => model.value.setKindHidden(item.key, kind.id, !visible),
178
119
  onSelect: (event) => event.preventDefault()
179
120
  }))]];
180
- if (hidden.length) groups.push([{
121
+ if (hiddenKinds.length) groups.push([{
181
122
  label: t("tree.filter.reset"),
182
123
  icon: "i-lucide-filter-x",
183
- onSelect: () => model.clearFilter(item.key)
124
+ onSelect: () => model.value.clearFilter(item.key)
184
125
  }]);
185
126
  return groups;
186
127
  }
187
- const hasFilters = computed(() => {
188
- const keys = collectKeys(unfilteredItems.value, /* @__PURE__ */ new Set());
189
- return Object.entries(nodeFilters.value).some(([key, hidden]) => hidden.length > 0 && keys.has(key));
190
- });
191
- watch(tree, (value) => {
192
- if (!value) return;
193
- const paths = /* @__PURE__ */ new Set();
194
- collectFolderPaths(value, paths);
195
- if (!paths.has(selectedFolder.value)) selectedFolder.value = "";
196
- });
197
- const activeFolder = computed(() => documents.value.find((d) => d.id === activeId.value)?.folder);
198
- watch(activeFolder, (folder) => {
199
- expand(ancestorKeys(folder ?? ""));
200
- if (folder !== void 0) selectedFolder.value = folder;
201
- }, { immediate: true });
202
- watch(activeId, (id) => id && expand([`doc:${id}`]), { immediate: true });
203
- /** A folder moved from `from` to `to`: its open/selected state follows it. */
204
- function followFolderMove(from, to) {
205
- model.followFolderMove(from, to);
206
- selectedFolder.value = remapFolderPath(selectedFolder.value, from, to);
207
- expand(ancestorKeys(parentPath(to)));
208
- }
209
- /** Makes a composite's children visible in the outline again. */
210
- function openOutline(blockId) {
211
- collapsedOutline.value = collapsedOutline.value.filter((key) => key !== `outline:${blockId}`);
212
- }
213
- async function importIntoComposite(blockId) {
214
- const files = await pickFiles("*/*");
215
- const instance = editor.value;
216
- if (!files.length || !instance || instance.isDestroyed) return;
217
- await importFiles(instance, files, compositeInsertPos(instance, blockId));
218
- if (blockId) openOutline(blockId);
219
- }
220
- function createCompositeFolder(blockId) {
221
- const instance = editor.value;
222
- if (!instance || instance.isDestroyed) return;
223
- const pos = compositeInsertPos(instance, blockId);
224
- instance.chain().insertContentAt(pos, compositeJSON("folder")).setTextSelection(pos + 2).focus().scrollIntoView().run();
225
- if (blockId) openOutline(blockId);
226
- }
227
- async function createDocumentIn(folder) {
228
- selectedFolder.value = folder;
229
- const doc = await props.store.create(void 0, folder).catch(() => void 0);
230
- if (!doc) return;
231
- expand(ancestorKeys(folder));
232
- await props.store.open(doc.id).catch(() => void 0);
233
- }
234
- const creatingFolder = ref(false);
235
- const folderDraft = ref("");
236
- /** Folder path the folder being named is created in. */
237
- const folderParent = ref("");
238
- const folderError = computed(() => folderDraft.value.trim() ? props.store.validateName(folderDraft.value, folderNamesIn(tree.value, folderParent.value)) : null);
239
- function startCreateFolder(parent) {
240
- selectedFolder.value = parent;
241
- folderParent.value = parent;
242
- folderDraft.value = "";
243
- creatingFolder.value = true;
244
- }
245
- async function commitCreateFolder() {
246
- if (!creatingFolder.value) return;
247
- if (!folderDraft.value.trim()) {
248
- creatingFolder.value = false;
249
- return;
250
- }
251
- if (folderError.value) return;
252
- creatingFolder.value = false;
253
- const parent = folderParent.value;
254
- if (await props.store.createFolder(joinPath(parent, folderDraft.value.trim())).then(() => true, () => false)) expand(ancestorKeys(parent));
255
- }
256
- /**
257
- * What can be created below `item`: folders of the store take documents and sub-folders, the open file (as the root or
258
- * as a document row) and its Ordner/Dokument composites take Ordner and imported Dokument Bausteine. Other rows take
259
- * nothing. Folders also list „Umbenennen“ here: renaming a document happens in the editor's title field.
260
- */
261
128
  function addMenu(item) {
262
- const groups = [];
263
- if (item.key !== "vroot" && (item.type === "root" || item.type === "folder")) {
264
- const path = item.path;
265
- groups.push([{
266
- label: t("tree.menu.newDocument"),
267
- icon: "i-lucide-file-plus",
268
- onSelect: () => void createDocumentIn(path)
269
- }, {
270
- label: item.type === "root" ? t("tree.menu.newFolder") : t("tree.menu.newSubfolder"),
271
- icon: "i-lucide-folder-plus",
272
- onSelect: () => startCreateFolder(path)
273
- }]);
274
- } else if (holdsComposites(item, {
275
- structure: settings.value.blocks.structure,
276
- editor: editor.value,
277
- activeId: activeId.value
278
- })) {
279
- const blockId = item.blockId ?? null;
280
- groups.push([{
281
- label: t("tree.menu.newCompositeFolder"),
282
- icon: "i-lucide-folder-plus",
283
- onSelect: () => {
284
- createCompositeFolder(blockId);
285
- if (!blockId) expand([item.key]);
286
- }
287
- }, {
288
- label: t("tree.menu.importFile"),
289
- icon: "i-lucide-file-up",
290
- onSelect: () => {
291
- importIntoComposite(blockId);
292
- if (!blockId) expand([item.key]);
293
- }
294
- }]);
295
- }
296
- if (item.type === "folder") groups.push([{
297
- label: t("tree.menu.rename"),
298
- icon: "i-lucide-pencil",
299
- onSelect: () => startRename(item)
300
- }]);
301
- return groups;
302
- }
303
- const renamingKey = ref(null);
304
- const renamingItem = shallowRef(null);
305
- const renameDraft = ref("");
306
- function startRename(item) {
307
- renamingItem.value = item;
308
- renamingKey.value = item.key;
309
- renameDraft.value = item.label;
310
- }
311
- const renameError = computed(() => {
312
- const item = renamingItem.value;
313
- if (!item || renamingKey.value === null || renameDraft.value.trim() === item.label) return null;
314
- return props.store.validateName(renameDraft.value, folderNamesIn(tree.value, parentPath(item.path), item.path));
315
- });
316
- function cancelRename() {
317
- renamingKey.value = null;
318
- renamingItem.value = null;
319
- }
320
- function onRenameBlur() {
321
- if (renamingKey.value === null) return;
322
- if (renameError.value) {
323
- notify({
324
- title: t("tree.folder.renameFailed"),
325
- description: renameError.value,
326
- kind: "warning",
327
- icon: "i-lucide-circle-alert"
328
- });
329
- cancelRename();
330
- return;
331
- }
332
- return commitRename();
333
- }
334
- async function commitRename() {
335
- const item = renamingItem.value;
336
- if (!item || renamingKey.value === null) return;
337
- if (renameError.value) return;
338
- const name = renameDraft.value.trim();
339
- cancelRename();
340
- if (name === item.label) return;
341
- const to = joinPath(parentPath(item.path), name);
342
- if (await props.store.moveFolder(item.path, to).then(() => true, () => false)) followFolderMove(item.path, to);
343
- }
344
- async function removeWithUndo(id, folder) {
345
- const removed = await props.store.remove(id, folder).catch(() => void 0);
346
- if (!removed) return;
347
- notify({
348
- title: t("tree.removed"),
349
- description: removed.title,
350
- icon: "i-lucide-trash-2",
351
- action: {
352
- label: t("tree.undo"),
353
- onClick: () => restore(removed)
354
- }
355
- });
356
- }
357
- async function restore(removed) {
358
- const restored = await removed.restore().catch(() => void 0);
359
- if (restored) await props.store.open(restored.id).catch(() => void 0);
360
- }
361
- function removeItem(item) {
362
- if (item.type === "document") return removeWithUndo(item.id, item.folder ?? "");
363
- return props.store.removeFolder(item.path).catch(() => void 0);
364
- }
365
- const dragging = ref(null);
366
- const dropKey = ref(null);
367
- function isDraggable$1(item) {
368
- return renamingKey.value !== item.key && isDraggable(item, virtual.value);
129
+ return model.value.addMenu(item).map((group) => group.map((entry) => ({
130
+ label: entry.label,
131
+ icon: entry.icon,
132
+ onSelect: entry.run
133
+ })));
369
134
  }
370
135
  function onDragStart(event, item) {
371
- if (!isDraggable$1(item) || !event.dataTransfer) return event.preventDefault();
372
- const payload = dragPayloadOf(item);
373
- dragging.value = payload;
136
+ const payload = model.value.dragStart(item);
137
+ if (!payload) return event.preventDefault();
138
+ if (!event.dataTransfer) return model.value.dragEnd();
374
139
  event.dataTransfer.setData(DRAG_MIME, JSON.stringify(payload));
375
140
  event.dataTransfer.effectAllowed = "move";
376
141
  }
377
142
  function onDragOver(event, item) {
378
- if (!canDrop(dragging.value, item, {
379
- virtual: virtual.value,
380
- editor: editor.value
381
- })) return;
382
- event.preventDefault();
383
- if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
384
- dropKey.value = item.key;
143
+ const verdict = model.value.dragOver(item);
144
+ if (!verdict) return;
145
+ if (verdict.ok) event.preventDefault();
146
+ if (event.dataTransfer) event.dataTransfer.dropEffect = verdict.ok ? "move" : "none";
385
147
  }
386
148
  function onDragLeave(event, item) {
387
- if (dropKey.value === item.key && !event.currentTarget.contains(event.relatedTarget)) dropKey.value = null;
149
+ if (!event.currentTarget.contains(event.relatedTarget)) model.value.dragLeave(item);
388
150
  }
389
- function endDrag() {
390
- dragging.value = null;
391
- dropKey.value = null;
392
- }
393
- async function onDrop(event, target) {
394
- const raw = event.dataTransfer?.getData(DRAG_MIME);
395
- endDrag();
396
- if (!raw) return;
151
+ function onDrop(event, item) {
152
+ if (!state.value.drag) return;
397
153
  event.preventDefault();
398
- const source = JSON.parse(raw);
399
- if (!canDrop(source, target, {
400
- virtual: virtual.value,
401
- editor: editor.value
402
- })) return;
403
- if (source.type === "composite") {
404
- const instance = editor.value;
405
- const targetId = target.key === "vroot" ? null : target.blockId;
406
- if (instance && moveBlockInto(instance, source.blockId, targetId) && targetId) openOutline(targetId);
407
- return;
408
- }
409
- const targetPath = target.path;
410
- if (source.type === "document") {
411
- if (await props.store.move(source.id, targetPath).then(() => true, () => false)) expand(ancestorKeys(targetPath));
412
- return;
413
- }
414
- const to = joinPath(targetPath, source.path.slice(source.path.lastIndexOf("/") + 1));
415
- if (await props.store.moveFolder(source.path, to).then(() => true, () => false)) followFolderMove(source.path, to);
154
+ return model.value.drop(item);
416
155
  }
417
156
  return (_ctx, _cache) => {
418
157
  return openBlock(), createElementBlock("div", _hoisted_1, [
419
- hasFilters.value ? (openBlock(), createElementBlock("div", _hoisted_2, [createVNode(unref(UButton), {
158
+ createVNode(unref(UInput), {
159
+ "model-value": unref(state).filterText,
160
+ icon: "i-lucide-search",
161
+ size: "sm",
162
+ placeholder: unref(t)("tree.filterText.placeholder"),
163
+ "aria-label": unref(t)("tree.filterText.placeholder"),
164
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => unref(model).setFilterText($event)),
165
+ onKeydown: _cache[2] || (_cache[2] = withKeys(($event) => unref(model).setFilterText(""), ["esc"]))
166
+ }, createSlots({ _: 2 }, [unref(state).filterText ? {
167
+ name: "trailing",
168
+ fn: withCtx(() => [createVNode(unref(UButton), {
169
+ icon: "i-lucide-x",
170
+ size: "xs",
171
+ color: "neutral",
172
+ variant: "link",
173
+ "aria-label": unref(t)("tree.filterText.clear"),
174
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(model).setFilterText(""))
175
+ }, null, 8, ["aria-label"])]),
176
+ key: "0"
177
+ } : void 0]), 1032, [
178
+ "model-value",
179
+ "placeholder",
180
+ "aria-label"
181
+ ]),
182
+ unref(state).view.hasKindFilters ? (openBlock(), createElementBlock("div", _hoisted_2, [createVNode(unref(UButton), {
420
183
  icon: "i-lucide-filter-x",
421
184
  label: unref(t)("tree.filter.reset"),
422
185
  size: "xs",
@@ -424,93 +187,101 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
424
187
  variant: "subtle",
425
188
  onClick: unref(model).clearAllFilters
426
189
  }, null, 8, ["label", "onClick"])])) : createCommentVNode("v-if", true),
427
- creatingFolder.value ? (openBlock(), createElementBlock("div", _hoisted_3, [createVNode(unref(UInput), {
428
- modelValue: folderDraft.value,
429
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => folderDraft.value = $event),
190
+ unref(state).creatingFolder ? (openBlock(), createElementBlock("div", _hoisted_3, [createVNode(unref(UInput), {
191
+ "model-value": unref(state).creatingFolder.draft,
430
192
  size: "sm",
431
193
  autofocus: "",
432
- color: folderError.value ? "error" : void 0,
433
- highlight: !!folderError.value,
434
- placeholder: folderParent.value ? unref(t)("tree.folder.placeholderIn", { parent: folderParent.value }) : unref(t)("tree.folder.placeholder"),
194
+ color: unref(state).creatingFolder.error ? "error" : void 0,
195
+ highlight: !!unref(state).creatingFolder.error,
196
+ placeholder: unref(state).creatingFolder.parent ? unref(t)("tree.folder.placeholderIn", { parent: unref(state).creatingFolder.parent }) : unref(t)("tree.folder.placeholder"),
435
197
  "aria-label": unref(t)("tree.folder.name"),
436
- "aria-invalid": !!folderError.value,
437
- onKeydown: [withKeys(commitCreateFolder, ["enter"]), _cache[1] || (_cache[1] = withKeys(($event) => creatingFolder.value = false, ["esc"]))],
438
- onBlur: _cache[2] || (_cache[2] = ($event) => creatingFolder.value = false)
198
+ "aria-invalid": !!unref(state).creatingFolder.error,
199
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => unref(model).setFolderDraft($event)),
200
+ onKeydown: [withKeys(unref(model).commitCreateFolder, ["enter"]), withKeys(unref(model).cancelCreateFolder, ["esc"])],
201
+ onBlur: unref(model).cancelCreateFolder
439
202
  }, null, 8, [
440
- "modelValue",
203
+ "model-value",
441
204
  "color",
442
205
  "highlight",
443
206
  "placeholder",
444
207
  "aria-label",
445
- "aria-invalid"
446
- ]), folderError.value ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString(folderError.value), 1)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
447
- !unref(tree) && !virtual.value ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString(unref(tree) === null ? unref(t)("tree.loadFailed") : unref(t)("tree.loading")), 1)) : (openBlock(), createBlock(unref(UTree), {
208
+ "aria-invalid",
209
+ "onKeydown",
210
+ "onBlur"
211
+ ]), unref(state).creatingFolder.error ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString(unref(state).creatingFolder.error), 1)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
212
+ !unref(state).tree && !unref(state).virtual ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString(unref(state).tree === null ? unref(t)("tree.loadFailed") : unref(t)("tree.loading")), 1)) : (openBlock(), createBlock(unref(UTree), {
448
213
  key: 3,
449
- expanded: treeExpanded.value,
450
- "onUpdate:expanded": _cache[9] || (_cache[9] = ($event) => treeExpanded.value = $event),
451
- items: items.value,
214
+ expanded: unref(state).view.open,
215
+ items: unref(state).view.items,
452
216
  "get-key": (item) => item.key,
453
217
  size: "sm",
454
- "aria-label": unref(t)("tree.aria")
218
+ "aria-label": unref(t)("tree.aria"),
219
+ "onUpdate:expanded": onExpanded
455
220
  }, {
456
- "item-wrapper": withCtx(({ item, expanded: isOpen }) => [createElementVNode("div", {
221
+ "item-wrapper": withCtx(({ item }) => [createElementVNode("div", _hoisted_6, [createElementVNode("div", {
457
222
  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)]", [
458
- item.id !== void 0 && item.id === unref(activeId) && "bg-[color-mix(in_oklab,var(--sk-primary)_10%,transparent)] font-medium text-[var(--sk-primary)]",
459
- item.type !== "document" && item.path === selectedFolder.value && "bg-[var(--sk-bg-elevated)]",
460
- virtual.value && (item.key === unref("vroot") ? virtualTarget.value === null : !!item.blockId && item.blockId === virtualTarget.value) && "bg-[var(--sk-bg-elevated)]",
461
- dropKey.value === item.key && "ring-1 ring-[var(--sk-primary)]"
223
+ row(item).active && "bg-[color-mix(in_oklab,var(--sk-primary)_10%,transparent)] font-medium text-[var(--sk-primary)]",
224
+ row(item).selected && "bg-[var(--sk-bg-elevated)]",
225
+ row(item).drop?.ok && "ring-1 ring-[var(--sk-primary)]",
226
+ refusal(item) && "bg-[color-mix(in_oklab,var(--sk-danger)_10%,transparent)] ring-1 ring-[var(--sk-danger)]"
462
227
  ]]),
463
- draggable: isDraggable$1(item),
228
+ draggable: unref(model).isDraggable(item),
464
229
  onDragstart: ($event) => onDragStart($event, item),
465
230
  onDragover: ($event) => onDragOver($event, item),
466
231
  onDragleave: ($event) => onDragLeave($event, item),
467
232
  onDrop: ($event) => onDrop($event, item),
468
- onDragend: endDrag
233
+ onDragend: _cache[10] || (_cache[10] = (...args) => unref(model).dragEnd && unref(model).dragEnd(...args))
469
234
  }, [
470
- item.type === "root" || item.type === "folder" || item.children?.length ? (openBlock(), createBlock(unref(UIcon), {
235
+ row(item).expandable ? (openBlock(), createBlock(unref(UIcon), {
471
236
  key: 0,
472
237
  name: "i-lucide-chevron-right",
473
- class: normalizeClass(["size-3.5 shrink-0 text-[var(--sk-muted)] transition-transform", isOpen && "rotate-90"]),
238
+ class: normalizeClass(["size-3.5 shrink-0 text-[var(--sk-muted)] transition-transform", row(item).open && "rotate-90"]),
474
239
  onClick: ($event) => onChevronClick($event, item)
475
- }, null, 8, ["class", "onClick"])) : item.type === "composite" || item.type === "heading" ? (openBlock(), createElementBlock("span", _hoisted_7)) : createCommentVNode("v-if", true),
240
+ }, null, 8, ["class", "onClick"])) : item.type === "composite" || item.type === "heading" ? (openBlock(), createElementBlock("span", _hoisted_8)) : createCommentVNode("v-if", true),
476
241
  createVNode(unref(UIcon), {
477
242
  name: item.icon,
478
243
  class: "size-4 shrink-0"
479
244
  }, null, 8, ["name"]),
480
- renamingKey.value === item.key ? (openBlock(), createElementBlock("div", _hoisted_8, [createVNode(unref(UInput), {
481
- modelValue: renameDraft.value,
482
- "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => renameDraft.value = $event),
245
+ row(item).renaming ? (openBlock(), createElementBlock("div", _hoisted_9, [createVNode(unref(UInput), {
246
+ "model-value": row(item).renaming.draft,
483
247
  size: "xs",
484
248
  class: "min-w-0",
485
249
  autofocus: "",
486
- color: renameError.value ? "error" : void 0,
487
- highlight: !!renameError.value,
250
+ color: row(item).renaming.error ? "error" : void 0,
251
+ highlight: !!row(item).renaming.error,
488
252
  "aria-label": unref(t)("tree.folder.name"),
489
- "aria-invalid": !!renameError.value,
490
- onFocus: _cache[4] || (_cache[4] = ($event) => $event.target.select()),
491
- onClick: _cache[5] || (_cache[5] = withModifiers(() => {}, ["stop"])),
253
+ "aria-invalid": !!row(item).renaming.error,
254
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => unref(model).setRenameDraft($event)),
255
+ onFocus: _cache[5] || (_cache[5] = ($event) => $event.target.select()),
256
+ onClick: _cache[6] || (_cache[6] = withModifiers(() => {}, ["stop"])),
492
257
  onKeydown: [
493
- _cache[6] || (_cache[6] = withModifiers(() => {}, ["stop"])),
494
- withKeys(commitRename, ["enter"]),
495
- withKeys(cancelRename, ["esc"])
258
+ _cache[7] || (_cache[7] = withModifiers(() => {}, ["stop"])),
259
+ withKeys(unref(model).commitRename, ["enter"]),
260
+ withKeys(unref(model).cancelRename, ["esc"])
496
261
  ],
497
- onBlur: onRenameBlur
262
+ onBlur: unref(model).blurRename
498
263
  }, null, 8, [
499
- "modelValue",
264
+ "model-value",
500
265
  "color",
501
266
  "highlight",
502
267
  "aria-label",
503
- "aria-invalid"
504
- ]), renameError.value ? (openBlock(), createElementBlock("p", {
268
+ "aria-invalid",
269
+ "onKeydown",
270
+ "onBlur"
271
+ ]), row(item).renaming.error ? (openBlock(), createElementBlock("p", {
505
272
  key: 0,
506
273
  class: "text-xs text-[var(--sk-danger)]",
507
274
  role: "alert",
508
- onClick: _cache[7] || (_cache[7] = withModifiers(() => {}, ["stop"]))
509
- }, toDisplayString(renameError.value), 1)) : createCommentVNode("v-if", true)])) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
275
+ onClick: _cache[8] || (_cache[8] = withModifiers(() => {}, ["stop"]))
276
+ }, toDisplayString(row(item).renaming.error), 1)) : createCommentVNode("v-if", true)])) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
510
277
  createElementVNode("span", {
511
278
  class: "min-w-0 flex-1 truncate",
512
279
  title: item.label
513
- }, toDisplayString(item.label), 9, _hoisted_9),
280
+ }, [labelParts(item) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
281
+ createTextVNode(toDisplayString(labelParts(item)[0]), 1),
282
+ createElementVNode("mark", _hoisted_11, toDisplayString(labelParts(item)[1]), 1),
283
+ createTextVNode(toDisplayString(labelParts(item)[2]), 1)
284
+ ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(item.label), 1)], 64))], 8, _hoisted_10),
514
285
  item.hasSummary ? (openBlock(), createBlock(unref(UIcon), {
515
286
  key: 0,
516
287
  name: "i-lucide-text-quote",
@@ -519,8 +290,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
519
290
  }, null, 8, ["title"])) : createCommentVNode("v-if", true),
520
291
  createElementVNode("div", {
521
292
  class: "flex shrink-0",
522
- onClick: _cache[8] || (_cache[8] = withModifiers(() => {}, ["stop"]))
523
- }, [showFilter(item) ? (openBlock(), createBlock(unref(UDropdownMenu), {
293
+ onClick: _cache[9] || (_cache[9] = withModifiers(() => {}, ["stop"]))
294
+ }, [row(item).showFilter ? (openBlock(), createBlock(unref(UDropdownMenu), {
524
295
  key: 0,
525
296
  items: filterMenu(item),
526
297
  content: { align: "start" }
@@ -528,9 +299,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
528
299
  default: withCtx(() => [createVNode(unref(UButton), {
529
300
  icon: "i-lucide-filter",
530
301
  size: "xs",
531
- color: isFiltered(item) ? "primary" : "neutral",
532
- variant: isFiltered(item) ? "soft" : "ghost",
533
- class: normalizeClass(!isFiltered(item) && "opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100"),
302
+ color: row(item).hiddenKinds.length ? "primary" : "neutral",
303
+ variant: row(item).hiddenKinds.length ? "soft" : "ghost",
304
+ class: normalizeClass(!row(item).hiddenKinds.length && "opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100"),
534
305
  title: unref(t)("tree.filter.title"),
535
306
  "aria-label": unref(t)("tree.filter.title")
536
307
  }, null, 8, [
@@ -541,7 +312,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
541
312
  "aria-label"
542
313
  ])]),
543
314
  _: 2
544
- }, 1032, ["items"])) : createCommentVNode("v-if", true), createElementVNode("div", _hoisted_10, [
315
+ }, 1032, ["items"])) : createCommentVNode("v-if", true), createElementVNode("div", _hoisted_12, [
545
316
  addMenu(item).length ? (openBlock(), createBlock(unref(UDropdownMenu), {
546
317
  key: 0,
547
318
  items: addMenu(item),
@@ -572,11 +343,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
572
343
  variant: "ghost",
573
344
  "aria-label": unref(t)("tree.delete"),
574
345
  "loading-auto": "",
575
- onClick: ($event) => removeItem(item)
346
+ onClick: ($event) => unref(model).remove(item)
576
347
  }, null, 8, ["aria-label", "onClick"])) : createCommentVNode("v-if", true)
577
348
  ])])
578
349
  ], 64))
579
- ], 42, _hoisted_6)]),
350
+ ], 42, _hoisted_7), refusal(item) ? (openBlock(), createElementBlock("p", _hoisted_13, toDisplayString(refusal(item)), 1)) : createCommentVNode("v-if", true)])]),
580
351
  _: 3
581
352
  }, 8, [
582
353
  "expanded",
@@ -584,7 +355,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
584
355
  "get-key",
585
356
  "aria-label"
586
357
  ])),
587
- isEmpty.value ? (openBlock(), createElementBlock("p", _hoisted_11, toDisplayString(unref(t)("tree.empty")), 1)) : createCommentVNode("v-if", true)
358
+ unref(state).view.noMatches ? (openBlock(), createElementBlock("p", _hoisted_14, toDisplayString(unref(t)("tree.noMatches")), 1)) : createCommentVNode("v-if", true),
359
+ unref(state).view.isEmpty ? (openBlock(), createElementBlock("p", _hoisted_15, toDisplayString(unref(t)("tree.empty")), 1)) : createCommentVNode("v-if", true)
588
360
  ]);
589
361
  };
590
362
  }