@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,6 +1,7 @@
1
1
  import { compositeKind } from "../kinds.js";
2
+ import { basketOf, titleHiddenOf } from "../baskets.js";
2
3
  import { derivationOf } from "../derivation.js";
3
- import { compositeKindsOf } from "../nodes.js";
4
+ import { compositeBasketsOf, compositeKindsOf } from "../nodes.js";
4
5
  import { cn } from "../../../react/ui/utils.js";
5
6
  import { useStore } from "../../../react/use-store.js";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -14,13 +15,25 @@ function CompositeView({ editor, node, selected }) {
14
15
  const expanded = useStore(editor.storage.composite.expanded);
15
16
  const id = node.attrs.id;
16
17
  const collapsed = typeof id === "string" && id !== "" && derivationOf(node) !== null && !expanded.has(id);
17
- const placeholderVars = { "--composite-title-placeholder": cssString(kind.titlePlaceholder) };
18
+ const basket = basketOf(node);
19
+ const basketColor = compositeBasketsOf(editor).find((candidate) => candidate.id === basket)?.color;
20
+ const kindTone = kind.chrome?.tone || void 0;
21
+ const revealedTitles = useStore(editor.storage.composite.revealedTitles);
22
+ const titleHidden = titleHiddenOf(node) && !(typeof id === "string" && revealedTitles.has(id));
23
+ const placeholderVars = {
24
+ "--composite-title-placeholder": cssString(kind.titlePlaceholder),
25
+ ...basketColor ? { "--sk-basket-color": basketColor } : {},
26
+ ...kindTone ? { "--sk-kind-tone": kindTone } : {}
27
+ };
18
28
  return /* @__PURE__ */ jsxs(NodeViewWrapper, {
19
29
  as: "section",
20
30
  className: cn("composite", collapsed && "is-collapsed", selected && "is-selected rounded-md ring-1 ring-primary"),
21
31
  "data-type": "composite",
22
32
  "data-kind": node.attrs.kind,
23
33
  "data-id": node.attrs.id || void 0,
34
+ "data-basket": basket ?? void 0,
35
+ "data-kind-tone": kindTone ? "" : void 0,
36
+ "data-title-hidden": titleHidden ? "" : void 0,
24
37
  style: placeholderVars,
25
38
  children: [/* @__PURE__ */ jsx("span", {
26
39
  className: "composite__toggle",
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeView.js","names":[],"sources":["../../../../src/features/composites/react/CompositeView.tsx"],"sourcesContent":["import { NodeViewContent, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'\nimport type { CSSProperties } from 'react'\nimport { cn } from '../../../react/ui/utils'\nimport { compositeKind } from '../kinds'\nimport { useStore } from '../../../react/use-store'\nimport { derivationOf } from '../derivation'\nimport { compositeKindsOf } from '../nodes'\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n\n/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */\nexport function CompositeView({ editor, node, selected }: NodeViewProps) {\n const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind))\n // A derived Baustein (one with a `meta.derivation`) shows collapsed to a faded preview until it is opened; the content\n // stays laid out (CSS clips it), so editing positions are unaffected. The chrome's chevron and a caret inside open it.\n const expanded = useStore(editor.storage.composite.expanded)\n const id: unknown = node.attrs.id\n const collapsed = typeof id === 'string' && id !== '' && derivationOf(node) !== null && !expanded.has(id)\n // Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\n const placeholderVars = { '--composite-title-placeholder': cssString(kind.titlePlaceholder) } as CSSProperties\n return (\n <NodeViewWrapper\n as=\"section\"\n className={cn('composite', collapsed && 'is-collapsed', selected && 'is-selected rounded-md ring-1 ring-primary')}\n data-type=\"composite\"\n data-kind={node.attrs.kind}\n data-id={node.attrs.id || undefined}\n style={placeholderVars}\n >\n {/* Anchor of the kind icon on the left border: it only takes the icon's place and size. The composite chrome overlay\n measures it and draws the icon as the button that opens the details popover and drags the composite. */}\n <span className=\"composite__toggle\" contentEditable={false} aria-hidden=\"true\" />\n <NodeViewContent className=\"composite__content\" />\n </NodeViewWrapper>\n )\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;;AAG9F,SAAgB,cAAc,EAAE,QAAQ,MAAM,YAA2B;CACvE,MAAM,OAAO,cAAc,iBAAiB,MAAM,GAAG,OAAO,KAAK,MAAM,IAAI,CAAC;CAG5E,MAAM,WAAW,SAAS,OAAO,QAAQ,UAAU,QAAQ;CAC3D,MAAM,KAAc,KAAK,MAAM;CAC/B,MAAM,YAAY,OAAO,OAAO,YAAY,OAAO,MAAM,aAAa,IAAI,MAAM,QAAQ,CAAC,SAAS,IAAI,EAAE;CAExG,MAAM,kBAAkB,EAAE,iCAAiC,UAAU,KAAK,gBAAgB,EAAE;CAC5F,OACE,qBAAC,iBAAD;EACE,IAAG;EACH,WAAW,GAAG,aAAa,aAAa,gBAAgB,YAAY,4CAA4C;EAChH,aAAU;EACV,aAAW,KAAK,MAAM;EACtB,WAAS,KAAK,MAAM,MAAM,KAAA;EAC1B,OAAO;EANT,UAAA,CAUE,oBAAC,QAAD;GAAM,WAAU;GAAoB,iBAAiB;GAAO,eAAY;EAAQ,CAAA,GAChF,oBAAC,iBAAD,EAAiB,WAAU,qBAAsB,CAAA,CAClC;;AAErB"}
1
+ {"version":3,"file":"CompositeView.js","names":[],"sources":["../../../../src/features/composites/react/CompositeView.tsx"],"sourcesContent":["import { NodeViewContent, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'\nimport type { CSSProperties } from 'react'\nimport { cn } from '../../../react/ui/utils'\nimport { basketOf, titleHiddenOf } from '../baskets'\nimport { compositeKind } from '../kinds'\nimport { useStore } from '../../../react/use-store'\nimport { derivationOf } from '../derivation'\nimport { compositeBasketsOf, compositeKindsOf } from '../nodes'\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n\n/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */\nexport function CompositeView({ editor, node, selected }: NodeViewProps) {\n const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind))\n // A derived Baustein (one with a `meta.derivation`) shows collapsed to a faded preview until it is opened; the content\n // stays laid out (CSS clips it), so editing positions are unaffected. The chrome's chevron and a caret inside open it.\n const expanded = useStore(editor.storage.composite.expanded)\n const id: unknown = node.attrs.id\n const collapsed = typeof id === 'string' && id !== '' && derivationOf(node) !== null && !expanded.has(id)\n // Colour basket (`meta.basket`): `data-basket` carries the id, the stripe takes the basket's colour from `--sk-basket-color`.\n const basket = basketOf(node)\n const basketColor = compositeBasketsOf(editor).find(candidate => candidate.id === basket)?.color\n // Kind tone (`CompositeKind.chrome.tone`): `data-kind-tone` marks the wrapper, the surface reads the colour from `--sk-kind-tone`.\n const kindTone = kind.chrome?.tone || undefined\n // A hidden title (`meta.titleHidden`) stays hidden until a caret enters it (`revealedTitles`, see `CompositeNode`).\n const revealedTitles = useStore(editor.storage.composite.revealedTitles)\n const titleHidden = titleHiddenOf(node) && !(typeof id === 'string' && revealedTitles.has(id))\n // Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\n const placeholderVars = {\n '--composite-title-placeholder': cssString(kind.titlePlaceholder),\n ...(basketColor ? { '--sk-basket-color': basketColor } : {}),\n ...(kindTone ? { '--sk-kind-tone': kindTone } : {}),\n } as CSSProperties\n return (\n <NodeViewWrapper\n as=\"section\"\n className={cn('composite', collapsed && 'is-collapsed', selected && 'is-selected rounded-md ring-1 ring-primary')}\n data-type=\"composite\"\n data-kind={node.attrs.kind}\n data-id={node.attrs.id || undefined}\n data-basket={basket ?? undefined}\n data-kind-tone={kindTone ? '' : undefined}\n data-title-hidden={titleHidden ? '' : undefined}\n style={placeholderVars}\n >\n {/* Anchor of the kind icon on the left border: it only takes the icon's place and size. The composite chrome overlay\n measures it and draws the icon as the button that opens the details popover and drags the composite. */}\n <span className=\"composite__toggle\" contentEditable={false} aria-hidden=\"true\" />\n <NodeViewContent className=\"composite__content\" />\n </NodeViewWrapper>\n )\n}\n"],"mappings":";;;;;;;;;;AAUA,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;;AAG9F,SAAgB,cAAc,EAAE,QAAQ,MAAM,YAA2B;CACvE,MAAM,OAAO,cAAc,iBAAiB,MAAM,GAAG,OAAO,KAAK,MAAM,IAAI,CAAC;CAG5E,MAAM,WAAW,SAAS,OAAO,QAAQ,UAAU,QAAQ;CAC3D,MAAM,KAAc,KAAK,MAAM;CAC/B,MAAM,YAAY,OAAO,OAAO,YAAY,OAAO,MAAM,aAAa,IAAI,MAAM,QAAQ,CAAC,SAAS,IAAI,EAAE;CAExG,MAAM,SAAS,SAAS,IAAI;CAC5B,MAAM,cAAc,mBAAmB,MAAM,CAAC,CAAC,MAAK,cAAa,UAAU,OAAO,MAAM,CAAC,EAAE;CAE3F,MAAM,WAAW,KAAK,QAAQ,QAAQ,KAAA;CAEtC,MAAM,iBAAiB,SAAS,OAAO,QAAQ,UAAU,cAAc;CACvE,MAAM,cAAc,cAAc,IAAI,KAAK,EAAE,OAAO,OAAO,YAAY,eAAe,IAAI,EAAE;CAE5F,MAAM,kBAAkB;EACtB,iCAAiC,UAAU,KAAK,gBAAgB;EAChE,GAAI,cAAc,EAAE,qBAAqB,YAAY,IAAI,CAAC;EAC1D,GAAI,WAAW,EAAE,kBAAkB,SAAS,IAAI,CAAC;CACnD;CACA,OACE,qBAAC,iBAAD;EACE,IAAG;EACH,WAAW,GAAG,aAAa,aAAa,gBAAgB,YAAY,4CAA4C;EAChH,aAAU;EACV,aAAW,KAAK,MAAM;EACtB,WAAS,KAAK,MAAM,MAAM,KAAA;EAC1B,eAAa,UAAU,KAAA;EACvB,kBAAgB,WAAW,KAAK,KAAA;EAChC,qBAAmB,cAAc,KAAK,KAAA;EACtC,OAAO;EATT,UAAA,CAaE,oBAAC,QAAD;GAAM,WAAU;GAAoB,iBAAiB;GAAO,eAAY;EAAQ,CAAA,GAChF,oBAAC,iBAAD,EAAiB,WAAU,qBAAsB,CAAA,CAClC;;AAErB"}
@@ -2,7 +2,7 @@ import { derivationOf } from "../derivation.js";
2
2
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
3
3
  import { cn } from "../../../react/ui/utils.js";
4
4
  import { Icon } from "../../../react/Icon.js";
5
- import { derivationDetailsOf, derivationMethodLabel } from "../derived-chrome.js";
5
+ import { derivationDetailsOf, derivationIsForeign, derivationMethodLabel } from "../derived-chrome.js";
6
6
  import { formatDate } from "../meta-display.js";
7
7
  import { useMemo } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -24,6 +24,7 @@ function DerivationBadge({ editor, node, detailed }) {
24
24
  ]);
25
25
  if (!derivation) return null;
26
26
  const method = derivationMethodLabel(t, derivation.method);
27
+ const foreign = derivationIsForeign(editor, derivation);
27
28
  const created = derivation.createdAt ? formatDate(derivation.createdAt) : "";
28
29
  if (!detailed) return /* @__PURE__ */ jsxs("div", {
29
30
  className: "flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground",
@@ -35,6 +36,7 @@ function DerivationBadge({ editor, node, detailed }) {
35
36
  children: [
36
37
  t("composites.derivation.badge"),
37
38
  method,
39
+ foreign ? t("composites.derivation.foreign") : "",
38
40
  created
39
41
  ].filter(Boolean).join(" · ")
40
42
  })]
@@ -53,6 +55,13 @@ function DerivationBadge({ editor, node, detailed }) {
53
55
  className: "size-3.5"
54
56
  }), t("composites.derivation.badge")]
55
57
  }),
58
+ details.foreign && /* @__PURE__ */ jsxs("span", {
59
+ className: cn(CHIP, "text-muted-foreground"),
60
+ children: [/* @__PURE__ */ jsx(Icon, {
61
+ name: "i-lucide-file-symlink",
62
+ className: "size-3.5"
63
+ }), t("composites.derivation.foreign")]
64
+ }),
56
65
  details.stale && /* @__PURE__ */ jsxs("span", {
57
66
  className: cn(CHIP, "text-(--sk-warning)"),
58
67
  children: [/* @__PURE__ */ jsx(Icon, {
@@ -1 +1 @@
1
- {"version":3,"file":"DerivationBadge.js","names":[],"sources":["../../../../src/features/composites/react/DerivationBadge.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { useMemo } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { derivationOf } from '../derivation'\nimport { derivationDetailsOf, derivationMethodLabel } from '../derived-chrome'\nimport { formatDate } from '../meta-display'\n\nconst CHIP = 'inline-flex h-5 shrink-0 items-center gap-1 rounded-sm px-1.5 text-xs leading-none whitespace-nowrap'\n\n/**\n * Where a derived Baustein comes from. Compact (the `derivation` field type): the „abgeleitet“ badge with method and\n * date. `detailed` (the details card): also the model, whether the source changed („Quelle geändert“), whether the body\n * was edited since it was generated („bearbeitet“) and a link to the stored raw output. The detailed variant hashes\n * the body, so it belongs only where one Baustein is shown.\n */\nexport function DerivationBadge({ editor, node, detailed }: { editor: Editor, node: ProseMirrorNode, detailed?: boolean }) {\n const { t } = useEditorI18n()\n const derivation = derivationOf(node)\n const details = useMemo(() => detailed ? derivationDetailsOf(editor, node) : null, [detailed, editor, node])\n if (!derivation) return null\n const method = derivationMethodLabel(t, derivation.method)\n const created = derivation.createdAt ? formatDate(derivation.createdAt) : ''\n\n if (!detailed) {\n return (\n <div className=\"flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground\">\n <Icon name=\"i-lucide-git-branch\" className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">{[t('composites.derivation.badge'), method, created].filter(Boolean).join(' · ')}</span>\n </div>\n )\n }\n if (!details) return null\n\n return (\n <div className=\"flex flex-col gap-1.5 rounded-md p-2 text-xs ring-1 ring-border\">\n <div className=\"flex flex-wrap items-center gap-1\">\n <span className={cn(CHIP, 'text-muted-foreground')}>\n <Icon name=\"i-lucide-git-branch\" className=\"size-3.5\" />{t('composites.derivation.badge')}\n </span>\n {details.stale && (\n <span className={cn(CHIP, 'text-(--sk-warning)')}>\n <Icon name=\"i-lucide-triangle-alert\" className=\"size-3.5\" />{t('composites.derivation.stale')}\n </span>\n )}\n {details.edited && (\n <span className={cn(CHIP, 'text-muted-foreground')}>\n <Icon name=\"i-lucide-pencil\" className=\"size-3.5\" />{t('composites.derivation.edited')}\n </span>\n )}\n </div>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-2 gap-y-0.5\">\n <dt className=\"text-muted-foreground\">{t('composites.derivation.method')}</dt>\n <dd className=\"truncate text-foreground\">{method}</dd>\n {derivation.model && (\n <>\n <dt className=\"text-muted-foreground\">{t('composites.derivation.model')}</dt>\n <dd className=\"truncate text-foreground\" title={derivation.model}>{derivation.model}</dd>\n </>\n )}\n {created && (\n <>\n <dt className=\"text-muted-foreground\">{t('composites.derivation.createdAt')}</dt>\n <dd className=\"text-foreground\">{created}</dd>\n </>\n )}\n </dl>\n {details.outputUrl && (\n <a href={details.outputUrl} target=\"_blank\" rel=\"noopener\" className=\"inline-flex w-fit items-center gap-1 text-primary hover:underline\">\n <Icon name=\"i-lucide-external-link\" className=\"size-3.5\" />{t('composites.derivation.openOutput')}\n </a>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,OAAO;;;;;;;AAQb,SAAgB,gBAAgB,EAAE,QAAQ,MAAM,YAA2E;CACzH,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,aAAa,aAAa,IAAI;CACpC,MAAM,UAAU,cAAc,WAAW,oBAAoB,QAAQ,IAAI,IAAI,MAAM;EAAC;EAAU;EAAQ;CAAI,CAAC;CAC3G,IAAI,CAAC,YAAY,OAAO;CACxB,MAAM,SAAS,sBAAsB,GAAG,WAAW,MAAM;CACzD,MAAM,UAAU,WAAW,YAAY,WAAW,WAAW,SAAS,IAAI;CAE1E,IAAI,CAAC,UACH,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,MAAD;GAAM,MAAK;GAAsB,WAAU;EAAqB,CAAA,GAChE,oBAAC,QAAD;GAAM,WAAU;GAAY,UAAA;IAAC,EAAE,6BAA6B;IAAG;IAAQ;GAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK;EAAQ,CAAA,CAC/G;;CAGT,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,uBAAuB;MAAjD,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAAsB,WAAU;MAAY,CAAA,GAAE,EAAE,6BAA6B,CACpF;;KACL,QAAQ,SACP,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,qBAAqB;MAA/C,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAA0B,WAAU;MAAY,CAAA,GAAE,EAAE,6BAA6B,CACxF;;KAEP,QAAQ,UACP,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,uBAAuB;MAAjD,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAAkB,WAAU;MAAY,CAAA,GAAE,EAAE,8BAA8B,CACjF;;IAEL;;GACL,qBAAC,MAAD;IAAI,WAAU;IAAd,UAAA;KACE,oBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,8BAA8B;KAAM,CAAA;KAC7E,oBAAC,MAAD;MAAI,WAAU;MAA4B,UAAA;KAAW,CAAA;KACpD,WAAW,SACV,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,6BAA6B;KAAM,CAAA,GAC5E,oBAAC,MAAD;MAAI,WAAU;MAA2B,OAAO,WAAW;MAAQ,UAAA,WAAW;KAAU,CAAA,CACxF,EAAA,CAAA;KAEH,WACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,iCAAiC;KAAM,CAAA,GAChF,oBAAC,MAAD;MAAI,WAAU;MAAmB,UAAA;KAAY,CAAA,CAC7C,EAAA,CAAA;IAEF;;GACH,QAAQ,aACP,qBAAC,KAAD;IAAG,MAAM,QAAQ;IAAW,QAAO;IAAS,KAAI;IAAW,WAAU;IAArE,UAAA,CACE,oBAAC,MAAD;KAAM,MAAK;KAAyB,WAAU;IAAY,CAAA,GAAE,EAAE,kCAAkC,CAC/F;;EAEF;;AAET"}
1
+ {"version":3,"file":"DerivationBadge.js","names":[],"sources":["../../../../src/features/composites/react/DerivationBadge.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { useMemo } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { derivationOf } from '../derivation'\nimport { derivationDetailsOf, derivationIsForeign, derivationMethodLabel } from '../derived-chrome'\nimport { formatDate } from '../meta-display'\n\nconst CHIP = 'inline-flex h-5 shrink-0 items-center gap-1 rounded-sm px-1.5 text-xs leading-none whitespace-nowrap'\n\n/**\n * Where a derived Baustein comes from. Compact (the `derivation` field type): the „abgeleitet“ badge with method and\n * date. `detailed` (the details card): also the model, whether the source changed („Quelle geändert“), whether the body\n * was edited since it was generated („bearbeitet“) and a link to the stored raw output. The detailed variant hashes\n * the body, so it belongs only where one Baustein is shown.\n */\nexport function DerivationBadge({ editor, node, detailed }: { editor: Editor, node: ProseMirrorNode, detailed?: boolean }) {\n const { t } = useEditorI18n()\n const derivation = derivationOf(node)\n const details = useMemo(() => detailed ? derivationDetailsOf(editor, node) : null, [detailed, editor, node])\n if (!derivation) return null\n const method = derivationMethodLabel(t, derivation.method)\n const foreign = derivationIsForeign(editor, derivation)\n const created = derivation.createdAt ? formatDate(derivation.createdAt) : ''\n\n if (!detailed) {\n return (\n <div className=\"flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground\">\n <Icon name=\"i-lucide-git-branch\" className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">{[t('composites.derivation.badge'), method, foreign ? t('composites.derivation.foreign') : '', created].filter(Boolean).join(' · ')}</span>\n </div>\n )\n }\n if (!details) return null\n\n return (\n <div className=\"flex flex-col gap-1.5 rounded-md p-2 text-xs ring-1 ring-border\">\n <div className=\"flex flex-wrap items-center gap-1\">\n <span className={cn(CHIP, 'text-muted-foreground')}>\n <Icon name=\"i-lucide-git-branch\" className=\"size-3.5\" />{t('composites.derivation.badge')}\n </span>\n {details.foreign && (\n <span className={cn(CHIP, 'text-muted-foreground')}>\n <Icon name=\"i-lucide-file-symlink\" className=\"size-3.5\" />{t('composites.derivation.foreign')}\n </span>\n )}\n {details.stale && (\n <span className={cn(CHIP, 'text-(--sk-warning)')}>\n <Icon name=\"i-lucide-triangle-alert\" className=\"size-3.5\" />{t('composites.derivation.stale')}\n </span>\n )}\n {details.edited && (\n <span className={cn(CHIP, 'text-muted-foreground')}>\n <Icon name=\"i-lucide-pencil\" className=\"size-3.5\" />{t('composites.derivation.edited')}\n </span>\n )}\n </div>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-2 gap-y-0.5\">\n <dt className=\"text-muted-foreground\">{t('composites.derivation.method')}</dt>\n <dd className=\"truncate text-foreground\">{method}</dd>\n {derivation.model && (\n <>\n <dt className=\"text-muted-foreground\">{t('composites.derivation.model')}</dt>\n <dd className=\"truncate text-foreground\" title={derivation.model}>{derivation.model}</dd>\n </>\n )}\n {created && (\n <>\n <dt className=\"text-muted-foreground\">{t('composites.derivation.createdAt')}</dt>\n <dd className=\"text-foreground\">{created}</dd>\n </>\n )}\n </dl>\n {details.outputUrl && (\n <a href={details.outputUrl} target=\"_blank\" rel=\"noopener\" className=\"inline-flex w-fit items-center gap-1 text-primary hover:underline\">\n <Icon name=\"i-lucide-external-link\" className=\"size-3.5\" />{t('composites.derivation.openOutput')}\n </a>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,OAAO;;;;;;;AAQb,SAAgB,gBAAgB,EAAE,QAAQ,MAAM,YAA2E;CACzH,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,aAAa,aAAa,IAAI;CACpC,MAAM,UAAU,cAAc,WAAW,oBAAoB,QAAQ,IAAI,IAAI,MAAM;EAAC;EAAU;EAAQ;CAAI,CAAC;CAC3G,IAAI,CAAC,YAAY,OAAO;CACxB,MAAM,SAAS,sBAAsB,GAAG,WAAW,MAAM;CACzD,MAAM,UAAU,oBAAoB,QAAQ,UAAU;CACtD,MAAM,UAAU,WAAW,YAAY,WAAW,WAAW,SAAS,IAAI;CAE1E,IAAI,CAAC,UACH,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,MAAD;GAAM,MAAK;GAAsB,WAAU;EAAqB,CAAA,GAChE,oBAAC,QAAD;GAAM,WAAU;GAAY,UAAA;IAAC,EAAE,6BAA6B;IAAG;IAAQ,UAAU,EAAE,+BAA+B,IAAI;IAAI;GAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK;EAAQ,CAAA,CAClK;;CAGT,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,uBAAuB;MAAjD,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAAsB,WAAU;MAAY,CAAA,GAAE,EAAE,6BAA6B,CACpF;;KACL,QAAQ,WACP,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,uBAAuB;MAAjD,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAAwB,WAAU;MAAY,CAAA,GAAE,EAAE,+BAA+B,CACxF;;KAEP,QAAQ,SACP,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,qBAAqB;MAA/C,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAA0B,WAAU;MAAY,CAAA,GAAE,EAAE,6BAA6B,CACxF;;KAEP,QAAQ,UACP,qBAAC,QAAD;MAAM,WAAW,GAAG,MAAM,uBAAuB;MAAjD,UAAA,CACE,oBAAC,MAAD;OAAM,MAAK;OAAkB,WAAU;MAAY,CAAA,GAAE,EAAE,8BAA8B,CACjF;;IAEL;;GACL,qBAAC,MAAD;IAAI,WAAU;IAAd,UAAA;KACE,oBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,8BAA8B;KAAM,CAAA;KAC7E,oBAAC,MAAD;MAAI,WAAU;MAA4B,UAAA;KAAW,CAAA;KACpD,WAAW,SACV,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,6BAA6B;KAAM,CAAA,GAC5E,oBAAC,MAAD;MAAI,WAAU;MAA2B,OAAO,WAAW;MAAQ,UAAA,WAAW;KAAU,CAAA,CACxF,EAAA,CAAA;KAEH,WACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,iCAAiC;KAAM,CAAA,GAChF,oBAAC,MAAD;MAAI,WAAU;MAAmB,UAAA;KAAY,CAAA,CAC7C,EAAA,CAAA;IAEF;;GACH,QAAQ,aACP,qBAAC,KAAD;IAAG,MAAM,QAAQ;IAAW,QAAO;IAAS,KAAI;IAAW,WAAU;IAArE,UAAA,CACE,oBAAC,MAAD;KAAM,MAAK;KAAyB,WAAU;IAAY,CAAA,GAAE,EAAE,kCAAkC,CAC/F;;EAEF;;AAET"}
@@ -0,0 +1,11 @@
1
+ import { Editor } from "@tiptap/core";
2
+ //#region src/features/composites/react/FocusChip.d.ts
3
+ /**
4
+ * Focus mode indicator (mounted by the composites feature): while a Baustein is focused (`focusComposite`) a small chip
5
+ * fixed at the bottom of the surface names it and leaves focus mode.
6
+ */
7
+ export declare function FocusChip({ editor }: {
8
+ editor: Editor;
9
+ }): import("react").JSX.Element | null;
10
+ //#endregion
11
+ //# sourceMappingURL=FocusChip.d.ts.map
@@ -0,0 +1,50 @@
1
+ import { findBlockById } from "../../../core/schema/block-ids.js";
2
+ import { useEditorI18n } from "../../../react/use-editor-i18n.js";
3
+ import { Icon } from "../../../react/Icon.js";
4
+ import { Button } from "../../../react/ui/button.js";
5
+ import { compositeFocusOf } from "../focus.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { useEditorState } from "@tiptap/react";
8
+ //#region src/features/composites/react/FocusChip.tsx
9
+ /**
10
+ * Focus mode indicator (mounted by the composites feature): while a Baustein is focused (`focusComposite`) a small chip
11
+ * fixed at the bottom of the surface names it and leaves focus mode.
12
+ */
13
+ function FocusChip({ editor }) {
14
+ const { t } = useEditorI18n();
15
+ const title = useEditorState({
16
+ editor,
17
+ selector: ({ editor: current }) => {
18
+ if (current.isDestroyed) return null;
19
+ const id = compositeFocusOf(current.state);
20
+ const found = id ? findBlockById(current.state.doc, id) : null;
21
+ return found ? found.node.child(0).textContent.trim() || t("composites.untitled") : null;
22
+ }
23
+ });
24
+ if (title === null) return null;
25
+ return /* @__PURE__ */ jsxs("div", {
26
+ className: "fixed bottom-4 left-1/2 z-20 flex max-w-[90vw] -translate-x-1/2 items-center gap-2 rounded-full border border-border bg-background py-1 pl-3 pr-1 shadow-lg",
27
+ role: "status",
28
+ children: [
29
+ /* @__PURE__ */ jsx(Icon, {
30
+ name: "i-lucide-focus",
31
+ className: "shrink-0 text-primary"
32
+ }),
33
+ /* @__PURE__ */ jsx("span", {
34
+ className: "truncate text-sm",
35
+ children: t("composites.focus.chip", { title })
36
+ }),
37
+ /* @__PURE__ */ jsxs(Button, {
38
+ size: "xs",
39
+ variant: "ghost",
40
+ "aria-label": t("composites.focus.leave"),
41
+ onClick: () => editor.commands.focusComposite(null),
42
+ children: [/* @__PURE__ */ jsx(Icon, { name: "i-lucide-x" }), t("composites.focus.release")]
43
+ })
44
+ ]
45
+ });
46
+ }
47
+ //#endregion
48
+ export { FocusChip };
49
+
50
+ //# sourceMappingURL=FocusChip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FocusChip.js","names":[],"sources":["../../../../src/features/composites/react/FocusChip.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useEditorState } from '@tiptap/react'\nimport { findBlockById } from '../../../core/schema'\nimport { Icon } from '../../../react/Icon'\nimport { Button } from '../../../react/ui/button'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { compositeFocusOf } from '../focus'\n\n/**\n * Focus mode indicator (mounted by the composites feature): while a Baustein is focused (`focusComposite`) a small chip\n * fixed at the bottom of the surface names it and leaves focus mode.\n */\nexport function FocusChip({ editor }: { editor: Editor }) {\n const { t } = useEditorI18n()\n const title = useEditorState({\n editor,\n selector: ({ editor: current }) => {\n if (current.isDestroyed) return null\n const id = compositeFocusOf(current.state)\n const found = id ? findBlockById(current.state.doc, id) : null\n return found ? found.node.child(0).textContent.trim() || t('composites.untitled') : null\n },\n })\n if (title === null) return null\n return (\n <div\n className=\"fixed bottom-4 left-1/2 z-20 flex max-w-[90vw] -translate-x-1/2 items-center gap-2 rounded-full border border-border bg-background py-1 pl-3 pr-1 shadow-lg\"\n role=\"status\"\n >\n <Icon name=\"i-lucide-focus\" className=\"shrink-0 text-primary\" />\n <span className=\"truncate text-sm\">{t('composites.focus.chip', { title })}</span>\n <Button size=\"xs\" variant=\"ghost\" aria-label={t('composites.focus.leave')} onClick={() => editor.commands.focusComposite(null)}>\n <Icon name=\"i-lucide-x\" />\n {t('composites.focus.release')}\n </Button>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,UAAU,EAAE,UAA8B;CACxD,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,QAAQ,eAAe;EAC3B;EACA,WAAW,EAAE,QAAQ,cAAc;GACjC,IAAI,QAAQ,aAAa,OAAO;GAChC,MAAM,KAAK,iBAAiB,QAAQ,KAAK;GACzC,MAAM,QAAQ,KAAK,cAAc,QAAQ,MAAM,KAAK,EAAE,IAAI;GAC1D,OAAO,QAAQ,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,KAAK,KAAK,EAAE,qBAAqB,IAAI;EACtF;CACF,CAAC;CACD,IAAI,UAAU,MAAM,OAAO;CAC3B,OACE,qBAAC,OAAD;EACE,WAAU;EACV,MAAK;EAFP,UAAA;GAIE,oBAAC,MAAD;IAAM,MAAK;IAAiB,WAAU;GAAyB,CAAA;GAC/D,oBAAC,QAAD;IAAM,WAAU;IAAoB,UAAA,EAAE,yBAAyB,EAAE,MAAM,CAAC;GAAQ,CAAA;GAChF,qBAAC,QAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,cAAY,EAAE,wBAAwB;IAAG,eAAe,OAAO,SAAS,eAAe,IAAI;IAA7H,UAAA,CACE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA,GACxB,EAAE,0BAA0B,CACvB;;EACL;;AAET"}
@@ -1,7 +1,9 @@
1
1
  import { DRAG_HANDLE_VISIBILITIES, HEADING_CONVERSION_SCOPES, KIND_ICON_VISIBILITIES, STRUCTURE_MODES, TREE_ROOTS } from "../../../settings/values.js";
2
+ import { SPLIT_TARGET_CHARS_MAX, clampSplitTargetChars } from "../../../settings/index.js";
2
3
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
3
4
  import { Icon } from "../../../react/Icon.js";
4
5
  import { useEditorSettings } from "../../../react/settings.js";
6
+ import { Input } from "../../../react/ui/input.js";
5
7
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
6
8
  import { SettingsSection } from "../../../react/SettingsSection.js";
7
9
  import { Label } from "../../../react/ui/label.js";
@@ -9,7 +11,7 @@ import { RadioGroup, RadioGroupItem } from "../../../react/ui/radio-group.js";
9
11
  import { STRUCTURE_MODE_KEYS } from "../structure-mode.js";
10
12
  import { DRAG_HANDLE_KEYS, HEADING_SCOPE_KEYS, KIND_ICON_KEYS, optionItems } from "../editing-settings-keys.js";
11
13
  import { TREE_ROOT_KEYS } from "../tree-root.js";
12
- import { useId } from "react";
14
+ import { useEffect, useId, useState } from "react";
13
15
  import { jsx, jsxs } from "react/jsx-runtime";
14
16
  //#region src/features/composites/react/SettingsEditingTab.tsx
15
17
  /** A group of radio options under a legend (the counterpart of Nuxt UI's `URadioGroup`), the options one above the other. */
@@ -58,6 +60,18 @@ function RadioOption({ item }) {
58
60
  function SettingsEditingTab({ kinds }) {
59
61
  const { settings, update } = useEditorSettings();
60
62
  const kindLabelId = useId();
63
+ const splitTargetId = useId();
64
+ const [splitTarget, setSplitTarget] = useState(String(settings.blocks.splitTargetChars));
65
+ useEffect(() => {
66
+ setSplitTarget(String(settings.blocks.splitTargetChars));
67
+ }, [settings.blocks.splitTargetChars]);
68
+ const commitSplitTarget = () => {
69
+ const next = clampSplitTargetChars(splitTarget, settings.blocks.splitTargetChars);
70
+ update((draft) => {
71
+ draft.blocks.splitTargetChars = next;
72
+ });
73
+ setSplitTarget(String(next));
74
+ };
61
75
  const { t } = useEditorI18n();
62
76
  const structureItems = optionItems(STRUCTURE_MODES, STRUCTURE_MODE_KEYS, t);
63
77
  const scopeItems = optionItems(HEADING_CONVERSION_SCOPES, HEADING_SCOPE_KEYS, t);
@@ -126,6 +140,27 @@ function SettingsEditingTab({ kinds }) {
126
140
  }, kind.id)) })]
127
141
  })]
128
142
  }),
143
+ /* @__PURE__ */ jsxs("div", {
144
+ className: "flex items-start justify-between gap-4 py-3",
145
+ children: [/* @__PURE__ */ jsx(Label, {
146
+ htmlFor: splitTargetId,
147
+ className: "min-w-0 flex-1 text-sm font-medium text-foreground",
148
+ children: t("settings.editing.splitTargetChars")
149
+ }), /* @__PURE__ */ jsx(Input, {
150
+ id: splitTargetId,
151
+ type: "number",
152
+ min: 200,
153
+ max: SPLIT_TARGET_CHARS_MAX,
154
+ step: 100,
155
+ className: "w-32",
156
+ value: splitTarget,
157
+ onChange: (event) => setSplitTarget(event.target.value),
158
+ onBlur: commitSplitTarget,
159
+ onKeyDown: (event) => {
160
+ if (event.key === "Enter") commitSplitTarget();
161
+ }
162
+ })]
163
+ }),
129
164
  /* @__PURE__ */ jsx(RadioField, {
130
165
  legend: t("composites.settings.kindIcon.legend"),
131
166
  items: kindIconItems,
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsEditingTab.js","names":[],"sources":["../../../../src/features/composites/react/SettingsEditingTab.tsx"],"sourcesContent":["import { useId } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorSettings } from '../../../react/settings'\nimport { SettingsSection } from '../../../react/SettingsSection'\nimport { Label } from '../../../react/ui/label'\nimport { RadioGroup, RadioGroupItem } from '../../../react/ui/radio-group'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { DRAG_HANDLE_VISIBILITIES, HEADING_CONVERSION_SCOPES, KIND_ICON_VISIBILITIES, STRUCTURE_MODES, TREE_ROOTS } from '../../../settings'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { DRAG_HANDLE_KEYS, HEADING_SCOPE_KEYS, KIND_ICON_KEYS, optionItems } from '../editing-settings-keys'\nimport type { CompositeKind } from '../kinds'\nimport { STRUCTURE_MODE_KEYS } from '../structure-mode'\nimport { TREE_ROOT_KEYS } from '../tree-root'\n\n/** A group of radio options under a legend (the counterpart of Nuxt UI's `URadioGroup`), the options one above the other. */\nfunction RadioField<T extends string>({ legend, items, value, onChange }: {\n legend: string\n items: readonly { label: string, description: string, value: T }[]\n value: T\n onChange: (value: T) => void\n}) {\n const legendId = useId()\n return (\n <div className=\"py-3\">\n <p id={legendId} className=\"mb-2 text-sm font-medium text-foreground\">{legend}</p>\n <RadioGroup\n aria-labelledby={legendId}\n className=\"flex flex-col gap-2\"\n value={value}\n onValueChange={(next) => {\n const item = items.find(candidate => candidate.value === next)\n if (item) onChange(item.value)\n }}\n >\n {items.map(item => <RadioOption key={item.value} item={item} />)}\n </RadioGroup>\n </div>\n )\n}\n\nfunction RadioOption({ item }: { item: { label: string, description: string, value: string } }) {\n const id = useId()\n return (\n <div className=\"flex items-start gap-2\">\n <RadioGroupItem id={id} value={item.value} className=\"mt-0.5\" />\n <Label htmlFor={id} className=\"flex-col items-start gap-0.5\">\n <span className=\"text-sm font-medium text-foreground\">{item.label}</span>\n <span className=\"text-sm font-normal text-muted-foreground\">{item.description}</span>\n </Label>\n </div>\n )\n}\n\n/** „Bearbeiten“: Gliederung (structure mode, conversion scope), Bausteine defaults and the visibility of the block handles. */\nexport function SettingsEditingTab({ kinds }: { kinds: readonly CompositeKind[] }) {\n const { settings, update } = useEditorSettings()\n const kindLabelId = useId()\n const { t } = useEditorI18n()\n const structureItems = optionItems(STRUCTURE_MODES, STRUCTURE_MODE_KEYS, t)\n const scopeItems = optionItems(HEADING_CONVERSION_SCOPES, HEADING_SCOPE_KEYS, t)\n const treeRootItems = optionItems(TREE_ROOTS, TREE_ROOT_KEYS, t)\n const kindIconItems = optionItems(KIND_ICON_VISIBILITIES, KIND_ICON_KEYS, t)\n const dragHandleItems = optionItems(DRAG_HANDLE_VISIBILITIES, DRAG_HANDLE_KEYS, t)\n\n return (\n <div className=\"flex flex-col gap-8\">\n <SettingsSection title={t('composites.settings.structure.title')}>\n <RadioField\n legend={t('composites.settings.structure.legend')}\n items={structureItems}\n value={settings.blocks.structure}\n onChange={value => update((draft) => { draft.blocks.structure = value })}\n />\n <RadioField\n legend={t('composites.settings.scope.legend')}\n items={scopeItems}\n value={settings.editing.headingConversionScope}\n onChange={value => update((draft) => { draft.editing.headingConversionScope = value })}\n />\n </SettingsSection>\n\n <SettingsSection title={t('composites.settings.sidebar.title')}>\n <RadioField\n legend={t('composites.settings.treeRoot.legend')}\n items={treeRootItems}\n value={settings.blocks.treeRoot}\n onChange={value => update((draft) => { draft.blocks.treeRoot = value })}\n />\n </SettingsSection>\n\n <SettingsSection title={t('composites.settings.composites.title')}>\n <div className=\"flex items-start justify-between gap-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <Label id={kindLabelId} className=\"text-sm font-medium text-foreground\">{t('composites.settings.defaultKind.label')}</Label>\n <p className=\"text-sm text-muted-foreground\">{t('composites.settings.defaultKind.description')}</p>\n </div>\n <Select value={settings.blocks.defaultKind} onValueChange={value => update((draft) => { draft.blocks.defaultKind = value })}>\n <SelectTrigger aria-labelledby={kindLabelId} className=\"w-64\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kinds.map(kind => (\n <SelectItem key={kind.id} value={kind.id}>\n <Icon name={kind.icon} />\n {kind.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <RadioField\n legend={t('composites.settings.kindIcon.legend')}\n items={kindIconItems}\n value={settings.blocks.kindIcon}\n onChange={value => update((draft) => { draft.blocks.kindIcon = value })}\n />\n <RadioField\n legend={t('composites.settings.dragHandle.legend')}\n items={dragHandleItems}\n value={settings.blocks.dragHandle}\n onChange={value => update((draft) => { draft.blocks.dragHandle = value })}\n />\n </SettingsSection>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SettingsEditingTab.js","names":[],"sources":["../../../../src/features/composites/react/SettingsEditingTab.tsx"],"sourcesContent":["import { useEffect, useId, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorSettings } from '../../../react/settings'\nimport { SettingsSection } from '../../../react/SettingsSection'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { RadioGroup, RadioGroupItem } from '../../../react/ui/radio-group'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { clampSplitTargetChars, DRAG_HANDLE_VISIBILITIES, HEADING_CONVERSION_SCOPES, KIND_ICON_VISIBILITIES, SPLIT_TARGET_CHARS_MAX, SPLIT_TARGET_CHARS_MIN, STRUCTURE_MODES, TREE_ROOTS } from '../../../settings'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { DRAG_HANDLE_KEYS, HEADING_SCOPE_KEYS, KIND_ICON_KEYS, optionItems } from '../editing-settings-keys'\nimport type { CompositeKind } from '../kinds'\nimport { STRUCTURE_MODE_KEYS } from '../structure-mode'\nimport { TREE_ROOT_KEYS } from '../tree-root'\n\n/** A group of radio options under a legend (the counterpart of Nuxt UI's `URadioGroup`), the options one above the other. */\nfunction RadioField<T extends string>({ legend, items, value, onChange }: {\n legend: string\n items: readonly { label: string, description: string, value: T }[]\n value: T\n onChange: (value: T) => void\n}) {\n const legendId = useId()\n return (\n <div className=\"py-3\">\n <p id={legendId} className=\"mb-2 text-sm font-medium text-foreground\">{legend}</p>\n <RadioGroup\n aria-labelledby={legendId}\n className=\"flex flex-col gap-2\"\n value={value}\n onValueChange={(next) => {\n const item = items.find(candidate => candidate.value === next)\n if (item) onChange(item.value)\n }}\n >\n {items.map(item => <RadioOption key={item.value} item={item} />)}\n </RadioGroup>\n </div>\n )\n}\n\nfunction RadioOption({ item }: { item: { label: string, description: string, value: string } }) {\n const id = useId()\n return (\n <div className=\"flex items-start gap-2\">\n <RadioGroupItem id={id} value={item.value} className=\"mt-0.5\" />\n <Label htmlFor={id} className=\"flex-col items-start gap-0.5\">\n <span className=\"text-sm font-medium text-foreground\">{item.label}</span>\n <span className=\"text-sm font-normal text-muted-foreground\">{item.description}</span>\n </Label>\n </div>\n )\n}\n\n/** „Bearbeiten“: Gliederung (structure mode, conversion scope), Bausteine defaults and the visibility of the block handles. */\nexport function SettingsEditingTab({ kinds }: { kinds: readonly CompositeKind[] }) {\n const { settings, update } = useEditorSettings()\n const kindLabelId = useId()\n const splitTargetId = useId()\n // The target size is edited as text and written back clamped to its range when the field is left, so a half-typed number never reaches the settings.\n const [splitTarget, setSplitTarget] = useState(String(settings.blocks.splitTargetChars))\n useEffect(() => { setSplitTarget(String(settings.blocks.splitTargetChars)) }, [settings.blocks.splitTargetChars])\n const commitSplitTarget = () => {\n const next = clampSplitTargetChars(splitTarget, settings.blocks.splitTargetChars)\n update((draft) => { draft.blocks.splitTargetChars = next })\n setSplitTarget(String(next))\n }\n const { t } = useEditorI18n()\n const structureItems = optionItems(STRUCTURE_MODES, STRUCTURE_MODE_KEYS, t)\n const scopeItems = optionItems(HEADING_CONVERSION_SCOPES, HEADING_SCOPE_KEYS, t)\n const treeRootItems = optionItems(TREE_ROOTS, TREE_ROOT_KEYS, t)\n const kindIconItems = optionItems(KIND_ICON_VISIBILITIES, KIND_ICON_KEYS, t)\n const dragHandleItems = optionItems(DRAG_HANDLE_VISIBILITIES, DRAG_HANDLE_KEYS, t)\n\n return (\n <div className=\"flex flex-col gap-8\">\n <SettingsSection title={t('composites.settings.structure.title')}>\n <RadioField\n legend={t('composites.settings.structure.legend')}\n items={structureItems}\n value={settings.blocks.structure}\n onChange={value => update((draft) => { draft.blocks.structure = value })}\n />\n <RadioField\n legend={t('composites.settings.scope.legend')}\n items={scopeItems}\n value={settings.editing.headingConversionScope}\n onChange={value => update((draft) => { draft.editing.headingConversionScope = value })}\n />\n </SettingsSection>\n\n <SettingsSection title={t('composites.settings.sidebar.title')}>\n <RadioField\n legend={t('composites.settings.treeRoot.legend')}\n items={treeRootItems}\n value={settings.blocks.treeRoot}\n onChange={value => update((draft) => { draft.blocks.treeRoot = value })}\n />\n </SettingsSection>\n\n <SettingsSection title={t('composites.settings.composites.title')}>\n <div className=\"flex items-start justify-between gap-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <Label id={kindLabelId} className=\"text-sm font-medium text-foreground\">{t('composites.settings.defaultKind.label')}</Label>\n <p className=\"text-sm text-muted-foreground\">{t('composites.settings.defaultKind.description')}</p>\n </div>\n <Select value={settings.blocks.defaultKind} onValueChange={value => update((draft) => { draft.blocks.defaultKind = value })}>\n <SelectTrigger aria-labelledby={kindLabelId} className=\"w-64\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kinds.map(kind => (\n <SelectItem key={kind.id} value={kind.id}>\n <Icon name={kind.icon} />\n {kind.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-start justify-between gap-4 py-3\">\n <Label htmlFor={splitTargetId} className=\"min-w-0 flex-1 text-sm font-medium text-foreground\">{t('settings.editing.splitTargetChars')}</Label>\n <Input\n id={splitTargetId}\n type=\"number\"\n min={SPLIT_TARGET_CHARS_MIN}\n max={SPLIT_TARGET_CHARS_MAX}\n step={100}\n className=\"w-32\"\n value={splitTarget}\n onChange={event => setSplitTarget(event.target.value)}\n onBlur={commitSplitTarget}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commitSplitTarget()\n }}\n />\n </div>\n <RadioField\n legend={t('composites.settings.kindIcon.legend')}\n items={kindIconItems}\n value={settings.blocks.kindIcon}\n onChange={value => update((draft) => { draft.blocks.kindIcon = value })}\n />\n <RadioField\n legend={t('composites.settings.dragHandle.legend')}\n items={dragHandleItems}\n value={settings.blocks.dragHandle}\n onChange={value => update((draft) => { draft.blocks.dragHandle = value })}\n />\n </SettingsSection>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -10,6 +10,7 @@ import { CompositeSummaryEditor } from "./react/CompositeSummaryEditor.js";
10
10
  import { CompositeTable } from "./react/CompositeTable.js";
11
11
  import { CompositeTagsEditor } from "./react/CompositeTagsEditor.js";
12
12
  import { CompositeView } from "./react/CompositeView.js";
13
+ import { FocusChip } from "./react/FocusChip.js";
13
14
  import { ReferenceView } from "./react/ReferenceView.js";
14
15
  import { SettingsEditingTab } from "./react/SettingsEditingTab.js";
15
16
  import { useCompositeAnchors } from "./react/use-composite-anchors.js";
@@ -21,5 +22,5 @@ import { useCompositeRows } from "./react/use-composite-rows.js";
21
22
  */
22
23
  export declare function compositeFeature(options?: CompositeFeatureOptions): ReactFeature;
23
24
  //#endregion
24
- export { CompositeChrome, CompositeDetails, CompositeFieldEditor, CompositeInspector, CompositeStatusMenu, CompositeSummaryEditor, CompositeTable, CompositeTagsEditor, CompositeView, ReferenceView, SettingsEditingTab, useCompositeAnchors, useCompositeRows };
25
+ export { CompositeChrome, CompositeDetails, CompositeFieldEditor, CompositeInspector, CompositeStatusMenu, CompositeSummaryEditor, CompositeTable, CompositeTagsEditor, CompositeView, FocusChip, ReferenceView, SettingsEditingTab, useCompositeAnchors, useCompositeRows };
25
26
  //# sourceMappingURL=react.d.ts.map
@@ -9,6 +9,7 @@ import { useCompositeAnchors } from "./react/use-composite-anchors.js";
9
9
  import { CompositeChrome } from "./react/CompositeChrome.js";
10
10
  import { ReferenceView } from "./react/ReferenceView.js";
11
11
  import { CompositeView } from "./react/CompositeView.js";
12
+ import { FocusChip } from "./react/FocusChip.js";
12
13
  import { SettingsEditingTab } from "./react/SettingsEditingTab.js";
13
14
  import { CompositeInspector } from "./react/CompositeInspector.js";
14
15
  import { CompositeTable } from "./react/CompositeTable.js";
@@ -21,6 +22,7 @@ import { ReactNodeViewRenderer } from "@tiptap/react";
21
22
  function compositeFeature(options = {}) {
22
23
  return compositeFeatureCore({
23
24
  chrome: CompositeChrome,
25
+ focusChip: FocusChip,
24
26
  settingsTab: SettingsEditingTab,
25
27
  nodeViews: {
26
28
  composite: ReactNodeViewRenderer(CompositeView),
@@ -29,6 +31,6 @@ function compositeFeature(options = {}) {
29
31
  }, options);
30
32
  }
31
33
  //#endregion
32
- export { CompositeChrome, CompositeDetails, CompositeFieldEditor, CompositeInspector, CompositeStatusMenu, CompositeSummaryEditor, CompositeTable, CompositeTagsEditor, CompositeView, ReferenceView, SettingsEditingTab, compositeFeature, useCompositeAnchors, useCompositeRows };
34
+ export { CompositeChrome, CompositeDetails, CompositeFieldEditor, CompositeInspector, CompositeStatusMenu, CompositeSummaryEditor, CompositeTable, CompositeTagsEditor, CompositeView, FocusChip, ReferenceView, SettingsEditingTab, compositeFeature, useCompositeAnchors, useCompositeRows };
33
35
 
34
36
  //# sourceMappingURL=react.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../../../src/features/composites/react.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { ReactNodeViewRenderer } from '@tiptap/react'\nimport type { ComponentType } from 'react'\nimport type { ReactFeature } from '../../react'\nimport { type CompositeFeatureOptions, compositeFeatureCore } from './feature'\nimport { CompositeChrome } from './react/CompositeChrome'\nimport { ReferenceView } from './react/ReferenceView'\nimport { CompositeView } from './react/CompositeView'\nimport { SettingsEditingTab } from './react/SettingsEditingTab'\n\nexport { CompositeChrome } from './react/CompositeChrome'\nexport { CompositeDetails } from './react/CompositeDetails'\nexport { CompositeFieldEditor } from './react/CompositeFieldEditor'\nexport { CompositeInspector } from './react/CompositeInspector'\nexport { CompositeStatusMenu } from './react/CompositeStatusMenu'\nexport { CompositeSummaryEditor } from './react/CompositeSummaryEditor'\nexport { CompositeTable } from './react/CompositeTable'\nexport { CompositeTagsEditor } from './react/CompositeTagsEditor'\nexport { CompositeView } from './react/CompositeView'\nexport { ReferenceView } from './react/ReferenceView'\nexport { SettingsEditingTab } from './react/SettingsEditingTab'\nexport { useCompositeAnchors } from './react/use-composite-anchors'\nexport { useCompositeRows } from './react/use-composite-rows'\n\n/**\n * The React composites feature (shadcn): see `compositeFeatureCore`. The host places `CompositeTable` and\n * `CompositeInspector` beside the editor.\n */\nexport function compositeFeature(options: CompositeFeatureOptions = {}): ReactFeature {\n return compositeFeatureCore<ComponentType<{ editor: Editor }>>({\n chrome: CompositeChrome,\n // A settings tab receives only its descriptor's `props` (`{ kinds }`), not the toolbar's `{ editor }` (see `EditorSettingsPanel`).\n settingsTab: SettingsEditingTab as unknown as ComponentType<{ editor: Editor }>,\n nodeViews: { composite: ReactNodeViewRenderer(CompositeView), reference: ReactNodeViewRenderer(ReferenceView) },\n }, options)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,iBAAiB,UAAmC,CAAC,GAAiB;CACpF,OAAO,qBAAwD;EAC7D,QAAQ;EAER,aAAa;EACb,WAAW;GAAE,WAAW,sBAAsB,aAAa;GAAG,WAAW,sBAAsB,aAAa;EAAE;CAChH,GAAG,OAAO;AACZ"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../../../src/features/composites/react.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { ReactNodeViewRenderer } from '@tiptap/react'\nimport type { ComponentType } from 'react'\nimport type { ReactFeature } from '../../react'\nimport { type CompositeFeatureOptions, compositeFeatureCore } from './feature'\nimport { CompositeChrome } from './react/CompositeChrome'\nimport { ReferenceView } from './react/ReferenceView'\nimport { CompositeView } from './react/CompositeView'\nimport { FocusChip } from './react/FocusChip'\nimport { SettingsEditingTab } from './react/SettingsEditingTab'\n\nexport { CompositeChrome } from './react/CompositeChrome'\nexport { CompositeDetails } from './react/CompositeDetails'\nexport { CompositeFieldEditor } from './react/CompositeFieldEditor'\nexport { CompositeInspector } from './react/CompositeInspector'\nexport { CompositeStatusMenu } from './react/CompositeStatusMenu'\nexport { CompositeSummaryEditor } from './react/CompositeSummaryEditor'\nexport { CompositeTable } from './react/CompositeTable'\nexport { CompositeTagsEditor } from './react/CompositeTagsEditor'\nexport { CompositeView } from './react/CompositeView'\nexport { FocusChip } from './react/FocusChip'\nexport { ReferenceView } from './react/ReferenceView'\nexport { SettingsEditingTab } from './react/SettingsEditingTab'\nexport { useCompositeAnchors } from './react/use-composite-anchors'\nexport { useCompositeRows } from './react/use-composite-rows'\n\n/**\n * The React composites feature (shadcn): see `compositeFeatureCore`. The host places `CompositeTable` and\n * `CompositeInspector` beside the editor.\n */\nexport function compositeFeature(options: CompositeFeatureOptions = {}): ReactFeature {\n return compositeFeatureCore<ComponentType<{ editor: Editor }>>({\n chrome: CompositeChrome,\n focusChip: FocusChip,\n // A settings tab receives only its descriptor's `props` (`{ kinds }`), not the toolbar's `{ editor }` (see `EditorSettingsPanel`).\n settingsTab: SettingsEditingTab as unknown as ComponentType<{ editor: Editor }>,\n nodeViews: { composite: ReactNodeViewRenderer(CompositeView), reference: ReactNodeViewRenderer(ReferenceView) },\n }, options)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,iBAAiB,UAAmC,CAAC,GAAiB;CACpF,OAAO,qBAAwD;EAC7D,QAAQ;EACR,WAAW;EAEX,aAAa;EACb,WAAW;GAAE,WAAW,sBAAsB,aAAa;GAAG,WAAW,sBAAsB,aAAa;EAAE;CAChH,GAAG,OAAO;AACZ"}
@@ -1,13 +1,14 @@
1
1
  import { CSL_TYPES, CslDate, CslItem, CslName, CslType } from "../../core/backend-types.js";
2
2
  import { CompositeAiBrief, compositeAiBrief } from "./ai-brief.js";
3
3
  import { CompositeKind, CompositeKindAi, CompositeMetaField, SOURCE_MEDIA_TYPES, compositeKind, defaultCompositeKinds, kindAccepts } from "./kinds.js";
4
- import { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeNode, CompositeOptions, CompositeStorage, CompositeTagsNode, CompositeTitleNode, compositeJSON, compositeKindsOf } from "./nodes.js";
4
+ import { BASKET_IDS, Basket, basketById, basketOf, defaultBaskets, titleHiddenOf } from "./baskets.js";
5
+ import { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeNode, CompositeOptions, CompositeStorage, CompositeTagsNode, CompositeTitleNode, compositeBasketsOf, compositeJSON, compositeKindsOf } from "./nodes.js";
5
6
  import { REFERENCE_NODE, ReferenceAttrs, ReferenceNode, ReferenceOptions, ReferenceSuggestionPluginKey, referenceMarkdown } from "./reference.js";
6
7
  import { compositeConversions, convertCompositeBlocks } from "./convert.js";
7
8
  import { CompositeFence, FenceSegment, splitCompositeFences } from "../../core/fences.js";
8
9
  import { blocksFromMarkdown, compositeFence, compositeFromMarkdown } from "./fences.js";
9
10
  import { compositeChromeBlocks, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, structureBlocks } from "./heading-composites.js";
10
- import { BIB_KEY, DERIVATION_KEY } from "./meta-keys.js";
11
+ import { BASKET_KEY, BIB_KEY, DERIVATION_KEY, TITLE_HIDDEN_KEY } from "./meta-keys.js";
11
12
  import { bibOf, bibtexOf, citeFull, citeShort, cslOf, cslTypeOptions, yearOf } from "./bibliography.js";
12
13
  import { Derivation, DerivationMethod, DerivationSource, bodyMarkdown, derivationOf, derivationState, renditionsOf, sourceOf } from "./derivation.js";
13
14
  import { LEGACY_COMPOSITE_NODE, migrateLegacyContent } from "./legacy.js";
@@ -21,7 +22,8 @@ import { AnyExtension } from "@tiptap/core";
21
22
  */
22
23
  export declare function compositeSchemaExtensions(options?: {
23
24
  kinds?: readonly CompositeKind[];
25
+ baskets?: readonly Basket[];
24
26
  }): AnyExtension[];
25
27
  //#endregion
26
- export { BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, type CompositeAiBrief, CompositeDescriptionNode, type CompositeFence, type CompositeKind, type CompositeKindAi, type CompositeMetaField, CompositeNode, type CompositeOptions, type CompositeStorage, CompositeTagsNode, CompositeTitleNode, type CslDate, type CslItem, type CslName, type CslType, DERIVATION_KEY, type Derivation, type DerivationMethod, type DerivationSource, type FenceSegment, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, type ReferenceAttrs, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, citeFull, citeShort, collectCompositeIds, compositeAiBrief, compositeChromeBlocks, compositeConversions, compositeFence, compositeFromMarkdown, compositeIdsOf, compositeJSON, compositeKind, compositeKindsOf, convertCompositeBlocks, cslOf, cslTypeOptions, defaultCompositeKinds, derivationOf, derivationState, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, kindAccepts, migrateLegacyContent, normalizeReferences, referenceMarkdown, referencesFromText, renditionsOf, sourceOf, splitCompositeFences, structureBlocks, yearOf };
28
+ export { BASKET_IDS, BASKET_KEY, BIB_KEY, type Basket, COMPOSITE_CHROME_COUNT, CSL_TYPES, type CompositeAiBrief, CompositeDescriptionNode, type CompositeFence, type CompositeKind, type CompositeKindAi, type CompositeMetaField, CompositeNode, type CompositeOptions, type CompositeStorage, CompositeTagsNode, CompositeTitleNode, type CslDate, type CslItem, type CslName, type CslType, DERIVATION_KEY, type Derivation, type DerivationMethod, type DerivationSource, type FenceSegment, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, type ReferenceAttrs, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, TITLE_HIDDEN_KEY, basketById, basketOf, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, citeFull, citeShort, collectCompositeIds, compositeAiBrief, compositeBasketsOf, compositeChromeBlocks, compositeConversions, compositeFence, compositeFromMarkdown, compositeIdsOf, compositeJSON, compositeKind, compositeKindsOf, convertCompositeBlocks, cslOf, cslTypeOptions, defaultBaskets, defaultCompositeKinds, derivationOf, derivationState, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, kindAccepts, migrateLegacyContent, normalizeReferences, referenceMarkdown, referencesFromText, renditionsOf, sourceOf, splitCompositeFences, structureBlocks, titleHiddenOf, yearOf };
27
29
  //# sourceMappingURL=schema.d.ts.map
@@ -1,10 +1,11 @@
1
1
  import { splitCompositeFences } from "../../core/fences.js";
2
2
  import { SOURCE_MEDIA_TYPES, compositeKind, defaultCompositeKinds, kindAccepts } from "./kinds.js";
3
- import { BIB_KEY, DERIVATION_KEY } from "./meta-keys.js";
3
+ import { BASKET_KEY, BIB_KEY, DERIVATION_KEY, TITLE_HIDDEN_KEY } from "./meta-keys.js";
4
4
  import { blocksFromMarkdown, compositeFence, compositeFromMarkdown } from "./fences.js";
5
+ import { BASKET_IDS, basketById, basketOf, defaultBaskets, titleHiddenOf } from "./baskets.js";
5
6
  import { bodyMarkdown, derivationOf, derivationState, renditionsOf, sourceOf } from "./derivation.js";
6
7
  import { compositeChromeBlocks, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, structureBlocks } from "./heading-composites.js";
7
- import { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeNode, CompositeTagsNode, CompositeTitleNode, compositeJSON, compositeKindsOf } from "./nodes.js";
8
+ import { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeNode, CompositeTagsNode, CompositeTitleNode, compositeBasketsOf, compositeJSON, compositeKindsOf } from "./nodes.js";
8
9
  import { REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, referenceMarkdown } from "./reference.js";
9
10
  import { CSL_TYPES } from "../../core/backend-types.js";
10
11
  import { bibOf, bibtexOf, citeFull, citeShort, cslOf, cslTypeOptions, yearOf } from "./bibliography.js";
@@ -20,7 +21,10 @@ import { collectCompositeIds, compositeIdsOf, normalizeReferences, referencesFro
20
21
  */
21
22
  function compositeSchemaExtensions(options = {}) {
22
23
  return [
23
- CompositeNode.configure(options.kinds ? { kinds: options.kinds } : {}),
24
+ CompositeNode.configure({
25
+ ...options.kinds && { kinds: options.kinds },
26
+ ...options.baskets && { baskets: options.baskets }
27
+ }),
24
28
  CompositeTitleNode,
25
29
  CompositeDescriptionNode,
26
30
  CompositeTagsNode,
@@ -28,6 +32,6 @@ function compositeSchemaExtensions(options = {}) {
28
32
  ];
29
33
  }
30
34
  //#endregion
31
- export { BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, CompositeDescriptionNode, CompositeNode, CompositeTagsNode, CompositeTitleNode, DERIVATION_KEY, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, citeFull, citeShort, collectCompositeIds, compositeAiBrief, compositeChromeBlocks, compositeConversions, compositeFence, compositeFromMarkdown, compositeIdsOf, compositeJSON, compositeKind, compositeKindsOf, compositeSchemaExtensions, convertCompositeBlocks, cslOf, cslTypeOptions, defaultCompositeKinds, derivationOf, derivationState, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, kindAccepts, migrateLegacyContent, normalizeReferences, referenceMarkdown, referencesFromText, renditionsOf, sourceOf, splitCompositeFences, structureBlocks, yearOf };
35
+ export { BASKET_IDS, BASKET_KEY, BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, CompositeDescriptionNode, CompositeNode, CompositeTagsNode, CompositeTitleNode, DERIVATION_KEY, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, TITLE_HIDDEN_KEY, basketById, basketOf, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, citeFull, citeShort, collectCompositeIds, compositeAiBrief, compositeBasketsOf, compositeChromeBlocks, compositeConversions, compositeFence, compositeFromMarkdown, compositeIdsOf, compositeJSON, compositeKind, compositeKindsOf, compositeSchemaExtensions, convertCompositeBlocks, cslOf, cslTypeOptions, defaultBaskets, defaultCompositeKinds, derivationOf, derivationState, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, kindAccepts, migrateLegacyContent, normalizeReferences, referenceMarkdown, referencesFromText, renditionsOf, sourceOf, splitCompositeFences, structureBlocks, titleHiddenOf, yearOf };
32
36
 
33
37
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/composites/schema.ts"],"sourcesContent":["// Vue-free entry of the composite feature (`@ecsplico/editor/composites/schema`): the node family, kinds, Markdown\n// fences, legacy migration, heading↔composite transforms and conversions. Servers build their schema from it; it never\n// imports node views, components or the feature factory.\nimport type { AnyExtension } from '@tiptap/core'\nimport { type CompositeKind } from './kinds'\nimport { CompositeNode, CompositeDescriptionNode, CompositeTagsNode, CompositeTitleNode } from './nodes'\nimport { ReferenceNode } from './reference'\n\nexport { type CompositeAiBrief, compositeAiBrief } from './ai-brief'\nexport { compositeConversions, convertCompositeBlocks } from './convert'\nexport { blocksFromMarkdown, type CompositeFence, compositeFence, compositeFromMarkdown, type FenceSegment, splitCompositeFences } from './fences'\nexport { compositeChromeBlocks, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, structureBlocks } from './heading-composites'\nexport { BIB_KEY, bibOf, bibtexOf, citeFull, citeShort, type CslDate, type CslItem, type CslName, type CslType, CSL_TYPES, cslOf, cslTypeOptions, yearOf } from './bibliography'\nexport { bodyMarkdown, DERIVATION_KEY, type Derivation, derivationOf, derivationState, type DerivationMethod, type DerivationSource, renditionsOf, sourceOf } from './derivation'\nexport { type CompositeKind, type CompositeKindAi, type CompositeMetaField, compositeKind, defaultCompositeKinds, kindAccepts, SOURCE_MEDIA_TYPES } from './kinds'\nexport { LEGACY_COMPOSITE_NODE, migrateLegacyContent } from './legacy'\nexport { REFERENCE_NODE, type ReferenceAttrs, referenceMarkdown, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey } from './reference'\nexport { compositeIdsOf, collectCompositeIds, normalizeReferences, referencesFromText } from './reference-text'\nexport {\n COMPOSITE_CHROME_COUNT,\n compositeJSON,\n compositeKindsOf,\n CompositeDescriptionNode,\n CompositeNode,\n type CompositeOptions,\n type CompositeStorage,\n CompositeTagsNode,\n CompositeTitleNode,\n} from './nodes'\n\n/**\n * The schema-bearing composite family (composite, title, description, tags, and the inline `reference` chip) without node views, to append to\n * `coreSchemaExtensions()`: `getSchema([...coreSchemaExtensions(), ...compositeSchemaExtensions({ kinds })])`. `kinds`\n * is the host's kind list (default: the built-in kinds in German, `defaultCompositeKinds`); it is storage, not schema.\n */\nexport function compositeSchemaExtensions(options: { kinds?: readonly CompositeKind[] } = {}): AnyExtension[] {\n return [CompositeNode.configure(options.kinds ? { kinds: options.kinds } : {}), CompositeTitleNode, CompositeDescriptionNode, CompositeTagsNode, ReferenceNode]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,0BAA0B,UAAgD,CAAC,GAAmB;CAC5G,OAAO;EAAC,cAAc,UAAU,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC,CAAC;EAAG;EAAoB;EAA0B;EAAmB;CAAa;AAChK"}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/composites/schema.ts"],"sourcesContent":["// Vue-free entry of the composite feature (`@ecsplico/editor/composites/schema`): the node family, kinds, Markdown\n// fences, legacy migration, heading↔composite transforms and conversions. Servers build their schema from it; it never\n// imports node views, components or the feature factory.\nimport type { AnyExtension } from '@tiptap/core'\nimport type { Basket } from './baskets'\nimport { type CompositeKind } from './kinds'\nimport { CompositeNode, CompositeDescriptionNode, CompositeTagsNode, CompositeTitleNode } from './nodes'\nimport { ReferenceNode } from './reference'\n\nexport { type CompositeAiBrief, compositeAiBrief } from './ai-brief'\nexport { type Basket, BASKET_IDS, basketById, basketOf, defaultBaskets, titleHiddenOf } from './baskets'\nexport { compositeConversions, convertCompositeBlocks } from './convert'\nexport { blocksFromMarkdown, type CompositeFence, compositeFence, compositeFromMarkdown, type FenceSegment, splitCompositeFences } from './fences'\nexport { compositeChromeBlocks, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, structureBlocks } from './heading-composites'\nexport { BIB_KEY, bibOf, bibtexOf, citeFull, citeShort, type CslDate, type CslItem, type CslName, type CslType, CSL_TYPES, cslOf, cslTypeOptions, yearOf } from './bibliography'\nexport { bodyMarkdown, DERIVATION_KEY, type Derivation, derivationOf, derivationState, type DerivationMethod, type DerivationSource, renditionsOf, sourceOf } from './derivation'\nexport { type CompositeKind, type CompositeKindAi, type CompositeMetaField, compositeKind, defaultCompositeKinds, kindAccepts, SOURCE_MEDIA_TYPES } from './kinds'\nexport { BASKET_KEY, TITLE_HIDDEN_KEY } from './meta-keys'\nexport { LEGACY_COMPOSITE_NODE, migrateLegacyContent } from './legacy'\nexport { REFERENCE_NODE, type ReferenceAttrs, referenceMarkdown, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey } from './reference'\nexport { compositeIdsOf, collectCompositeIds, normalizeReferences, referencesFromText } from './reference-text'\nexport {\n COMPOSITE_CHROME_COUNT,\n compositeJSON,\n compositeBasketsOf,\n compositeKindsOf,\n CompositeDescriptionNode,\n CompositeNode,\n type CompositeOptions,\n type CompositeStorage,\n CompositeTagsNode,\n CompositeTitleNode,\n} from './nodes'\n\n/**\n * The schema-bearing composite family (composite, title, description, tags, and the inline `reference` chip) without node views, to append to\n * `coreSchemaExtensions()`: `getSchema([...coreSchemaExtensions(), ...compositeSchemaExtensions({ kinds })])`. `kinds`\n * is the host's kind list (default: the built-in kinds in German, `defaultCompositeKinds`); it is storage, not schema.\n */\nexport function compositeSchemaExtensions(options: { kinds?: readonly CompositeKind[], baskets?: readonly Basket[] } = {}): AnyExtension[] {\n return [CompositeNode.configure({ ...(options.kinds && { kinds: options.kinds }), ...(options.baskets && { baskets: options.baskets }) }), CompositeTitleNode, CompositeDescriptionNode, CompositeTagsNode, ReferenceNode]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,0BAA0B,UAA6E,CAAC,GAAmB;CACzI,OAAO;EAAC,cAAc,UAAU;GAAE,GAAI,QAAQ,SAAS,EAAE,OAAO,QAAQ,MAAM;GAAI,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,QAAQ;EAAG,CAAC;EAAG;EAAoB;EAA0B;EAAmB;CAAa;AAC3N"}
@@ -0,0 +1,62 @@
1
+ import { CompositeKind } from "./kinds.js";
2
+ import { Extension } from "@tiptap/core";
3
+ import { Node as Node$1, Schema } from "@tiptap/pm/model";
4
+ //#region src/features/composites/split.d.ts
5
+ /** Where the parts of a split go: next to the split Baustein (`siblings`) or into it as sub-Bausteine (`children`). */
6
+ export type SplitMode = 'siblings' | 'children';
7
+ /**
8
+ * Groups `blocks` in order so that no group exceeds `targetChars` text characters, never splitting inside a block: a
9
+ * new group starts when adding the block would exceed the target and the group is not empty, so a single block longer
10
+ * than the target forms a group of its own.
11
+ */
12
+ export declare function splitBodyByLength(blocks: readonly Node$1[], targetChars: number): Node$1[][];
13
+ /**
14
+ * Title for a part holding `blocks`: the first sentence of its first textblock (up to the first `.`, `!` or `?` that
15
+ * is followed by white space or ends the text; the mark itself is left out), at most 60 characters, `…` appended when
16
+ * cut. '' when the blocks hold no text.
17
+ */
18
+ export declare function generatedTitle(blocks: readonly Node$1[]): string;
19
+ /**
20
+ * Kind of the sub-Bausteine a split of a `parentKind` Baustein creates: `defaultKind` when the parent accepts it, else
21
+ * the parent's own kind when it accepts itself, else null (the split is refused).
22
+ */
23
+ export declare function childKindFor(kinds: readonly CompositeKind[], parentKind: string, defaultKind: string): string | null;
24
+ /**
25
+ * The nodes that replace `composite` once its body is cut into `groups` (in order, each non-empty).
26
+ * - `children`: one node, `composite` with its own title, description, tags and meta whose body is one new Baustein of
27
+ * `childKind` per group.
28
+ * - `siblings`: `composite` itself keeping the first group, then one new Baustein of the same kind per further group.
29
+ * New parts carry a generated title, hidden when `hideTitles`, and no block id.
30
+ */
31
+ export declare function splitComposite(schema: Schema, composite: Node$1, groups: readonly (readonly Node$1[])[], mode: SplitMode, childKind: string, hideTitles: boolean): Node$1[];
32
+ declare module '@tiptap/core' {
33
+ interface Commands<ReturnType> {
34
+ compositeSplit: {
35
+ /**
36
+ * Split the caret's innermost Baustein in front of the body block holding the caret (refused when that is the first body block or the caret is not in a body): the part before and the part from the caret on become sibling Bausteine or sub-Bausteine (`children`, of the default kind or the parent's own; refused when neither is accepted). The caret moves into the new part.
37
+ */
38
+ splitCompositeAtCaret: (options: {
39
+ mode: SplitMode;
40
+ }) => ReturnType;
41
+ /**
42
+ * Split the Baustein at `pos` (default: the caret's innermost one) into parts of about `targetChars` characters (default: setting `blocks.splitTargetChars`) without cutting inside a block. Refused with fewer than two parts, or in `children` mode when no child kind is accepted. The generated titles are hidden.
43
+ */
44
+ splitCompositeByLength: (options: {
45
+ mode: SplitMode;
46
+ targetChars?: number;
47
+ pos?: number;
48
+ }) => ReturnType;
49
+ };
50
+ }
51
+ }
52
+ /** Options of `CompositeSplit`: read on every use, so a changed setting applies without recreating the editor. */
53
+ export interface CompositeSplitOptions {
54
+ /** Kind of the sub-Bausteine a `children` split creates when the parent accepts it (setting `blocks.defaultKind`). */
55
+ defaultKind: () => string;
56
+ /** Target size in characters of a length split (setting `blocks.splitTargetChars`). */
57
+ targetChars: () => number;
58
+ }
59
+ /** Client-only, no schema: the split commands of Bausteine. */
60
+ export declare const CompositeSplit: Extension<CompositeSplitOptions, any>;
61
+ //#endregion
62
+ //# sourceMappingURL=split.d.ts.map