@ecsplico/editor 3.2.0 → 3.4.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 (57) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/code/CodeSurface.vue.d.ts +3 -3
  3. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  4. package/dist/features/ai/protocol/generate.d.ts +1 -1
  5. package/dist/features/composites/components/CompositeChrome.js +10 -9
  6. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  7. package/dist/features/composites/components/CompositeView.js +5 -1
  8. package/dist/features/composites/components/CompositeView.js.map +1 -1
  9. package/dist/features/composites/feature.js +12 -1
  10. package/dist/features/composites/feature.js.map +1 -1
  11. package/dist/features/composites/index.d.ts +2 -1
  12. package/dist/features/composites/index.js +2 -1
  13. package/dist/features/composites/kinds.d.ts +10 -1
  14. package/dist/features/composites/kinds.js.map +1 -1
  15. package/dist/features/composites/merge.d.ts +24 -0
  16. package/dist/features/composites/merge.js +50 -0
  17. package/dist/features/composites/merge.js.map +1 -0
  18. package/dist/features/composites/nodes.d.ts +1 -0
  19. package/dist/features/composites/nodes.js +1 -1
  20. package/dist/features/composites/nodes.js.map +1 -1
  21. package/dist/features/composites/outline.d.ts +9 -2
  22. package/dist/features/composites/outline.js +41 -3
  23. package/dist/features/composites/outline.js.map +1 -1
  24. package/dist/features/composites/react/CompositeChrome.js +11 -9
  25. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  26. package/dist/features/composites/react/CompositeView.js +4 -1
  27. package/dist/features/composites/react/CompositeView.js.map +1 -1
  28. package/dist/features/composites/rows.d.ts +2 -0
  29. package/dist/features/composites/rows.js +1 -0
  30. package/dist/features/composites/rows.js.map +1 -1
  31. package/dist/i18n/de/composites.js +1 -0
  32. package/dist/i18n/de/composites.js.map +1 -1
  33. package/dist/i18n/de/tree.js +1 -0
  34. package/dist/i18n/de/tree.js.map +1 -1
  35. package/dist/i18n/de.d.ts +2 -0
  36. package/dist/i18n/en/composites.js +1 -0
  37. package/dist/i18n/en/composites.js.map +1 -1
  38. package/dist/i18n/en/tree.js +1 -0
  39. package/dist/i18n/en/tree.js.map +1 -1
  40. package/dist/markdown/MarkdownSurface.vue.d.ts +5 -5
  41. package/dist/nuxt/module.d.ts +4 -0
  42. package/dist/server/handlers/ai.d.ts +1 -1
  43. package/dist/styles/composites.css +10 -1
  44. package/dist/tree/DocumentTree.js +25 -9
  45. package/dist/tree/DocumentTree.js.map +1 -1
  46. package/dist/tree/react/DocumentTree.js +14 -2
  47. package/dist/tree/react/DocumentTree.js.map +1 -1
  48. package/dist/tree/tree-host.js +11 -1
  49. package/dist/tree/tree-host.js.map +1 -1
  50. package/dist/tree/tree-items.js +3 -1
  51. package/dist/tree/tree-items.js.map +1 -1
  52. package/dist/tree/tree-model.js +9 -0
  53. package/dist/tree/tree-model.js.map +1 -1
  54. package/dist/vue/AdvancedEditor.vue.d.ts +4 -4
  55. package/dist/vue/SimpleEditor.vue.d.ts +4 -4
  56. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  57. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.4.0 - 2026-10-21
4
+
5
+ ### Added
6
+
7
+ - `CompositeKind.chrome.controls?: boolean` (default `true`). With `controls: false` the chrome of a Baustein of that kind is read-only although the editor is editable (Vue and React `CompositeChrome`; `CompositeRow.controls`): no basket menu, status menu, title-visibility button, tag removal or `+` chip and no drag handle on the kind icon, and a read-only details popover; existing basket, status and tags stay visible as chips. `mergeCompositeWithNext` also refuses (so `TreeModel.canMerge`, the row button and the block action disappear) when the Baustein or the one it would absorb has such a kind. For kinds whose attributes a host guard refuses to change.
8
+
9
+ ### Changed
10
+
11
+ - Outline label of a Baustein without a title: instead of „(ohne Titel)“ the document tree (Vue and React rows) shows the text of the first heading of the Baustein's own body, else the start of the first non-empty text of its own body (cut at 60 characters with „…“); text inside a nested Baustein is not used, and only a Baustein with an empty body keeps „(ohne Titel)“. `compositeOutline` marks such a label with `OutlineNode.labelFromBody` and `TreeItem.labelFromBody` (rows render it muted and italic, `data-label-from-body`), and the title filter matches the derived label too. A Baustein with a title is unchanged.
12
+
13
+ ## 3.3.0 - 2026-10-21
14
+
15
+ ### Added
16
+
17
+ - Kind tone: `CompositeKind.chrome.tone` (a CSS colour or `var(...)`). A Baustein of such a kind gets `data-kind-tone` and `--sk-kind-tone` on its wrapper (Vue and React `CompositeView`), a tinted surface and a left border in the tone (`composites.css`; strength `--sk-kind-tone-mix`, `8%` under `:where(:root)`, `14%` under `:where(.dark)`), and its document-tree rows tint the kind icon (`TreeItem.tone`). Kinds without a tone are unchanged.
18
+ - Merging a Baustein with the next one (`@ecsplico/editor/composites`): the command `mergeCompositeWithNext(pos?)` makes a Baustein absorb the Baustein that directly follows it (body and sub-Bausteine appended; the first keeps title, description, tags, id, kind and meta) in one undo step, refused without a following Baustein, when the first kind does not accept a nested kind, or when read-only. Block action „Mit nächstem zusammenführen“, a merge button on `DocumentTree` rows (Vue and React; `TreeCommand` `{ type: 'mergeBlock', id }`, `TreeModel.canMerge(item)` / `merge(item)`; a host-built `TreeEditor` must now provide `canMerge(id)`), exported `CompositeMerge` and `mergeBody`.
19
+
3
20
  ## 3.2.0 - 2026-10-20
4
21
 
5
22
  ### Added
@@ -12,16 +12,16 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {
12
12
  view: import("vue").ShallowRef<EditorView | undefined, EditorView | undefined>;
13
13
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
14
  "update:modelValue": (text: string) => any;
15
- ready: (view: EditorView) => any;
16
15
  save: (text: string) => any;
16
+ ready: (view: EditorView) => any;
17
17
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
18
18
  "onUpdate:modelValue"?: ((text: string) => any) | undefined;
19
- onReady?: ((view: EditorView) => any) | undefined;
20
19
  onSave?: ((text: string) => any) | undefined;
20
+ onReady?: ((view: EditorView) => any) | undefined;
21
21
  }>, {
22
22
  editable: boolean;
23
- modelValue: string;
24
23
  wordWrap: boolean;
24
+ modelValue: string;
25
25
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
26
  declare const _default: typeof __VLS_export;
27
27
  //#endregion
@@ -33,16 +33,16 @@ type __VLS_Slots = {} & { [K in NonNullable<typeof __VLS_13>]?: (props: typeof _
33
33
  };
34
34
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
35
35
  "update:modelValue": (text: string) => any;
36
- ready: (target: DocumentSurfaceTarget) => any;
37
36
  save: (text: string) => any;
37
+ ready: (target: DocumentSurfaceTarget) => any;
38
38
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
39
39
  "onUpdate:modelValue"?: ((text: string) => any) | undefined;
40
- onReady?: ((target: DocumentSurfaceTarget) => any) | undefined;
41
40
  onSave?: ((text: string) => any) | undefined;
41
+ onReady?: ((target: DocumentSurfaceTarget) => any) | undefined;
42
42
  }>, {
43
43
  editable: boolean;
44
- modelValue: string;
45
44
  wordWrap: boolean;
45
+ modelValue: string;
46
46
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
47
47
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
48
48
  declare const _default: typeof __VLS_export;
@@ -17,8 +17,8 @@ export type ChatStream = (messages: ChatMessage[], signal: AbortSignal) => Async
17
17
  export declare const generateBodySchema: z.ZodObject<{
18
18
  task: z.ZodEnum<{
19
19
  custom: "custom";
20
- continue: "continue";
21
20
  generate: "generate";
21
+ continue: "continue";
22
22
  reformulate: "reformulate";
23
23
  "transcript-summary": "transcript-summary";
24
24
  "transcript-minutes": "transcript-minutes";
@@ -129,6 +129,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
129
129
  return [{
130
130
  row,
131
131
  anchor,
132
+ editable: editable.value && row.controls,
132
133
  left,
133
134
  top: (inStrip ? anchor.toggleTop + anchor.toggleSize / 2 : anchor.lastCenter) - ROW_HEIGHT / 2,
134
135
  width: Math.max((frame.value?.right ?? anchor.right) - left, 120),
@@ -173,7 +174,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
173
174
  content: withCtx(() => [createVNode(_sfc_main$2, {
174
175
  editor: __props.editor,
175
176
  row: item.row,
176
- editable: editable.value
177
+ editable: item.editable
177
178
  }, null, 8, [
178
179
  "editor",
179
180
  "row",
@@ -182,10 +183,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
182
183
  default: withCtx(() => [createElementVNode("span", {
183
184
  role: "button",
184
185
  tabindex: "0",
185
- draggable: editable.value,
186
+ draggable: item.editable,
186
187
  class: normalizeClass([
187
188
  "absolute z-10 flex items-center justify-center rounded-sm bg-[var(--sk-bg)] text-[var(--sk-muted)] transition-[color,background-color,opacity] duration-120 motion-reduce:transition-none hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]",
188
- editable.value ? "cursor-grab active:cursor-grabbing" : "cursor-pointer",
189
+ item.editable ? "cursor-grab active:cursor-grabbing" : "cursor-pointer",
189
190
  iconOnHover.value && !hoveredKeys.value.has(item.row.key) && chipsHoveredKey.value !== item.row.key && "opacity-0 hover:opacity-100 focus-visible:opacity-100 data-[state=open]:opacity-100"
190
191
  ]),
191
192
  style: normalizeStyle({
@@ -195,7 +196,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
195
196
  height: `${item.anchor.toggleSize}px`
196
197
  }),
197
198
  "aria-label": unref(t)("composites.chrome.details", { kind: item.row.kindLabel }),
198
- title: editable.value ? unref(t)("composites.chrome.detailsDrag", { kind: item.row.kindLabel }) : unref(t)("composites.chrome.details", { kind: item.row.kindLabel }),
199
+ title: item.editable ? unref(t)("composites.chrome.detailsDrag", { kind: item.row.kindLabel }) : unref(t)("composites.chrome.details", { kind: item.row.kindLabel }),
199
200
  onKeydown: _cache[0] || (_cache[0] = withKeys(withModifiers(($event) => $event.currentTarget.click(), ["prevent"]), ["enter", "space"])),
200
201
  onDragstart: ($event) => onIconDragStart($event, item.row)
201
202
  }, [(openBlock(), createBlock(unref(UIcon), {
@@ -204,7 +205,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
204
205
  class: "size-3.5"
205
206
  }, null, 8, ["name"]))], 46, _hoisted_2)]),
206
207
  _: 2
207
- }, 1024)) : createCommentVNode("v-if", true), editable.value || item.basket || item.status || item.derived || item.row.tagsVisible && item.row.tags.length ? (openBlock(), createElementBlock("div", {
208
+ }, 1024)) : createCommentVNode("v-if", true), item.editable || item.basket || item.status || item.derived || item.row.tagsVisible && item.row.tags.length ? (openBlock(), createElementBlock("div", {
208
209
  key: 1,
209
210
  class: "absolute z-10 flex items-center gap-px overflow-hidden rounded-md bg-[var(--sk-bg)]",
210
211
  style: normalizeStyle({
@@ -216,7 +217,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
216
217
  onMouseenter: ($event) => chipsHoveredKey.value = item.row.key,
217
218
  onMouseleave: _cache[1] || (_cache[1] = ($event) => chipsHoveredKey.value = null)
218
219
  }, [
219
- editable.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(_sfc_main$1, {
220
+ item.editable ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(_sfc_main$1, {
220
221
  editor: __props.editor,
221
222
  row: item.row
222
223
  }, {
@@ -277,7 +278,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
277
278
  class: "size-3.5"
278
279
  }), createTextVNode(toDisplayString(unref(t)("composites.derivation.stale")), 1)], 2)) : createCommentVNode("v-if", true)
279
280
  ], 64)) : createCommentVNode("v-if", true),
280
- item.status ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [editable.value ? (openBlock(), createBlock(_sfc_main$3, {
281
+ item.status ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [item.editable ? (openBlock(), createBlock(_sfc_main$3, {
281
282
  key: 0,
282
283
  editor: __props.editor,
283
284
  row: item.row
@@ -302,7 +303,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
302
303
  return openBlock(), createElementBlock("span", {
303
304
  key: tag,
304
305
  class: normalizeClass([chip, "group max-w-40 gap-0"])
305
- }, [createElementVNode("span", _hoisted_9, "#" + toDisplayString(tag), 1), editable.value ? (openBlock(), createElementBlock("button", {
306
+ }, [createElementVNode("span", _hoisted_9, "#" + toDisplayString(tag), 1), item.editable ? (openBlock(), createElementBlock("button", {
306
307
  key: 0,
307
308
  type: "button",
308
309
  class: "flex h-4 w-0 shrink-0 items-center justify-center overflow-hidden rounded-sm opacity-0 transition-all duration-150 group-hover:ml-1 group-hover:w-4 group-hover:opacity-100 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:ml-1 focus-visible:w-4 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-[var(--sk-primary)]",
@@ -313,7 +314,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
313
314
  class: "size-3"
314
315
  })], 8, _hoisted_10)) : createCommentVNode("v-if", true)], 2);
315
316
  }), 128)),
316
- editable.value && item.row.tagsVisible ? (openBlock(), createBlock(unref(UPopover), {
317
+ item.editable && item.row.tagsVisible ? (openBlock(), createBlock(unref(UPopover), {
317
318
  key: 4,
318
319
  content: {
319
320
  side: "bottom",
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeChrome.js","names":["_unref","_openBlock","_createBlock","_Teleport","_createElementVNode","_createElementBlock","_Fragment","_renderList","_withCtx","_createVNode","CompositeDetails","_normalizeClass","_normalizeStyle","_withKeys","_withModifiers","_createCommentVNode","CompositeBasketMenu","_createTextVNode","_toDisplayString","CompositeStatusMenu","CompositeTagsEditor"],"sources":["../../../../src/features/composites/components/CompositeChrome.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Editor } from '@tiptap/vue-3'\nimport { computed, shallowRef, watch } from 'vue'\nimport { startBlockDrag } from '../../../core'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { useEditorSettings } from '../../../vue/settings'\nimport { compositeSectionOf } from '../anchors'\nimport { derivedChromeOf } from '../derived-chrome'\nimport { rowStatus } from '../meta-display'\nimport { basketById, basketOf, titleHiddenOf } from '../baskets'\nimport { compositeBasketsOf } from '../nodes'\nimport { compositeOfRow, type CompositeRow, setCompositeTags } from '../rows'\nimport { useCompositeAnchors } from '../use-composite-anchors'\nimport { useCompositeRows } from '../use-composite-rows'\nimport CompositeBasketMenu from './CompositeBasketMenu.vue'\nimport CompositeDetails from './CompositeDetails.vue'\nimport CompositeStatusMenu from './CompositeStatusMenu.vue'\nimport CompositeTagsEditor from './CompositeTagsEditor.vue'\n\n/**\n * Chrome of every composite, laid over the editor (mounted by the composites feature): on the title line the status\n * chip and one chip per tag (with a `+` chip to add tags), and on the front the kind icon. The icon is a button that\n * opens the details popover (kind with a confirmation before it changes, the kind's fields and the summary;\n * `CompositeDetails`) and, in an editable editor, the composite's drag handle: dragging it moves the composite\n * (`startBlockDrag`). A kind with `chrome.tags: false` shows no tag chips and no `+` chip. With `blocks.kindIcon: 'hover'` it shows only while the composite is hovered, its popover is\n * open or the icon has keyboard focus. Chips and popover also render in read-only editors, without edit affordances.\n * The node view's own description and tags rows are hidden by CSS; this overlay shows and edits them.\n */\nconst props = defineProps<{ editor: Editor }>()\n\nconst { Icon: UIcon, Popover: UPopover } = useUiKit()\nconst { t } = useEditorI18n()\n\nconst { rows } = useCompositeRows(() => props.editor)\nconst { host, anchors, frame } = useCompositeAnchors(() => props.editor, rows)\n\n// `isEditable` is not reactive: follow it on every transaction (`EditorSurface` dispatches one after `setEditable`).\nconst editable = shallowRef(false)\nwatch(() => props.editor, (instance, _previous, onCleanup) => {\n editable.value = !instance.isDestroyed && instance.isEditable\n const sync = () => {\n editable.value = !instance.isDestroyed && instance.isEditable\n }\n instance.on('transaction', sync)\n onCleanup(() => instance.off('transaction', sync))\n}, { immediate: true })\n\nconst { settings } = useEditorSettings()\nconst iconOnHover = computed(() => settings.value.blocks.kindIcon === 'hover')\n\n// Hover state of `kindIcon: 'hover'`: the keys of the rows whose composite is under the pointer (that one and every\n// composite around it), plus the row whose chips the pointer is on (they sit outside the editor's DOM).\nconst hoveredKeys = shallowRef<ReadonlySet<string>>(new Set())\nconst chipsHoveredKey = shallowRef<string | null>(null)\nlet hoveredSection: Element | null = null\n\nfunction onEditorMouseover(event: MouseEvent) {\n const section = event.target instanceof Element ? event.target.closest('.composite') : null\n if (section === hoveredSection) return\n hoveredSection = section\n const chain = new Set<Element>()\n for (let el = section; el; el = el.parentElement?.closest('.composite') ?? null) chain.add(el)\n const { view, state } = props.editor\n hoveredKeys.value = new Set(rows.value.filter((row) => {\n const found = compositeOfRow(state.doc, row)\n const dom = found ? view.nodeDOM(found.pos) : null\n const section = dom instanceof Element ? compositeSectionOf(dom) : null\n return section !== null && chain.has(section)\n }).map(row => row.key))\n}\n\nfunction onEditorMouseleave() {\n hoveredSection = null\n hoveredKeys.value = new Set()\n}\n\nwatch([() => props.editor, iconOnHover], ([instance, hover], _previous, onCleanup) => {\n onEditorMouseleave()\n if (!hover || instance.isDestroyed) return\n const { dom } = instance.view\n dom.addEventListener('mouseover', onEditorMouseover)\n dom.addEventListener('mouseleave', onEditorMouseleave)\n onCleanup(() => {\n dom.removeEventListener('mouseover', onEditorMouseover)\n dom.removeEventListener('mouseleave', onEditorMouseleave)\n })\n}, { immediate: true })\n\nfunction onIconDragStart(event: DragEvent, row: CompositeRow) {\n const found = compositeOfRow(props.editor.state.doc, row)\n if (!found || !startBlockDrag(props.editor, event, found.pos)) event.preventDefault()\n}\n\n/** Chips start right after the title's last character and run on to the editor's right edge. */\nconst ROW_HEIGHT = 24\n\nconst expanded = useStoreRef(() => props.editor.storage.composite.expanded)\nconst revealedTitles = useStoreRef(() => props.editor.storage.composite.revealedTitles)\n\nconst placed = computed(() => {\n const baskets = compositeBasketsOf(props.editor)\n // End of the collapsed derived Baustein the rows being walked sit in: its clipped content shows no chrome.\n let hiddenUntil = -1\n return rows.value.flatMap((row) => {\n if (row.pos < hiddenUntil) return []\n const derived = derivedChromeOf(props.editor, row)\n const open = !derived || !row.id || expanded.value.has(row.id)\n if (!open) hiddenUntil = row.end\n const anchor = anchors.value.get(row.key)\n if (!anchor) return []\n const titleHidden = titleHiddenOf(row)\n // A hidden title leaves nothing to measure: the chips sit in the strip beside the kind icon (`composites.css`).\n const inStrip = titleHidden && !(row.id && revealedTitles.value.has(row.id)) && anchor.toggleSize > 0\n // An empty title shows a placeholder the anchor cannot measure: keep clear of it.\n const left = inStrip ? anchor.toggleLeft + anchor.toggleSize + 6 : anchor.lineEnd + (anchor.titleEmpty ? 116 : 12)\n return [{\n row,\n anchor,\n left,\n top: (inStrip ? anchor.toggleTop + anchor.toggleSize / 2 : anchor.lastCenter) - ROW_HEIGHT / 2,\n width: Math.max((frame.value?.right ?? anchor.right) - left, 120),\n status: rowStatus(row, t),\n derived: derived && { stale: derived.stale, open, toggleable: !!row.id },\n basket: basketById(baskets, basketOf(row)) ?? null,\n titleHidden,\n }]\n })\n})\n\nfunction toggleExpanded(row: CompositeRow) {\n if (row.id) props.editor.commands.toggleCompositeExpanded(row.id)\n}\n\nfunction removeTag(row: CompositeRow, tag: string) {\n setCompositeTags(props.editor, row, row.tags.filter(candidate => candidate !== tag))\n}\n\nfunction toggleTitleHidden(row: CompositeRow) {\n const found = compositeOfRow(props.editor.state.doc, row)\n if (found) props.editor.commands.setCompositeTitleHidden(!titleHiddenOf(row), found.pos)\n}\n\nconst chip = 'inline-flex h-5 shrink-0 items-center gap-1 rounded-sm px-1.5 text-xs leading-none whitespace-nowrap text-[var(--sk-muted)]'\nconst chipButton = `${chip} transition-colors duration-150 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]`\n\n/** Scale and fade in from the icon (`transform-origin` is Reka's), a bit longer than Nuxt UI's default; `composites.css` defines the keyframes and the reduced-motion override. */\nconst detailsPopoverUi = {\n content: 'composite-popover data-[state=open]:animate-[composite-pop-in_160ms_var(--ease-out)] data-[state=closed]:animate-[composite-pop-out_120ms_var(--ease-out)]',\n}\n</script>\n\n<template>\n <Teleport v-if=\"host\" :to=\"host\">\n <div class=\"absolute left-0 top-0 h-0 w-0\">\n <template v-for=\"item in placed\" :key=\"item.row.key\">\n <UPopover\n v-if=\"item.anchor.toggleSize\"\n :content=\"{ side: 'bottom', align: 'start', sideOffset: 4 }\"\n :ui=\"detailsPopoverUi\"\n >\n <!-- A span, not a `button`: Firefox does not start drags from buttons. -->\n <span\n role=\"button\"\n tabindex=\"0\"\n :draggable=\"editable\"\n :class=\"[\n 'absolute z-10 flex items-center justify-center rounded-sm bg-[var(--sk-bg)] text-[var(--sk-muted)] transition-[color,background-color,opacity] duration-120 motion-reduce:transition-none hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]',\n editable ? 'cursor-grab active:cursor-grabbing' : 'cursor-pointer',\n iconOnHover && !hoveredKeys.has(item.row.key) && chipsHoveredKey !== item.row.key && 'opacity-0 hover:opacity-100 focus-visible:opacity-100 data-[state=open]:opacity-100',\n ]\"\n :style=\"{ top: `${item.anchor.toggleTop}px`, left: `${item.anchor.toggleLeft}px`, width: `${item.anchor.toggleSize}px`, height: `${item.anchor.toggleSize}px` }\"\n :aria-label=\"t('composites.chrome.details', { kind: item.row.kindLabel })\"\n :title=\"editable ? t('composites.chrome.detailsDrag', { kind: item.row.kindLabel }) : t('composites.chrome.details', { kind: item.row.kindLabel })\"\n @keydown.enter.space.prevent=\"($event.currentTarget as HTMLElement).click()\"\n @dragstart=\"onIconDragStart($event, item.row)\"\n >\n <UIcon :key=\"item.row.icon\" :name=\"item.row.icon\" class=\"size-3.5\" />\n </span>\n <template #content>\n <CompositeDetails :editor=\"editor\" :row=\"item.row\" :editable=\"editable\" />\n </template>\n </UPopover>\n\n <div\n v-if=\"editable || item.basket || item.status || item.derived || (item.row.tagsVisible && item.row.tags.length)\"\n class=\"absolute z-10 flex items-center gap-px overflow-hidden rounded-md bg-[var(--sk-bg)]\"\n :style=\"{ top: `${item.top}px`, left: `${item.left}px`, maxWidth: `${item.width}px`, height: `${ROW_HEIGHT}px` }\"\n @mouseenter=\"chipsHoveredKey = item.row.key\"\n @mouseleave=\"chipsHoveredKey = null\"\n >\n <template v-if=\"editable\">\n <CompositeBasketMenu :editor=\"editor\" :row=\"item.row\">\n <button type=\"button\" :class=\"chipButton\" :aria-label=\"t('composites.basket.label')\" :title=\"item.basket ? `${t('composites.basket.label')}: ${item.basket.label}` : t('composites.basket.label')\">\n <span v-if=\"item.basket\" class=\"size-2.5 rounded-full\" :style=\"{ backgroundColor: item.basket.color }\" />\n <UIcon v-else name=\"i-lucide-circle-dashed\" class=\"size-3.5\" />\n </button>\n </CompositeBasketMenu>\n <button\n type=\"button\"\n :class=\"chipButton\"\n :aria-label=\"t(item.titleHidden ? 'composites.titleHidden.show' : 'composites.titleHidden.hide')\"\n :title=\"t(item.titleHidden ? 'composites.titleHidden.show' : 'composites.titleHidden.hide')\"\n @click=\"toggleTitleHidden(item.row)\"\n >\n <UIcon :name=\"item.titleHidden ? 'i-lucide-eye' : 'i-lucide-eye-off'\" class=\"size-3.5\" />\n </button>\n </template>\n <span v-else-if=\"item.basket\" :class=\"chip\" :title=\"item.basket.label\">\n <span class=\"size-2.5 rounded-full\" :style=\"{ backgroundColor: item.basket.color }\" />\n </span>\n\n <template v-if=\"item.derived\">\n <button\n v-if=\"item.derived.toggleable\"\n type=\"button\"\n :class=\"chipButton\"\n :aria-expanded=\"item.derived.open\"\n :aria-label=\"t(item.derived.open ? 'composites.derivation.collapse' : 'composites.derivation.expand')\"\n :title=\"t(item.derived.open ? 'composites.derivation.collapse' : 'composites.derivation.expand')\"\n @click=\"toggleExpanded(item.row)\"\n >\n <UIcon :name=\"item.derived.open ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'\" class=\"size-3.5\" />\n </button>\n <span :class=\"chip\">\n <UIcon name=\"i-lucide-git-branch\" class=\"size-3.5\" />{{ t('composites.derivation.badge') }}\n </span>\n <span v-if=\"item.derived.stale\" :class=\"[chip, 'text-[var(--sk-warning)]']\">\n <UIcon name=\"i-lucide-triangle-alert\" class=\"size-3.5\" />{{ t('composites.derivation.stale') }}\n </span>\n </template>\n\n <template v-if=\"item.status\">\n <CompositeStatusMenu v-if=\"editable\" :editor=\"editor\" :row=\"item.row\">\n <button type=\"button\" :class=\"chipButton\" :aria-label=\"t('composites.status.label', { status: item.status.label })\">\n <UIcon :name=\"item.status.icon\" :class=\"['size-3.5', item.status.color]\" />{{ item.status.label }}\n </button>\n </CompositeStatusMenu>\n <span v-else :class=\"chip\">\n <UIcon :name=\"item.status.icon\" :class=\"['size-3.5', item.status.color]\" />{{ item.status.label }}\n </span>\n </template>\n\n <span v-for=\"tag in item.row.tagsVisible ? item.row.tags : []\" :key=\"tag\" :class=\"[chip, 'group max-w-40 gap-0']\">\n <span class=\"truncate\">#{{ tag }}</span>\n <button\n v-if=\"editable\"\n type=\"button\"\n class=\"flex h-4 w-0 shrink-0 items-center justify-center overflow-hidden rounded-sm opacity-0 transition-all duration-150 group-hover:ml-1 group-hover:w-4 group-hover:opacity-100 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:ml-1 focus-visible:w-4 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-[var(--sk-primary)]\"\n :aria-label=\"t('composites.tag.remove', { tag })\"\n @click=\"removeTag(item.row, tag)\"\n >\n <UIcon name=\"i-lucide-x\" class=\"size-3\" />\n </button>\n </span>\n\n <UPopover\n v-if=\"editable && item.row.tagsVisible\"\n :content=\"{ side: 'bottom', align: 'start', sideOffset: 6, onCloseAutoFocus: (event: Event) => event.preventDefault() }\"\n >\n <button type=\"button\" :class=\"chipButton\" :aria-label=\"t('composites.tag.add')\" :title=\"t('composites.tag.add')\">\n <UIcon name=\"i-lucide-plus\" class=\"size-3.5\" />\n </button>\n <template #content>\n <div class=\"w-64 p-3\">\n <CompositeTagsEditor :editor=\"editor\" :row=\"item.row\" />\n </div>\n </template>\n </UPopover>\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompositeChrome.js","names":["_unref","_openBlock","_createBlock","_Teleport","_createElementVNode","_createElementBlock","_Fragment","_renderList","_withCtx","_createVNode","CompositeDetails","_normalizeClass","_normalizeStyle","_withKeys","_withModifiers","_createCommentVNode","CompositeBasketMenu","_createTextVNode","_toDisplayString","CompositeStatusMenu","CompositeTagsEditor"],"sources":["../../../../src/features/composites/components/CompositeChrome.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Editor } from '@tiptap/vue-3'\nimport { computed, shallowRef, watch } from 'vue'\nimport { startBlockDrag } from '../../../core'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { useEditorSettings } from '../../../vue/settings'\nimport { compositeSectionOf } from '../anchors'\nimport { derivedChromeOf } from '../derived-chrome'\nimport { rowStatus } from '../meta-display'\nimport { basketById, basketOf, titleHiddenOf } from '../baskets'\nimport { compositeBasketsOf } from '../nodes'\nimport { compositeOfRow, type CompositeRow, setCompositeTags } from '../rows'\nimport { useCompositeAnchors } from '../use-composite-anchors'\nimport { useCompositeRows } from '../use-composite-rows'\nimport CompositeBasketMenu from './CompositeBasketMenu.vue'\nimport CompositeDetails from './CompositeDetails.vue'\nimport CompositeStatusMenu from './CompositeStatusMenu.vue'\nimport CompositeTagsEditor from './CompositeTagsEditor.vue'\n\n/**\n * Chrome of every composite, laid over the editor (mounted by the composites feature): on the title line the status\n * chip and one chip per tag (with a `+` chip to add tags), and on the front the kind icon. The icon is a button that\n * opens the details popover (kind with a confirmation before it changes, the kind's fields and the summary;\n * `CompositeDetails`) and, in an editable editor, the composite's drag handle: dragging it moves the composite\n * (`startBlockDrag`). A kind with `chrome.tags: false` shows no tag chips and no `+` chip. With `blocks.kindIcon: 'hover'` it shows only while the composite is hovered, its popover is\n * open or the icon has keyboard focus. Chips and popover also render in read-only editors, without edit affordances.\n * The node view's own description and tags rows are hidden by CSS; this overlay shows and edits them.\n */\nconst props = defineProps<{ editor: Editor }>()\n\nconst { Icon: UIcon, Popover: UPopover } = useUiKit()\nconst { t } = useEditorI18n()\n\nconst { rows } = useCompositeRows(() => props.editor)\nconst { host, anchors, frame } = useCompositeAnchors(() => props.editor, rows)\n\n// `isEditable` is not reactive: follow it on every transaction (`EditorSurface` dispatches one after `setEditable`).\nconst editable = shallowRef(false)\nwatch(() => props.editor, (instance, _previous, onCleanup) => {\n editable.value = !instance.isDestroyed && instance.isEditable\n const sync = () => {\n editable.value = !instance.isDestroyed && instance.isEditable\n }\n instance.on('transaction', sync)\n onCleanup(() => instance.off('transaction', sync))\n}, { immediate: true })\n\nconst { settings } = useEditorSettings()\nconst iconOnHover = computed(() => settings.value.blocks.kindIcon === 'hover')\n\n// Hover state of `kindIcon: 'hover'`: the keys of the rows whose composite is under the pointer (that one and every\n// composite around it), plus the row whose chips the pointer is on (they sit outside the editor's DOM).\nconst hoveredKeys = shallowRef<ReadonlySet<string>>(new Set())\nconst chipsHoveredKey = shallowRef<string | null>(null)\nlet hoveredSection: Element | null = null\n\nfunction onEditorMouseover(event: MouseEvent) {\n const section = event.target instanceof Element ? event.target.closest('.composite') : null\n if (section === hoveredSection) return\n hoveredSection = section\n const chain = new Set<Element>()\n for (let el = section; el; el = el.parentElement?.closest('.composite') ?? null) chain.add(el)\n const { view, state } = props.editor\n hoveredKeys.value = new Set(rows.value.filter((row) => {\n const found = compositeOfRow(state.doc, row)\n const dom = found ? view.nodeDOM(found.pos) : null\n const section = dom instanceof Element ? compositeSectionOf(dom) : null\n return section !== null && chain.has(section)\n }).map(row => row.key))\n}\n\nfunction onEditorMouseleave() {\n hoveredSection = null\n hoveredKeys.value = new Set()\n}\n\nwatch([() => props.editor, iconOnHover], ([instance, hover], _previous, onCleanup) => {\n onEditorMouseleave()\n if (!hover || instance.isDestroyed) return\n const { dom } = instance.view\n dom.addEventListener('mouseover', onEditorMouseover)\n dom.addEventListener('mouseleave', onEditorMouseleave)\n onCleanup(() => {\n dom.removeEventListener('mouseover', onEditorMouseover)\n dom.removeEventListener('mouseleave', onEditorMouseleave)\n })\n}, { immediate: true })\n\nfunction onIconDragStart(event: DragEvent, row: CompositeRow) {\n const found = compositeOfRow(props.editor.state.doc, row)\n if (!found || !startBlockDrag(props.editor, event, found.pos)) event.preventDefault()\n}\n\n/** Chips start right after the title's last character and run on to the editor's right edge. */\nconst ROW_HEIGHT = 24\n\nconst expanded = useStoreRef(() => props.editor.storage.composite.expanded)\nconst revealedTitles = useStoreRef(() => props.editor.storage.composite.revealedTitles)\n\nconst placed = computed(() => {\n const baskets = compositeBasketsOf(props.editor)\n // End of the collapsed derived Baustein the rows being walked sit in: its clipped content shows no chrome.\n let hiddenUntil = -1\n return rows.value.flatMap((row) => {\n if (row.pos < hiddenUntil) return []\n const derived = derivedChromeOf(props.editor, row)\n const open = !derived || !row.id || expanded.value.has(row.id)\n if (!open) hiddenUntil = row.end\n const anchor = anchors.value.get(row.key)\n if (!anchor) return []\n const titleHidden = titleHiddenOf(row)\n // A hidden title leaves nothing to measure: the chips sit in the strip beside the kind icon (`composites.css`).\n const inStrip = titleHidden && !(row.id && revealedTitles.value.has(row.id)) && anchor.toggleSize > 0\n // An empty title shows a placeholder the anchor cannot measure: keep clear of it.\n const left = inStrip ? anchor.toggleLeft + anchor.toggleSize + 6 : anchor.lineEnd + (anchor.titleEmpty ? 116 : 12)\n return [{\n row,\n anchor,\n // A kind without `chrome.controls` renders as in a read-only editor.\n editable: editable.value && row.controls,\n left,\n top: (inStrip ? anchor.toggleTop + anchor.toggleSize / 2 : anchor.lastCenter) - ROW_HEIGHT / 2,\n width: Math.max((frame.value?.right ?? anchor.right) - left, 120),\n status: rowStatus(row, t),\n derived: derived && { stale: derived.stale, open, toggleable: !!row.id },\n basket: basketById(baskets, basketOf(row)) ?? null,\n titleHidden,\n }]\n })\n})\n\nfunction toggleExpanded(row: CompositeRow) {\n if (row.id) props.editor.commands.toggleCompositeExpanded(row.id)\n}\n\nfunction removeTag(row: CompositeRow, tag: string) {\n setCompositeTags(props.editor, row, row.tags.filter(candidate => candidate !== tag))\n}\n\nfunction toggleTitleHidden(row: CompositeRow) {\n const found = compositeOfRow(props.editor.state.doc, row)\n if (found) props.editor.commands.setCompositeTitleHidden(!titleHiddenOf(row), found.pos)\n}\n\nconst chip = 'inline-flex h-5 shrink-0 items-center gap-1 rounded-sm px-1.5 text-xs leading-none whitespace-nowrap text-[var(--sk-muted)]'\nconst chipButton = `${chip} transition-colors duration-150 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]`\n\n/** Scale and fade in from the icon (`transform-origin` is Reka's), a bit longer than Nuxt UI's default; `composites.css` defines the keyframes and the reduced-motion override. */\nconst detailsPopoverUi = {\n content: 'composite-popover data-[state=open]:animate-[composite-pop-in_160ms_var(--ease-out)] data-[state=closed]:animate-[composite-pop-out_120ms_var(--ease-out)]',\n}\n</script>\n\n<template>\n <Teleport v-if=\"host\" :to=\"host\">\n <div class=\"absolute left-0 top-0 h-0 w-0\">\n <template v-for=\"item in placed\" :key=\"item.row.key\">\n <UPopover\n v-if=\"item.anchor.toggleSize\"\n :content=\"{ side: 'bottom', align: 'start', sideOffset: 4 }\"\n :ui=\"detailsPopoverUi\"\n >\n <!-- A span, not a `button`: Firefox does not start drags from buttons. -->\n <span\n role=\"button\"\n tabindex=\"0\"\n :draggable=\"item.editable\"\n :class=\"[\n 'absolute z-10 flex items-center justify-center rounded-sm bg-[var(--sk-bg)] text-[var(--sk-muted)] transition-[color,background-color,opacity] duration-120 motion-reduce:transition-none hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--sk-primary)]',\n item.editable ? 'cursor-grab active:cursor-grabbing' : 'cursor-pointer',\n iconOnHover && !hoveredKeys.has(item.row.key) && chipsHoveredKey !== item.row.key && 'opacity-0 hover:opacity-100 focus-visible:opacity-100 data-[state=open]:opacity-100',\n ]\"\n :style=\"{ top: `${item.anchor.toggleTop}px`, left: `${item.anchor.toggleLeft}px`, width: `${item.anchor.toggleSize}px`, height: `${item.anchor.toggleSize}px` }\"\n :aria-label=\"t('composites.chrome.details', { kind: item.row.kindLabel })\"\n :title=\"item.editable ? t('composites.chrome.detailsDrag', { kind: item.row.kindLabel }) : t('composites.chrome.details', { kind: item.row.kindLabel })\"\n @keydown.enter.space.prevent=\"($event.currentTarget as HTMLElement).click()\"\n @dragstart=\"onIconDragStart($event, item.row)\"\n >\n <UIcon :key=\"item.row.icon\" :name=\"item.row.icon\" class=\"size-3.5\" />\n </span>\n <template #content>\n <CompositeDetails :editor=\"editor\" :row=\"item.row\" :editable=\"item.editable\" />\n </template>\n </UPopover>\n\n <div\n v-if=\"item.editable || item.basket || item.status || item.derived || (item.row.tagsVisible && item.row.tags.length)\"\n class=\"absolute z-10 flex items-center gap-px overflow-hidden rounded-md bg-[var(--sk-bg)]\"\n :style=\"{ top: `${item.top}px`, left: `${item.left}px`, maxWidth: `${item.width}px`, height: `${ROW_HEIGHT}px` }\"\n @mouseenter=\"chipsHoveredKey = item.row.key\"\n @mouseleave=\"chipsHoveredKey = null\"\n >\n <template v-if=\"item.editable\">\n <CompositeBasketMenu :editor=\"editor\" :row=\"item.row\">\n <button type=\"button\" :class=\"chipButton\" :aria-label=\"t('composites.basket.label')\" :title=\"item.basket ? `${t('composites.basket.label')}: ${item.basket.label}` : t('composites.basket.label')\">\n <span v-if=\"item.basket\" class=\"size-2.5 rounded-full\" :style=\"{ backgroundColor: item.basket.color }\" />\n <UIcon v-else name=\"i-lucide-circle-dashed\" class=\"size-3.5\" />\n </button>\n </CompositeBasketMenu>\n <button\n type=\"button\"\n :class=\"chipButton\"\n :aria-label=\"t(item.titleHidden ? 'composites.titleHidden.show' : 'composites.titleHidden.hide')\"\n :title=\"t(item.titleHidden ? 'composites.titleHidden.show' : 'composites.titleHidden.hide')\"\n @click=\"toggleTitleHidden(item.row)\"\n >\n <UIcon :name=\"item.titleHidden ? 'i-lucide-eye' : 'i-lucide-eye-off'\" class=\"size-3.5\" />\n </button>\n </template>\n <span v-else-if=\"item.basket\" :class=\"chip\" :title=\"item.basket.label\">\n <span class=\"size-2.5 rounded-full\" :style=\"{ backgroundColor: item.basket.color }\" />\n </span>\n\n <template v-if=\"item.derived\">\n <button\n v-if=\"item.derived.toggleable\"\n type=\"button\"\n :class=\"chipButton\"\n :aria-expanded=\"item.derived.open\"\n :aria-label=\"t(item.derived.open ? 'composites.derivation.collapse' : 'composites.derivation.expand')\"\n :title=\"t(item.derived.open ? 'composites.derivation.collapse' : 'composites.derivation.expand')\"\n @click=\"toggleExpanded(item.row)\"\n >\n <UIcon :name=\"item.derived.open ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'\" class=\"size-3.5\" />\n </button>\n <span :class=\"chip\">\n <UIcon name=\"i-lucide-git-branch\" class=\"size-3.5\" />{{ t('composites.derivation.badge') }}\n </span>\n <span v-if=\"item.derived.stale\" :class=\"[chip, 'text-[var(--sk-warning)]']\">\n <UIcon name=\"i-lucide-triangle-alert\" class=\"size-3.5\" />{{ t('composites.derivation.stale') }}\n </span>\n </template>\n\n <template v-if=\"item.status\">\n <CompositeStatusMenu v-if=\"item.editable\" :editor=\"editor\" :row=\"item.row\">\n <button type=\"button\" :class=\"chipButton\" :aria-label=\"t('composites.status.label', { status: item.status.label })\">\n <UIcon :name=\"item.status.icon\" :class=\"['size-3.5', item.status.color]\" />{{ item.status.label }}\n </button>\n </CompositeStatusMenu>\n <span v-else :class=\"chip\">\n <UIcon :name=\"item.status.icon\" :class=\"['size-3.5', item.status.color]\" />{{ item.status.label }}\n </span>\n </template>\n\n <span v-for=\"tag in item.row.tagsVisible ? item.row.tags : []\" :key=\"tag\" :class=\"[chip, 'group max-w-40 gap-0']\">\n <span class=\"truncate\">#{{ tag }}</span>\n <button\n v-if=\"item.editable\"\n type=\"button\"\n class=\"flex h-4 w-0 shrink-0 items-center justify-center overflow-hidden rounded-sm opacity-0 transition-all duration-150 group-hover:ml-1 group-hover:w-4 group-hover:opacity-100 hover:bg-[var(--sk-bg-elevated)] hover:text-[var(--sk-fg-highlighted)] focus-visible:ml-1 focus-visible:w-4 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-[var(--sk-primary)]\"\n :aria-label=\"t('composites.tag.remove', { tag })\"\n @click=\"removeTag(item.row, tag)\"\n >\n <UIcon name=\"i-lucide-x\" class=\"size-3\" />\n </button>\n </span>\n\n <UPopover\n v-if=\"item.editable && item.row.tagsVisible\"\n :content=\"{ side: 'bottom', align: 'start', sideOffset: 6, onCloseAutoFocus: (event: Event) => event.preventDefault() }\"\n >\n <button type=\"button\" :class=\"chipButton\" :aria-label=\"t('composites.tag.add')\" :title=\"t('composites.tag.add')\">\n <UIcon name=\"i-lucide-plus\" class=\"size-3.5\" />\n </button>\n <template #content>\n <div class=\"w-64 p-3\">\n <CompositeTagsEditor :editor=\"editor\" :row=\"item.row\" />\n </div>\n </template>\n </UPopover>\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n"],"mappings":"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"}
@@ -19,6 +19,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
19
19
  });
20
20
  const basket = computed(() => basketOf(props.node));
21
21
  const basketColor = computed(() => compositeBasketsOf(props.editor).find((candidate) => candidate.id === basket.value)?.color);
22
+ const kindTone = computed(() => kind.value.chrome?.tone || void 0);
22
23
  const revealedTitles = useStoreRef(() => props.editor.storage.composite.revealedTitles);
23
24
  const titleHidden = computed(() => {
24
25
  const id = props.node.attrs.id;
@@ -28,7 +29,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
28
29
  const cssString = (text) => `"${text.replace(/["\\]/g, "\\$&").replace(/\n/g, "\\a ")}"`;
29
30
  const placeholderVars = computed(() => ({
30
31
  "--composite-title-placeholder": cssString(kind.value.titlePlaceholder),
31
- ...basketColor.value ? { "--sk-basket-color": basketColor.value } : {}
32
+ ...basketColor.value ? { "--sk-basket-color": basketColor.value } : {},
33
+ ...kindTone.value ? { "--sk-kind-tone": kindTone.value } : {}
32
34
  }));
33
35
  return (_ctx, _cache) => {
34
36
  return openBlock(), createBlock(unref(NodeViewWrapper), {
@@ -41,6 +43,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
41
43
  "data-kind": _ctx.node.attrs.kind,
42
44
  "data-id": _ctx.node.attrs.id || void 0,
43
45
  "data-basket": basket.value || void 0,
46
+ "data-kind-tone": kindTone.value ? "" : void 0,
44
47
  "data-title-hidden": titleHidden.value ? "" : void 0,
45
48
  style: normalizeStyle(placeholderVars.value)
46
49
  }, {
@@ -59,6 +62,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
59
62
  "data-kind",
60
63
  "data-id",
61
64
  "data-basket",
65
+ "data-kind-tone",
62
66
  "data-title-hidden",
63
67
  "style"
64
68
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeView.js","names":["selected","node","_openBlock","_createBlock","_unref","_normalizeClass","_normalizeStyle","_withCtx","_createCommentVNode","_createElementVNode","_createVNode"],"sources":["../../../../src/features/composites/components/CompositeView.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { NodeViewContent, NodeViewWrapper, nodeViewProps } from '@tiptap/vue-3'\nimport { computed } from 'vue'\nimport { basketOf, titleHiddenOf } from '../baskets'\nimport { compositeKind } from '../kinds'\nimport { compositeBasketsOf, compositeKindsOf } from '../nodes'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { derivationOf } from '../derivation'\n\nconst props = defineProps(nodeViewProps)\n\nconst kind = computed(() => compositeKind(compositeKindsOf(props.editor), String(props.node.attrs.kind)))\n\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.\nconst expanded = useStoreRef(() => props.editor.storage.composite.expanded)\nconst collapsed = computed(() => {\n const id: unknown = props.node.attrs.id\n return typeof id === 'string' && id !== '' && derivationOf(props.node) !== null && !expanded.value.has(id)\n})\n\n// Colour basket (`meta.basket`): `data-basket` carries the id, the stripe takes the basket's colour from `--sk-basket-color`.\nconst basket = computed(() => basketOf(props.node))\nconst basketColor = computed(() => compositeBasketsOf(props.editor).find(candidate => candidate.id === basket.value)?.color)\n\n// A hidden title (`meta.titleHidden`) stays hidden until a caret enters it (`revealedTitles`, see `CompositeNode`).\nconst revealedTitles = useStoreRef(() => props.editor.storage.composite.revealedTitles)\nconst titleHidden = computed(() => {\n const id: unknown = props.node.attrs.id\n return titleHiddenOf(props.node) && !(typeof id === 'string' && revealedTitles.value.has(id))\n})\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n// Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\nconst placeholderVars = computed(() => ({\n '--composite-title-placeholder': cssString(kind.value.titlePlaceholder),\n ...(basketColor.value ? { '--sk-basket-color': basketColor.value } : {}),\n}))\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"section\"\n :class=\"['composite', { 'is-collapsed': collapsed, 'is-selected rounded-md ring-1 ring-[var(--sk-primary)]': selected }]\"\n data-type=\"composite\"\n :data-kind=\"node.attrs.kind\"\n :data-id=\"node.attrs.id || undefined\"\n :data-basket=\"basket || 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 class=\"composite__toggle\" contenteditable=\"false\" aria-hidden=\"true\" />\n <NodeViewContent class=\"composite__content\" />\n </NodeViewWrapper>\n</template>\n"],"mappings":";;;;;;;;;;;;EASA,MAAM,QAAQ;EAEd,MAAM,OAAO,eAAe,cAAc,iBAAiB,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC;EAIxG,MAAM,WAAW,kBAAkB,MAAM,OAAO,QAAQ,UAAU,QAAQ;EAC1E,MAAM,YAAY,eAAe;GAC/B,MAAM,KAAc,MAAM,KAAK,MAAM;GACrC,OAAO,OAAO,OAAO,YAAY,OAAO,MAAM,aAAa,MAAM,IAAI,MAAM,QAAQ,CAAC,SAAS,MAAM,IAAI,EAAE;EAC3G,CAAC;EAGD,MAAM,SAAS,eAAe,SAAS,MAAM,IAAI,CAAC;EAClD,MAAM,cAAc,eAAe,mBAAmB,MAAM,MAAM,CAAC,CAAC,MAAK,cAAa,UAAU,OAAO,OAAO,KAAK,CAAC,EAAE,KAAK;EAG3H,MAAM,iBAAiB,kBAAkB,MAAM,OAAO,QAAQ,UAAU,cAAc;EACtF,MAAM,cAAc,eAAe;GACjC,MAAM,KAAc,MAAM,KAAK,MAAM;GACrC,OAAO,cAAc,MAAM,IAAI,KAAK,EAAE,OAAO,OAAO,YAAY,eAAe,MAAM,IAAI,EAAE;EAC7F,CAAC;;EAGD,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;EAE9F,MAAM,kBAAkB,gBAAgB;GACtC,iCAAiC,UAAU,KAAK,MAAM,gBAAgB;GACtE,GAAI,YAAY,QAAQ,EAAE,qBAAqB,YAAY,MAAM,IAAI,CAAC;EACxE,EAAE;;GAIA,OAAAE,UAAA,GAAAC,YAckBC,MAAA,eAAA,GAAA;IAbhB,IAAG;IACF,OAAKC,eAAA,CAAA,aAAA;KAAA,gBAAkC,UAAA;KAAS,0DAA4DL,KAAAA;IAAQ,CAAA,CAAA;IACrH,aAAU;IACT,aAAWC,KAAAA,KAAK,MAAM;IACtB,WAASA,KAAAA,KAAK,MAAM,MAAM,KAAA;IAC1B,eAAa,OAAA,SAAU,KAAA;IACvB,qBAAmB,YAAA,QAAW,KAAQ,KAAA;IACtC,OAAKK,eAAE,gBAAA,KAAe;;IAEvB,SAAAC,cAC6G;KAD7GC,mBAAA,oOAAA;KAEA,OAAA,OAAA,OAAA,KAAAC,mBAA6E,QAAA;MAAvE,OAAM;MAAoB,iBAAgB;MAAQ,eAAY;;KACpEC,YAA8CN,MAAA,eAAA,GAAA,EAA7B,OAAM,qBAAoB,CAAA"}
1
+ {"version":3,"file":"CompositeView.js","names":["selected","node","_openBlock","_createBlock","_unref","_normalizeClass","_normalizeStyle","_withCtx","_createCommentVNode","_createElementVNode","_createVNode"],"sources":["../../../../src/features/composites/components/CompositeView.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { NodeViewContent, NodeViewWrapper, nodeViewProps } from '@tiptap/vue-3'\nimport { computed } from 'vue'\nimport { basketOf, titleHiddenOf } from '../baskets'\nimport { compositeKind } from '../kinds'\nimport { compositeBasketsOf, compositeKindsOf } from '../nodes'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { derivationOf } from '../derivation'\n\nconst props = defineProps(nodeViewProps)\n\nconst kind = computed(() => compositeKind(compositeKindsOf(props.editor), String(props.node.attrs.kind)))\n\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.\nconst expanded = useStoreRef(() => props.editor.storage.composite.expanded)\nconst collapsed = computed(() => {\n const id: unknown = props.node.attrs.id\n return typeof id === 'string' && id !== '' && derivationOf(props.node) !== null && !expanded.value.has(id)\n})\n\n// Colour basket (`meta.basket`): `data-basket` carries the id, the stripe takes the basket's colour from `--sk-basket-color`.\nconst basket = computed(() => basketOf(props.node))\nconst basketColor = computed(() => compositeBasketsOf(props.editor).find(candidate => candidate.id === basket.value)?.color)\n\n// Kind tone (`CompositeKind.chrome.tone`): `data-kind-tone` marks the wrapper, the surface reads the colour from `--sk-kind-tone`.\nconst kindTone = computed(() => kind.value.chrome?.tone || undefined)\n\n// A hidden title (`meta.titleHidden`) stays hidden until a caret enters it (`revealedTitles`, see `CompositeNode`).\nconst revealedTitles = useStoreRef(() => props.editor.storage.composite.revealedTitles)\nconst titleHidden = computed(() => {\n const id: unknown = props.node.attrs.id\n return titleHiddenOf(props.node) && !(typeof id === 'string' && revealedTitles.value.has(id))\n})\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n// Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\nconst placeholderVars = computed(() => ({\n '--composite-title-placeholder': cssString(kind.value.titlePlaceholder),\n ...(basketColor.value ? { '--sk-basket-color': basketColor.value } : {}),\n ...(kindTone.value ? { '--sk-kind-tone': kindTone.value } : {}),\n}))\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"section\"\n :class=\"['composite', { 'is-collapsed': collapsed, 'is-selected rounded-md ring-1 ring-[var(--sk-primary)]': selected }]\"\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 class=\"composite__toggle\" contenteditable=\"false\" aria-hidden=\"true\" />\n <NodeViewContent class=\"composite__content\" />\n </NodeViewWrapper>\n</template>\n"],"mappings":";;;;;;;;;;;;EASA,MAAM,QAAQ;EAEd,MAAM,OAAO,eAAe,cAAc,iBAAiB,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC;EAIxG,MAAM,WAAW,kBAAkB,MAAM,OAAO,QAAQ,UAAU,QAAQ;EAC1E,MAAM,YAAY,eAAe;GAC/B,MAAM,KAAc,MAAM,KAAK,MAAM;GACrC,OAAO,OAAO,OAAO,YAAY,OAAO,MAAM,aAAa,MAAM,IAAI,MAAM,QAAQ,CAAC,SAAS,MAAM,IAAI,EAAE;EAC3G,CAAC;EAGD,MAAM,SAAS,eAAe,SAAS,MAAM,IAAI,CAAC;EAClD,MAAM,cAAc,eAAe,mBAAmB,MAAM,MAAM,CAAC,CAAC,MAAK,cAAa,UAAU,OAAO,OAAO,KAAK,CAAC,EAAE,KAAK;EAG3H,MAAM,WAAW,eAAe,KAAK,MAAM,QAAQ,QAAQ,KAAA,CAAS;EAGpE,MAAM,iBAAiB,kBAAkB,MAAM,OAAO,QAAQ,UAAU,cAAc;EACtF,MAAM,cAAc,eAAe;GACjC,MAAM,KAAc,MAAM,KAAK,MAAM;GACrC,OAAO,cAAc,MAAM,IAAI,KAAK,EAAE,OAAO,OAAO,YAAY,eAAe,MAAM,IAAI,EAAE;EAC7F,CAAC;;EAGD,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;EAE9F,MAAM,kBAAkB,gBAAgB;GACtC,iCAAiC,UAAU,KAAK,MAAM,gBAAgB;GACtE,GAAI,YAAY,QAAQ,EAAE,qBAAqB,YAAY,MAAM,IAAI,CAAC;GACtE,GAAI,SAAS,QAAQ,EAAE,kBAAkB,SAAS,MAAM,IAAI,CAAC;EAC/D,EAAE;;GAIA,OAAAE,UAAA,GAAAC,YAekBC,MAAA,eAAA,GAAA;IAdhB,IAAG;IACF,OAAKC,eAAA,CAAA,aAAA;KAAA,gBAAkC,UAAA;KAAS,0DAA4DL,KAAAA;IAAQ,CAAA,CAAA;IACrH,aAAU;IACT,aAAWC,KAAAA,KAAK,MAAM;IACtB,WAASA,KAAAA,KAAK,MAAM,MAAM,KAAA;IAC1B,eAAa,OAAA,SAAU,KAAA;IACvB,kBAAgB,SAAA,QAAQ,KAAQ,KAAA;IAChC,qBAAmB,YAAA,QAAW,KAAQ,KAAA;IACtC,OAAKK,eAAE,gBAAA,KAAe;;IAEvB,SAAAC,cAC6G;KAD7GC,mBAAA,oOAAA;KAEA,OAAA,OAAA,OAAA,KAAAC,mBAA6E,QAAA;MAAvE,OAAM;MAAoB,iBAAgB;MAAQ,eAAY;;KACpEC,YAA8CN,MAAA,eAAA,GAAA,EAA7B,OAAM,qBAAoB,CAAA"}
@@ -19,6 +19,7 @@ import { AcceptedChildren, compositeInsertGuard } from "./accepted-children.js";
19
19
  import { documentCompositeMarkdown, markdownFileName } from "./markdown-export.js";
20
20
  import { compositeNodes } from "./node-views.js";
21
21
  import { CompositeFocus } from "./focus.js";
22
+ import { CompositeMerge } from "./merge.js";
22
23
  import { REFERENCE_AI_BLOCK } from "./reference-ai.js";
23
24
  import { referenceSuggestion } from "./reference-suggestion.js";
24
25
  import { SourceReveal } from "./reveal-source.js";
@@ -64,6 +65,7 @@ function compositeFeatureCore(ui, options = {}) {
64
65
  }),
65
66
  SourceReveal,
66
67
  CompositeFocus,
68
+ CompositeMerge,
67
69
  CompositeSplit.configure({
68
70
  defaultKind: () => ctx.settings.get().blocks.defaultKind,
69
71
  targetChars: () => ctx.settings.get().blocks.splitTargetChars
@@ -103,7 +105,16 @@ function compositeFeatureCore(ui, options = {}) {
103
105
  if (id) editor.commands.focusComposite(id);
104
106
  }
105
107
  },
106
- ...splitBlockActions(ctx)
108
+ ...splitBlockActions(ctx),
109
+ {
110
+ id: "composite-merge-next",
111
+ label: ctx.t("composites.merge.next"),
112
+ icon: "i-lucide-merge",
113
+ ability: ABILITY.compositeMeta,
114
+ order: 470,
115
+ isVisible: ({ editor, pos }) => editor.can().mergeCompositeWithNext(pos),
116
+ run: ({ editor, pos }) => void editor.chain().focus().mergeCompositeWithNext(pos).run()
117
+ }
107
118
  ],
108
119
  overlays: [ui.chrome, ui.focusChip].filter((overlay) => overlay !== void 0),
109
120
  settingsTabs: (ctx) => [{
@@ -1 +1 @@
1
- {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/composites/feature.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { BlockAction, CommandDef, EditorFeature, FeatureContext, MenuItem, ToolbarGroupDef } from '../../core'\nimport { abilitiesAtSelection, downloadText, editorEntryOf, settingsTabsOf } from '../../core'\nimport type { Translate } from '../../i18n'\nimport { ABILITY, blockIdOf, findBlockById } from '../../core/schema'\nimport { AcceptedChildren, compositeInsertGuard } from './accepted-children'\nimport { type Basket, defaultBaskets } from './baskets'\nimport { bibOf, bibtexOf, cslOf } from './bibliography'\nimport { compositeConversions } from './convert'\nimport { bodyMarkdown, derivationOf } from './derivation'\nimport { blocksFromMarkdown } from './fences'\nimport { structureBlocks } from './heading-composites'\nimport { type CompositeKind, compositeKind, defaultCompositeKinds } from './kinds'\nimport { migrateLegacyContent } from './legacy'\nimport { compositeSchemaExtensions } from './schema'\nimport { documentCompositeMarkdown, markdownFileName } from './markdown-export'\nimport { type CompositeNodeViews, compositeNodes } from './node-views'\nimport { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeTitleNode, compositeAround, compositeKindsOf } from './nodes'\nimport { CompositeFocus } from './focus'\nimport { REFERENCE_TRIGGER } from './reference'\nimport { REFERENCE_AI_BLOCK } from './reference-ai'\nimport { referenceSuggestion } from './reference-suggestion'\nimport { compositeIdsOf, normalizeReferences } from './reference-text'\nimport { SourceReveal } from './reveal-source'\nimport { CompositeSplit, type SplitMode } from './split'\nimport { Structure, structureOf } from './structure'\nimport { STRUCTURE_MODE_KEYS } from './structure-mode'\n\n/** What a framework binding supplies to the composites feature. */\nexport interface CompositesUi<C> {\n /** The chips on each title line and the details popover on the kind icon; mounted as an overlay. */\n chrome: C\n /** The focus chip („Fokus: <Titel> · Aufheben“) shown while a Baustein is focused; mounted as an overlay. Absent: no chip (the focus mode itself works). */\n focusChip?: C\n /** The „Bearbeiten“ settings tab; receives `{ kinds }` as props. */\n settingsTab: C\n /** The composite block view of the framework. */\n nodeViews: CompositeNodeViews\n}\n\n/** Options of `compositeFeature`. */\nexport interface CompositeFeatureOptions {\n /** The composite kinds („Bausteine“) offered in the editor, with their own labels (default: `defaultCompositeKinds(t)`, the built-in kinds in the editor's language); read once. */\n kinds?: readonly CompositeKind[]\n /** The colour baskets a Baustein can be put into (default: `defaultBaskets(t)`, red/orange/yellow/green/blue in the editor's language; colours are the `--sk-basket-<id>` CSS variables); read once. */\n baskets?: readonly Basket[]\n}\n\n/** Heading level the structure stage starts at when it turns composites into headings (below the document title). */\nconst STRUCTURE_STAGE_LEVEL = 2\n\n/**\n * Composites („Bausteine“): the node family with its node views, the toolbar group (insert, „In Baustein umwandeln“,\n * „Gliederung umwandeln“), `/` commands, the conversion providers (wrap into / switch kind of / unwrap composites),\n * Markdown `:::` fences, legacy `section` migration, the preferred-structure setting and its `editing` settings tab,\n * the chips on each title line (status, tags) and the details popover on the kind icon (the binding's `chrome` overlay), focus mode on one\n * Baustein (`CompositeFocus`, the „Fokussieren“ block action and the binding's `focusChip` overlay), and\n * the AI view of kinds and structure, and the kinds' accepted children (`AcceptedChildren`: an edit that nests a Baustein\n * into one that does not accept its kind is refused with a notice). Contributes the `parseMarkdown`,\n * `structure` and `migrateContent` stages. Imports no AI, media or transcript code.\n */\nexport function compositeFeatureCore<C>(ui: CompositesUi<C>, options: CompositeFeatureOptions = {}): EditorFeature<C> {\n // Host kinds keep their labels; the built-in ones are produced from the context's translator (memoized per `t`).\n const kindsOf = (ctx: { t: Translate }) => options.kinds ?? defaultCompositeKinds(ctx.t)\n const basketsOf = (ctx: { t: Translate }) => options.baskets ?? defaultBaskets(ctx.t)\n const { Composite, CompositeTags, Reference } = compositeNodes(ui.nodeViews)\n return {\n id: 'composites',\n dimension: 'content',\n schemaExtensions: () => compositeSchemaExtensions({ ...(options.kinds && { kinds: options.kinds }), ...(options.baskets && { baskets: options.baskets }) }),\n extensions: ctx => [\n Composite.configure({ kinds: kindsOf(ctx), baskets: basketsOf(ctx) }),\n CompositeTitleNode,\n CompositeDescriptionNode,\n CompositeTags,\n Structure.configure({ mode: () => ctx.settings.get().blocks.structure }),\n AcceptedChildren.configure({ notify: ctx.notify, t: ctx.t }),\n SourceReveal,\n CompositeFocus,\n CompositeSplit.configure({ defaultKind: () => ctx.settings.get().blocks.defaultKind, targetChars: () => ctx.settings.get().blocks.splitTargetChars }),\n Reference.configure({ suggestion: referenceSuggestion(ctx.t) }),\n ],\n toolbarGroups: COMPOSITE_TOOLBAR_GROUPS,\n commands: ctx => compositeCommands(ctx, kindsOf(ctx)),\n insertGuards: () => [compositeInsertGuard],\n blockActions: ctx => [{\n id: 'document-export',\n label: ctx.t('composites.blockAction.export'),\n icon: 'i-lucide-download',\n ability: ABILITY.compositeExport,\n order: 400,\n isVisible: ({ node }) => node.attrs.kind === 'document',\n run: ({ editor, node }) => downloadText(markdownFileName(node), documentCompositeMarkdown(editor, node)),\n }, {\n id: 'bibliography-export',\n label: ctx.t('composites.blockAction.bibtex'),\n icon: 'i-lucide-book-marked',\n ability: ABILITY.compositeExport,\n order: 410,\n isVisible: ({ node }) => bibOf(node) !== null,\n run: ({ node }) => downloadText(`${markdownFileName(node).replace(/\\.md$/, '')}.bib`, bibtexOf(cslOf(node)!), 'text/x-bibtex;charset=utf-8'),\n }, {\n id: 'composite-focus',\n label: ctx.t('composites.focus.action'),\n icon: 'i-lucide-focus',\n order: 420,\n isVisible: ({ node }) => node.type.name === 'composite',\n run: ({ editor, node }) => {\n const id = blockIdOf(node)\n if (id) editor.commands.focusComposite(id)\n },\n }, ...splitBlockActions(ctx)],\n overlays: [ui.chrome, ui.focusChip].filter(overlay => overlay !== undefined),\n settingsTabs: ctx => [{ id: 'editing', label: ctx.t('composites.tab'), icon: 'i-lucide-pencil', component: ui.settingsTab, props: { kinds: kindsOf(ctx) } }],\n blocks: {\n parseMarkdown: (editor, markdown) => blocksFromMarkdown(md => editor.markdown!.parse(md), markdown, compositeKindsOf(editor)),\n structure: (editor, blocks) => {\n const { schema } = editor\n return structureBlocks(schema, blocks.map(block => schema.nodeFromJSON(block)), structureOf(editor), STRUCTURE_STAGE_LEVEL, compositeKindsOf(editor)).map(node => node.toJSON())\n },\n migrateContent: migrateLegacyContent,\n normalize: (editor, blocks) => normalizeReferences(blocks, compositeIdsOf(editor.state.doc)),\n },\n conversions: compositeConversions(options.kinds),\n aiContext: editor => ({\n kinds: compositeKindsOf(editor).map(({ id, label, fields, ai }) => ({ id, label, fields, ...(ai?.purpose && { purpose: ai.purpose }) })),\n structure: structureOf(editor),\n blocks: [REFERENCE_AI_BLOCK],\n }),\n // A Baustein derived from another block hands the model that source block's Markdown.\n aiBlockData: ({ editor, node }) => {\n const from = derivationOf(node)?.from\n const source = from && 'block' in from ? findBlockById(editor.state.doc, from.block)?.node : undefined\n // i18n-ignore: model-facing data label (German prompt text, not UI)\n return source?.type.name === 'composite' ? [{ label: `Quelle: ${source.child(0).textContent.trim()}`, text: bodyMarkdown(editor, source) }] : []\n },\n }\n}\n\n/**\n * The four split actions of a Baustein: at the caret (as sibling or sub-Bausteine; offered on the Baustein around the\n * caret while the caret is past the first body block) and by length (as sub-Bausteine or siblings; offered while the\n * body falls into two parts or more). Each is hidden when the command refuses, so a kind that accepts no child kind\n * never shows the `children` variants.\n */\nfunction splitBlockActions({ t }: FeatureContext): BlockAction[] {\n const atCaret = (id: string, labelKey: 'composites.split.here' | 'composites.split.children', icon: string, order: number, mode: SplitMode): BlockAction => ({\n id,\n label: t(labelKey),\n icon,\n ability: ABILITY.compositeMeta,\n order,\n isVisible: ({ editor, pos }) => {\n const { $head } = editor.state.selection\n const found = compositeAround($head)\n return found?.pos === pos && $head.index(found.depth) > COMPOSITE_CHROME_COUNT && editor.can().splitCompositeAtCaret({ mode })\n },\n run: ({ editor }) => void editor.chain().focus().splitCompositeAtCaret({ mode }).run(),\n })\n const byLength = (id: string, labelKey: 'composites.split.lengthChildren' | 'composites.split.lengthSiblings', icon: string, order: number, mode: SplitMode): BlockAction => ({\n id,\n label: t(labelKey),\n icon,\n ability: ABILITY.compositeMeta,\n order,\n isVisible: ({ editor, pos }) => editor.can().splitCompositeByLength({ mode, pos }),\n run: ({ editor, pos }) => void editor.chain().focus().splitCompositeByLength({ mode, pos }).run(),\n })\n return [\n atCaret('composite-split-here', 'composites.split.here', 'i-lucide-scissors', 430, 'siblings'),\n atCaret('composite-split-children', 'composites.split.children', 'i-lucide-split', 440, 'children'),\n byLength('composite-split-length-children', 'composites.split.lengthChildren', 'i-lucide-ruler', 450, 'children'),\n byLength('composite-split-length-siblings', 'composites.split.lengthSiblings', 'i-lucide-ruler', 460, 'siblings'),\n ]\n}\n\nconst COMPOSITE_TOOLBAR_GROUPS: ToolbarGroupDef[] = [{ id: 'composites', order: 60, labelKey: 'palette.group.composites' }]\n\n/**\n * Converting headings to Bausteine and back: the checks and actions the toolbar's „Gliederung umwandeln“ menu and the\n * `/gliedern*` and `/aufloesen*` commands share, so both placements gate and act identically. They read the scope and\n * default kind from the settings at call time.\n */\nfunction structureActions({ settings }: FeatureContext) {\n const groupOptions = (recursive: boolean) => ({ recursive, scope: settings.get().editing.headingConversionScope, kind: settings.get().blocks.defaultKind })\n const flattenOptions = (recursive: boolean) => ({ recursive, scope: settings.get().editing.headingConversionScope })\n return {\n canGroup: (editor: Editor, recursive: boolean) => editor.can().convertHeadingsToComposites(groupOptions(recursive)),\n canFlatten: (editor: Editor, recursive: boolean) => editor.can().convertCompositesToHeadings(flattenOptions(recursive)),\n group: (editor: Editor, recursive: boolean) => void editor.chain().focus().convertHeadingsToComposites(groupOptions(recursive)).run(),\n flatten: (editor: Editor, recursive: boolean) => void editor.chain().focus().convertCompositesToHeadings(flattenOptions(recursive)).run(),\n }\n}\n\n/**\n * The commands of the composites feature, each declared once. Toolbar group beside the inserts: the default kind's\n * insert button (it follows the setting, so label/icon/shortcut/`creates` are getters read at render time), „In\n * Baustein umwandeln“ (one entry per kind for the caret's block) and „Gliederung umwandeln“ (headings <-> composites in\n * both directions, the preferred structure's direction first). `/` menu: one command per kind (`creates` that kind, so\n * the insert guard hides kinds the surrounding Baustein does not accept) and the four heading conversions.\n */\nfunction compositeCommands<C>(ctx: FeatureContext, kinds: readonly CompositeKind[]): CommandDef<C>[] {\n const { settings, t } = ctx\n const defaultKind = () => compositeKind(kinds, settings.get().blocks.defaultKind)\n const { canGroup, canFlatten, group, flatten } = structureActions(ctx)\n\n function kindItems(editor: Editor): MenuItem[] {\n return [\n { type: 'label', label: t('composites.menu.kindHeading') },\n ...compositeKindsOf(editor).map((kind): MenuItem => {\n const target = { type: 'composite', kind: kind.id } as const\n return { label: kind.label, icon: kind.icon, disabled: !editor.can().convertBlockTo(target), onSelect: () => editor.chain().focus().convertBlockTo(target).run() }\n }),\n ]\n }\n\n function structureItems(editor: Editor): MenuItem[] {\n const structure = settings.get().blocks.structure\n const abilities = abilitiesAtSelection(editor)\n const composite = abilities.has(ABILITY.composite)\n const headings = abilities.has(ABILITY.headings)\n const sep: MenuItem = { type: 'separator' }\n const toComposites: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toComposites') },\n { label: t('composites.menu.toComposites.top'), description: t('composites.menu.toComposites.top.description'), icon: 'i-lucide-layers', disabled: !composite || !canGroup(editor, false), onSelect: () => group(editor, false) },\n { label: t('composites.menu.toComposites.all'), description: t('composites.menu.toComposites.all.description'), icon: 'i-lucide-list-tree', disabled: !composite || !canGroup(editor, true), onSelect: () => group(editor, true) },\n ]\n const toHeadings: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toHeadings') },\n { label: t('composites.menu.toHeadings.top'), description: t('composites.menu.toHeadings.top.description'), icon: 'i-lucide-heading', disabled: !headings || !canFlatten(editor, false), onSelect: () => flatten(editor, false) },\n { label: t('composites.menu.toHeadings.all'), description: t('composites.menu.toHeadings.all.description'), icon: 'i-lucide-align-left', disabled: !headings || !canFlatten(editor, true), onSelect: () => flatten(editor, true) },\n ]\n const entry = editorEntryOf(editor)\n // The settings entry exists only while some feature contributes a tab to open.\n const settingsEntry: MenuItem[] = entry && settingsTabsOf(entry.preset, entry.ctx.app).length\n ? [sep, { label: t('composites.menu.settings'), icon: 'i-lucide-settings-2', onSelect: () => entry.ui.openSettings('editing') }]\n : []\n return [\n { type: 'label', label: t('composites.menu.preferred', { mode: t(STRUCTURE_MODE_KEYS[structure].labelKey) }) },\n ...(structure === 'composite' ? [...toComposites, sep, ...toHeadings] : [...toHeadings, sep, ...toComposites]),\n ...settingsEntry,\n ]\n }\n\n const insertKind = (kind: string, slashId: string, label: string, icon: string): CommandDef<C> => ({\n id: `composite.${kind}`,\n slash: { id: slashId },\n creates: { type: 'composite', attrs: { kind } },\n icon,\n label,\n ability: ABILITY.composite,\n run: (editor) => { editor.chain().focus().insertComposite(kind).run() },\n })\n\n return [\n {\n id: 'insert',\n toolbar: { group: 'composites', order: 10 },\n // Getters: the default kind arrives with the server settings; the toolbar reads them at render time.\n get icon() { return defaultKind().icon },\n get label() { return defaultKind().label },\n // Mod-Shift-a (CompositeNode) always inserts a `section`, so only then is it shown as the shortcut.\n get kbds() { return defaultKind().id === 'section' ? ['meta', 'shift', 'a'] : undefined },\n get creates() { return { type: 'composite', attrs: { kind: defaultKind().id } } },\n ability: ABILITY.composite,\n can: editor => editor.can().insertComposite(defaultKind().id),\n run: (editor) => { editor.chain().focus().insertComposite(defaultKind().id).run() },\n },\n {\n id: 'to-kind',\n toolbar: { group: 'composites', order: 20 },\n icon: 'i-lucide-replace',\n label: t('composites.toolbar.toKind'),\n ability: ABILITY.composite,\n can: editor => kindItems(editor).some(item => item.type !== 'label' && !item.disabled),\n menu: kindItems,\n },\n {\n id: 'structure',\n toolbar: { group: 'composites', order: 30 },\n icon: 'i-lucide-list-tree',\n label: t('composites.toolbar.structure'),\n can: editor => canGroup(editor, true) || canFlatten(editor, true),\n menu: structureItems,\n },\n insertKind('section', 'abschnitt', t('composites.slash.section'), 'i-lucide-layers'),\n ...kinds.filter(kind => kind.id !== 'section').map(kind => insertKind(kind.id, kind.id, kind.label, kind.icon)),\n { id: 'gliedern', slash: {}, label: t('composites.slash.group'), icon: 'i-lucide-layers', ability: ABILITY.composite, can: editor => canGroup(editor, false), run: editor => group(editor, false) },\n { id: 'gliedern-alle', slash: {}, label: t('composites.slash.groupAll'), icon: 'i-lucide-list-tree', ability: ABILITY.composite, can: editor => canGroup(editor, true), run: editor => group(editor, true) },\n { id: 'aufloesen', slash: {}, label: t('composites.slash.flatten'), icon: 'i-lucide-heading', ability: ABILITY.headings, can: editor => canFlatten(editor, false), run: editor => flatten(editor, false) },\n { id: 'aufloesen-alle', slash: {}, label: t('composites.slash.flattenAll'), icon: 'i-lucide-align-left', ability: ABILITY.headings, can: editor => canFlatten(editor, true), run: editor => flatten(editor, true) },\n { id: 'verweis', slash: {}, label: t('composites.reference.insert'), icon: 'i-lucide-link-2', ability: ABILITY.reference, run: (editor) => { editor.chain().focus().insertContent(REFERENCE_TRIGGER).run() } },\n ]\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/composites/feature.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { BlockAction, CommandDef, EditorFeature, FeatureContext, MenuItem, ToolbarGroupDef } from '../../core'\nimport { abilitiesAtSelection, downloadText, editorEntryOf, settingsTabsOf } from '../../core'\nimport type { Translate } from '../../i18n'\nimport { ABILITY, blockIdOf, findBlockById } from '../../core/schema'\nimport { AcceptedChildren, compositeInsertGuard } from './accepted-children'\nimport { type Basket, defaultBaskets } from './baskets'\nimport { bibOf, bibtexOf, cslOf } from './bibliography'\nimport { compositeConversions } from './convert'\nimport { bodyMarkdown, derivationOf } from './derivation'\nimport { blocksFromMarkdown } from './fences'\nimport { structureBlocks } from './heading-composites'\nimport { type CompositeKind, compositeKind, defaultCompositeKinds } from './kinds'\nimport { migrateLegacyContent } from './legacy'\nimport { compositeSchemaExtensions } from './schema'\nimport { documentCompositeMarkdown, markdownFileName } from './markdown-export'\nimport { type CompositeNodeViews, compositeNodes } from './node-views'\nimport { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeTitleNode, compositeAround, compositeKindsOf } from './nodes'\nimport { CompositeFocus } from './focus'\nimport { CompositeMerge } from './merge'\nimport { REFERENCE_TRIGGER } from './reference'\nimport { REFERENCE_AI_BLOCK } from './reference-ai'\nimport { referenceSuggestion } from './reference-suggestion'\nimport { compositeIdsOf, normalizeReferences } from './reference-text'\nimport { SourceReveal } from './reveal-source'\nimport { CompositeSplit, type SplitMode } from './split'\nimport { Structure, structureOf } from './structure'\nimport { STRUCTURE_MODE_KEYS } from './structure-mode'\n\n/** What a framework binding supplies to the composites feature. */\nexport interface CompositesUi<C> {\n /** The chips on each title line and the details popover on the kind icon; mounted as an overlay. */\n chrome: C\n /** The focus chip („Fokus: <Titel> · Aufheben“) shown while a Baustein is focused; mounted as an overlay. Absent: no chip (the focus mode itself works). */\n focusChip?: C\n /** The „Bearbeiten“ settings tab; receives `{ kinds }` as props. */\n settingsTab: C\n /** The composite block view of the framework. */\n nodeViews: CompositeNodeViews\n}\n\n/** Options of `compositeFeature`. */\nexport interface CompositeFeatureOptions {\n /** The composite kinds („Bausteine“) offered in the editor, with their own labels (default: `defaultCompositeKinds(t)`, the built-in kinds in the editor's language); read once. */\n kinds?: readonly CompositeKind[]\n /** The colour baskets a Baustein can be put into (default: `defaultBaskets(t)`, red/orange/yellow/green/blue in the editor's language; colours are the `--sk-basket-<id>` CSS variables); read once. */\n baskets?: readonly Basket[]\n}\n\n/** Heading level the structure stage starts at when it turns composites into headings (below the document title). */\nconst STRUCTURE_STAGE_LEVEL = 2\n\n/**\n * Composites („Bausteine“): the node family with its node views, the toolbar group (insert, „In Baustein umwandeln“,\n * „Gliederung umwandeln“), `/` commands, the conversion providers (wrap into / switch kind of / unwrap composites),\n * Markdown `:::` fences, legacy `section` migration, the preferred-structure setting and its `editing` settings tab,\n * the chips on each title line (status, tags) and the details popover on the kind icon (the binding's `chrome` overlay), focus mode on one\n * Baustein (`CompositeFocus`, the „Fokussieren“ block action and the binding's `focusChip` overlay), and\n * the AI view of kinds and structure, and the kinds' accepted children (`AcceptedChildren`: an edit that nests a Baustein\n * into one that does not accept its kind is refused with a notice). Contributes the `parseMarkdown`,\n * `structure` and `migrateContent` stages. Imports no AI, media or transcript code.\n */\nexport function compositeFeatureCore<C>(ui: CompositesUi<C>, options: CompositeFeatureOptions = {}): EditorFeature<C> {\n // Host kinds keep their labels; the built-in ones are produced from the context's translator (memoized per `t`).\n const kindsOf = (ctx: { t: Translate }) => options.kinds ?? defaultCompositeKinds(ctx.t)\n const basketsOf = (ctx: { t: Translate }) => options.baskets ?? defaultBaskets(ctx.t)\n const { Composite, CompositeTags, Reference } = compositeNodes(ui.nodeViews)\n return {\n id: 'composites',\n dimension: 'content',\n schemaExtensions: () => compositeSchemaExtensions({ ...(options.kinds && { kinds: options.kinds }), ...(options.baskets && { baskets: options.baskets }) }),\n extensions: ctx => [\n Composite.configure({ kinds: kindsOf(ctx), baskets: basketsOf(ctx) }),\n CompositeTitleNode,\n CompositeDescriptionNode,\n CompositeTags,\n Structure.configure({ mode: () => ctx.settings.get().blocks.structure }),\n AcceptedChildren.configure({ notify: ctx.notify, t: ctx.t }),\n SourceReveal,\n CompositeFocus,\n CompositeMerge,\n CompositeSplit.configure({ defaultKind: () => ctx.settings.get().blocks.defaultKind, targetChars: () => ctx.settings.get().blocks.splitTargetChars }),\n Reference.configure({ suggestion: referenceSuggestion(ctx.t) }),\n ],\n toolbarGroups: COMPOSITE_TOOLBAR_GROUPS,\n commands: ctx => compositeCommands(ctx, kindsOf(ctx)),\n insertGuards: () => [compositeInsertGuard],\n blockActions: ctx => [{\n id: 'document-export',\n label: ctx.t('composites.blockAction.export'),\n icon: 'i-lucide-download',\n ability: ABILITY.compositeExport,\n order: 400,\n isVisible: ({ node }) => node.attrs.kind === 'document',\n run: ({ editor, node }) => downloadText(markdownFileName(node), documentCompositeMarkdown(editor, node)),\n }, {\n id: 'bibliography-export',\n label: ctx.t('composites.blockAction.bibtex'),\n icon: 'i-lucide-book-marked',\n ability: ABILITY.compositeExport,\n order: 410,\n isVisible: ({ node }) => bibOf(node) !== null,\n run: ({ node }) => downloadText(`${markdownFileName(node).replace(/\\.md$/, '')}.bib`, bibtexOf(cslOf(node)!), 'text/x-bibtex;charset=utf-8'),\n }, {\n id: 'composite-focus',\n label: ctx.t('composites.focus.action'),\n icon: 'i-lucide-focus',\n order: 420,\n isVisible: ({ node }) => node.type.name === 'composite',\n run: ({ editor, node }) => {\n const id = blockIdOf(node)\n if (id) editor.commands.focusComposite(id)\n },\n }, ...splitBlockActions(ctx), {\n id: 'composite-merge-next',\n label: ctx.t('composites.merge.next'),\n icon: 'i-lucide-merge',\n ability: ABILITY.compositeMeta,\n order: 470,\n isVisible: ({ editor, pos }) => editor.can().mergeCompositeWithNext(pos),\n run: ({ editor, pos }) => void editor.chain().focus().mergeCompositeWithNext(pos).run(),\n }],\n overlays: [ui.chrome, ui.focusChip].filter(overlay => overlay !== undefined),\n settingsTabs: ctx => [{ id: 'editing', label: ctx.t('composites.tab'), icon: 'i-lucide-pencil', component: ui.settingsTab, props: { kinds: kindsOf(ctx) } }],\n blocks: {\n parseMarkdown: (editor, markdown) => blocksFromMarkdown(md => editor.markdown!.parse(md), markdown, compositeKindsOf(editor)),\n structure: (editor, blocks) => {\n const { schema } = editor\n return structureBlocks(schema, blocks.map(block => schema.nodeFromJSON(block)), structureOf(editor), STRUCTURE_STAGE_LEVEL, compositeKindsOf(editor)).map(node => node.toJSON())\n },\n migrateContent: migrateLegacyContent,\n normalize: (editor, blocks) => normalizeReferences(blocks, compositeIdsOf(editor.state.doc)),\n },\n conversions: compositeConversions(options.kinds),\n aiContext: editor => ({\n kinds: compositeKindsOf(editor).map(({ id, label, fields, ai }) => ({ id, label, fields, ...(ai?.purpose && { purpose: ai.purpose }) })),\n structure: structureOf(editor),\n blocks: [REFERENCE_AI_BLOCK],\n }),\n // A Baustein derived from another block hands the model that source block's Markdown.\n aiBlockData: ({ editor, node }) => {\n const from = derivationOf(node)?.from\n const source = from && 'block' in from ? findBlockById(editor.state.doc, from.block)?.node : undefined\n // i18n-ignore: model-facing data label (German prompt text, not UI)\n return source?.type.name === 'composite' ? [{ label: `Quelle: ${source.child(0).textContent.trim()}`, text: bodyMarkdown(editor, source) }] : []\n },\n }\n}\n\n/**\n * The four split actions of a Baustein: at the caret (as sibling or sub-Bausteine; offered on the Baustein around the\n * caret while the caret is past the first body block) and by length (as sub-Bausteine or siblings; offered while the\n * body falls into two parts or more). Each is hidden when the command refuses, so a kind that accepts no child kind\n * never shows the `children` variants.\n */\nfunction splitBlockActions({ t }: FeatureContext): BlockAction[] {\n const atCaret = (id: string, labelKey: 'composites.split.here' | 'composites.split.children', icon: string, order: number, mode: SplitMode): BlockAction => ({\n id,\n label: t(labelKey),\n icon,\n ability: ABILITY.compositeMeta,\n order,\n isVisible: ({ editor, pos }) => {\n const { $head } = editor.state.selection\n const found = compositeAround($head)\n return found?.pos === pos && $head.index(found.depth) > COMPOSITE_CHROME_COUNT && editor.can().splitCompositeAtCaret({ mode })\n },\n run: ({ editor }) => void editor.chain().focus().splitCompositeAtCaret({ mode }).run(),\n })\n const byLength = (id: string, labelKey: 'composites.split.lengthChildren' | 'composites.split.lengthSiblings', icon: string, order: number, mode: SplitMode): BlockAction => ({\n id,\n label: t(labelKey),\n icon,\n ability: ABILITY.compositeMeta,\n order,\n isVisible: ({ editor, pos }) => editor.can().splitCompositeByLength({ mode, pos }),\n run: ({ editor, pos }) => void editor.chain().focus().splitCompositeByLength({ mode, pos }).run(),\n })\n return [\n atCaret('composite-split-here', 'composites.split.here', 'i-lucide-scissors', 430, 'siblings'),\n atCaret('composite-split-children', 'composites.split.children', 'i-lucide-split', 440, 'children'),\n byLength('composite-split-length-children', 'composites.split.lengthChildren', 'i-lucide-ruler', 450, 'children'),\n byLength('composite-split-length-siblings', 'composites.split.lengthSiblings', 'i-lucide-ruler', 460, 'siblings'),\n ]\n}\n\nconst COMPOSITE_TOOLBAR_GROUPS: ToolbarGroupDef[] = [{ id: 'composites', order: 60, labelKey: 'palette.group.composites' }]\n\n/**\n * Converting headings to Bausteine and back: the checks and actions the toolbar's „Gliederung umwandeln“ menu and the\n * `/gliedern*` and `/aufloesen*` commands share, so both placements gate and act identically. They read the scope and\n * default kind from the settings at call time.\n */\nfunction structureActions({ settings }: FeatureContext) {\n const groupOptions = (recursive: boolean) => ({ recursive, scope: settings.get().editing.headingConversionScope, kind: settings.get().blocks.defaultKind })\n const flattenOptions = (recursive: boolean) => ({ recursive, scope: settings.get().editing.headingConversionScope })\n return {\n canGroup: (editor: Editor, recursive: boolean) => editor.can().convertHeadingsToComposites(groupOptions(recursive)),\n canFlatten: (editor: Editor, recursive: boolean) => editor.can().convertCompositesToHeadings(flattenOptions(recursive)),\n group: (editor: Editor, recursive: boolean) => void editor.chain().focus().convertHeadingsToComposites(groupOptions(recursive)).run(),\n flatten: (editor: Editor, recursive: boolean) => void editor.chain().focus().convertCompositesToHeadings(flattenOptions(recursive)).run(),\n }\n}\n\n/**\n * The commands of the composites feature, each declared once. Toolbar group beside the inserts: the default kind's\n * insert button (it follows the setting, so label/icon/shortcut/`creates` are getters read at render time), „In\n * Baustein umwandeln“ (one entry per kind for the caret's block) and „Gliederung umwandeln“ (headings <-> composites in\n * both directions, the preferred structure's direction first). `/` menu: one command per kind (`creates` that kind, so\n * the insert guard hides kinds the surrounding Baustein does not accept) and the four heading conversions.\n */\nfunction compositeCommands<C>(ctx: FeatureContext, kinds: readonly CompositeKind[]): CommandDef<C>[] {\n const { settings, t } = ctx\n const defaultKind = () => compositeKind(kinds, settings.get().blocks.defaultKind)\n const { canGroup, canFlatten, group, flatten } = structureActions(ctx)\n\n function kindItems(editor: Editor): MenuItem[] {\n return [\n { type: 'label', label: t('composites.menu.kindHeading') },\n ...compositeKindsOf(editor).map((kind): MenuItem => {\n const target = { type: 'composite', kind: kind.id } as const\n return { label: kind.label, icon: kind.icon, disabled: !editor.can().convertBlockTo(target), onSelect: () => editor.chain().focus().convertBlockTo(target).run() }\n }),\n ]\n }\n\n function structureItems(editor: Editor): MenuItem[] {\n const structure = settings.get().blocks.structure\n const abilities = abilitiesAtSelection(editor)\n const composite = abilities.has(ABILITY.composite)\n const headings = abilities.has(ABILITY.headings)\n const sep: MenuItem = { type: 'separator' }\n const toComposites: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toComposites') },\n { label: t('composites.menu.toComposites.top'), description: t('composites.menu.toComposites.top.description'), icon: 'i-lucide-layers', disabled: !composite || !canGroup(editor, false), onSelect: () => group(editor, false) },\n { label: t('composites.menu.toComposites.all'), description: t('composites.menu.toComposites.all.description'), icon: 'i-lucide-list-tree', disabled: !composite || !canGroup(editor, true), onSelect: () => group(editor, true) },\n ]\n const toHeadings: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toHeadings') },\n { label: t('composites.menu.toHeadings.top'), description: t('composites.menu.toHeadings.top.description'), icon: 'i-lucide-heading', disabled: !headings || !canFlatten(editor, false), onSelect: () => flatten(editor, false) },\n { label: t('composites.menu.toHeadings.all'), description: t('composites.menu.toHeadings.all.description'), icon: 'i-lucide-align-left', disabled: !headings || !canFlatten(editor, true), onSelect: () => flatten(editor, true) },\n ]\n const entry = editorEntryOf(editor)\n // The settings entry exists only while some feature contributes a tab to open.\n const settingsEntry: MenuItem[] = entry && settingsTabsOf(entry.preset, entry.ctx.app).length\n ? [sep, { label: t('composites.menu.settings'), icon: 'i-lucide-settings-2', onSelect: () => entry.ui.openSettings('editing') }]\n : []\n return [\n { type: 'label', label: t('composites.menu.preferred', { mode: t(STRUCTURE_MODE_KEYS[structure].labelKey) }) },\n ...(structure === 'composite' ? [...toComposites, sep, ...toHeadings] : [...toHeadings, sep, ...toComposites]),\n ...settingsEntry,\n ]\n }\n\n const insertKind = (kind: string, slashId: string, label: string, icon: string): CommandDef<C> => ({\n id: `composite.${kind}`,\n slash: { id: slashId },\n creates: { type: 'composite', attrs: { kind } },\n icon,\n label,\n ability: ABILITY.composite,\n run: (editor) => { editor.chain().focus().insertComposite(kind).run() },\n })\n\n return [\n {\n id: 'insert',\n toolbar: { group: 'composites', order: 10 },\n // Getters: the default kind arrives with the server settings; the toolbar reads them at render time.\n get icon() { return defaultKind().icon },\n get label() { return defaultKind().label },\n // Mod-Shift-a (CompositeNode) always inserts a `section`, so only then is it shown as the shortcut.\n get kbds() { return defaultKind().id === 'section' ? ['meta', 'shift', 'a'] : undefined },\n get creates() { return { type: 'composite', attrs: { kind: defaultKind().id } } },\n ability: ABILITY.composite,\n can: editor => editor.can().insertComposite(defaultKind().id),\n run: (editor) => { editor.chain().focus().insertComposite(defaultKind().id).run() },\n },\n {\n id: 'to-kind',\n toolbar: { group: 'composites', order: 20 },\n icon: 'i-lucide-replace',\n label: t('composites.toolbar.toKind'),\n ability: ABILITY.composite,\n can: editor => kindItems(editor).some(item => item.type !== 'label' && !item.disabled),\n menu: kindItems,\n },\n {\n id: 'structure',\n toolbar: { group: 'composites', order: 30 },\n icon: 'i-lucide-list-tree',\n label: t('composites.toolbar.structure'),\n can: editor => canGroup(editor, true) || canFlatten(editor, true),\n menu: structureItems,\n },\n insertKind('section', 'abschnitt', t('composites.slash.section'), 'i-lucide-layers'),\n ...kinds.filter(kind => kind.id !== 'section').map(kind => insertKind(kind.id, kind.id, kind.label, kind.icon)),\n { id: 'gliedern', slash: {}, label: t('composites.slash.group'), icon: 'i-lucide-layers', ability: ABILITY.composite, can: editor => canGroup(editor, false), run: editor => group(editor, false) },\n { id: 'gliedern-alle', slash: {}, label: t('composites.slash.groupAll'), icon: 'i-lucide-list-tree', ability: ABILITY.composite, can: editor => canGroup(editor, true), run: editor => group(editor, true) },\n { id: 'aufloesen', slash: {}, label: t('composites.slash.flatten'), icon: 'i-lucide-heading', ability: ABILITY.headings, can: editor => canFlatten(editor, false), run: editor => flatten(editor, false) },\n { id: 'aufloesen-alle', slash: {}, label: t('composites.slash.flattenAll'), icon: 'i-lucide-align-left', ability: ABILITY.headings, can: editor => canFlatten(editor, true), run: editor => flatten(editor, true) },\n { id: 'verweis', slash: {}, label: t('composites.reference.insert'), icon: 'i-lucide-link-2', ability: ABILITY.reference, run: (editor) => { editor.chain().focus().insertContent(REFERENCE_TRIGGER).run() } },\n ]\n}\n"],"mappings":"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"}
@@ -17,6 +17,7 @@ import { CompositeKindCount, CompositeRowsHandle, CompositeRowsState, createComp
17
17
  import { CompositeInspector, CompositeInspectorSection, CompositeInspectorState, CompositeKindOption, compositeFieldText, createCompositeInspector } from "./inspector-model.js";
18
18
  import { ReferenceTarget, referenceLabel, referenceTarget, referenceTitle } from "./reference-label.js";
19
19
  import { referenceSuggestion } from "./reference-suggestion.js";
20
+ import { CompositeMerge, mergeBody } from "./merge.js";
20
21
  import { CompositeSplit, CompositeSplitOptions, SplitMode, childKindFor, generatedTitle, splitBodyByLength, splitComposite } from "./split.js";
21
22
  import { Structure, StructureStorage, structureOf } from "./structure.js";
22
23
  import { STRUCTURE_MODE_KEYS } from "./structure-mode.js";
@@ -31,4 +32,4 @@ import { Derivation, DerivationMethod, DerivationSource, bodyMarkdown, derivatio
31
32
  import { LEGACY_COMPOSITE_NODE, migrateLegacyContent } from "./legacy.js";
32
33
  import { normalizeReferences, referencesFromText } from "./reference-text.js";
33
34
  import { compositeSchemaExtensions } from "./schema.js";
34
- export { AcceptedChildren, type AcceptedChildrenOptions, BASKET_IDS, BASKET_KEY, BIB_KEY, type Basket, COMPOSITE_CHROME_COUNT, CSL_TYPES, type CompositeAiBrief, type CompositeAnchor, type CompositeAnchorsHandle, type CompositeBacklink, CompositeDescriptionNode, type CompositeFeatureOptions, type CompositeFence, CompositeFocus, type CompositeFocusState, type CompositeFrame, type CompositeInspector, type CompositeInspectorSection, type CompositeInspectorState, type CompositeKind, type CompositeKindAi, type CompositeKindCount, type CompositeKindOption, type CompositeMention, type CompositeMetaField, CompositeNode, type CompositeNodeViews, type CompositeOptions, type CompositeReference, type CompositeRow, type CompositeRowsHandle, type CompositeRowsState, CompositeSplit, type CompositeSplitOptions, type CompositeStorage, CompositeTagsNode, CompositeTitleNode, type CompositesUi, type CslDate, type CslItem, type CslName, type CslType, DERIVATION_KEY, type Derivation, type DerivationMethod, type DerivationSource, type FenceSegment, LEGACY_COMPOSITE_NODE, type MoveVerdict, type OutlineNode, REFERENCE_NODE, type ReferenceAttrs, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey, type ReferenceTarget, SOURCE_MEDIA_TYPES, STRUCTURE_MODE_KEYS, type SourceLocator, SourceReveal, type SplitMode, Structure, type StructureStorage, TITLE_HIDDEN_KEY, TREE_ROOT_KEYS, basketById, basketOf, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, canMoveBlockInto, childKindFor, citeFull, citeShort, compositeAiBrief, compositeBacklinks, compositeBasketsOf, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFocusKey, compositeFocusOf, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, cslOf, cslTypeOptions, defaultBaskets, defaultCompositeKinds, derivationOf, derivationState, documentCompositeMarkdown, flattenCompositesToHeadings, focusDecorations, generatedTitle, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, migrateLegacyContent, moveBlockInto, moveIntoVerdict, normalizeReferences, observeCompositeAnchors, parseLocator, referenceLabel, referenceMarkdown, referenceSuggestion, referenceTarget, referenceTitle, referencesFromText, renditionsOf, revealSource, seekSource, setCompositeDescription, setCompositeMetaField, setCompositeTags, sourceOf, splitBodyByLength, splitComposite, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf, titleHiddenOf, yearOf };
35
+ export { AcceptedChildren, type AcceptedChildrenOptions, BASKET_IDS, BASKET_KEY, BIB_KEY, type Basket, COMPOSITE_CHROME_COUNT, CSL_TYPES, type CompositeAiBrief, type CompositeAnchor, type CompositeAnchorsHandle, type CompositeBacklink, CompositeDescriptionNode, type CompositeFeatureOptions, type CompositeFence, CompositeFocus, type CompositeFocusState, type CompositeFrame, type CompositeInspector, type CompositeInspectorSection, type CompositeInspectorState, type CompositeKind, type CompositeKindAi, type CompositeKindCount, type CompositeKindOption, type CompositeMention, CompositeMerge, type CompositeMetaField, CompositeNode, type CompositeNodeViews, type CompositeOptions, type CompositeReference, type CompositeRow, type CompositeRowsHandle, type CompositeRowsState, CompositeSplit, type CompositeSplitOptions, type CompositeStorage, CompositeTagsNode, CompositeTitleNode, type CompositesUi, type CslDate, type CslItem, type CslName, type CslType, DERIVATION_KEY, type Derivation, type DerivationMethod, type DerivationSource, type FenceSegment, LEGACY_COMPOSITE_NODE, type MoveVerdict, type OutlineNode, REFERENCE_NODE, type ReferenceAttrs, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey, type ReferenceTarget, SOURCE_MEDIA_TYPES, STRUCTURE_MODE_KEYS, type SourceLocator, SourceReveal, type SplitMode, Structure, type StructureStorage, TITLE_HIDDEN_KEY, TREE_ROOT_KEYS, basketById, basketOf, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, canMoveBlockInto, childKindFor, citeFull, citeShort, compositeAiBrief, compositeBacklinks, compositeBasketsOf, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFocusKey, compositeFocusOf, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, cslOf, cslTypeOptions, defaultBaskets, defaultCompositeKinds, derivationOf, derivationState, documentCompositeMarkdown, flattenCompositesToHeadings, focusDecorations, generatedTitle, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, mergeBody, migrateLegacyContent, moveBlockInto, moveIntoVerdict, normalizeReferences, observeCompositeAnchors, parseLocator, referenceLabel, referenceMarkdown, referenceSuggestion, referenceTarget, referenceTitle, referencesFromText, renditionsOf, revealSource, seekSource, setCompositeDescription, setCompositeMetaField, setCompositeTags, sourceOf, splitBodyByLength, splitComposite, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf, titleHiddenOf, yearOf };
@@ -18,6 +18,7 @@ import { AcceptedChildren } from "./accepted-children.js";
18
18
  import { documentCompositeMarkdown, headingsMarkdown, markdownFileName } from "./markdown-export.js";
19
19
  import { compositeNodes } from "./node-views.js";
20
20
  import { CompositeFocus, compositeFocusKey, compositeFocusOf, focusDecorations } from "./focus.js";
21
+ import { CompositeMerge, mergeBody } from "./merge.js";
21
22
  import { referenceLabel, referenceTarget, referenceTitle } from "./reference-label.js";
22
23
  import { compositeBacklinks, compositeDescriptionText, compositeMetaWith, compositeOfRow, compositeRowAt, compositeRows, setCompositeDescription, setCompositeMetaField, setCompositeTags } from "./rows.js";
23
24
  import { referenceSuggestion } from "./reference-suggestion.js";
@@ -31,4 +32,4 @@ import { createCompositeRows } from "./rows-model.js";
31
32
  import { TREE_ROOT_KEYS } from "./tree-root.js";
32
33
  import { compositeFieldText, createCompositeInspector } from "./inspector-model.js";
33
34
  import { canMoveBlockInto, compositeOutline, moveBlockInto, moveIntoVerdict } from "./outline.js";
34
- export { AcceptedChildren, BASKET_IDS, BASKET_KEY, BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, CompositeDescriptionNode, CompositeFocus, CompositeNode, CompositeSplit, CompositeTagsNode, CompositeTitleNode, DERIVATION_KEY, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, STRUCTURE_MODE_KEYS, SourceReveal, Structure, TITLE_HIDDEN_KEY, TREE_ROOT_KEYS, basketById, basketOf, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, canMoveBlockInto, childKindFor, citeFull, citeShort, compositeAiBrief, compositeBacklinks, compositeBasketsOf, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFocusKey, compositeFocusOf, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, cslOf, cslTypeOptions, defaultBaskets, defaultCompositeKinds, derivationOf, derivationState, documentCompositeMarkdown, flattenCompositesToHeadings, focusDecorations, generatedTitle, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, migrateLegacyContent, moveBlockInto, moveIntoVerdict, normalizeReferences, observeCompositeAnchors, parseLocator, referenceLabel, referenceMarkdown, referenceSuggestion, referenceTarget, referenceTitle, referencesFromText, renditionsOf, revealSource, seekSource, setCompositeDescription, setCompositeMetaField, setCompositeTags, sourceOf, splitBodyByLength, splitComposite, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf, titleHiddenOf, yearOf };
35
+ export { AcceptedChildren, BASKET_IDS, BASKET_KEY, BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, CompositeDescriptionNode, CompositeFocus, CompositeMerge, CompositeNode, CompositeSplit, CompositeTagsNode, CompositeTitleNode, DERIVATION_KEY, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, STRUCTURE_MODE_KEYS, SourceReveal, Structure, TITLE_HIDDEN_KEY, TREE_ROOT_KEYS, basketById, basketOf, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, canMoveBlockInto, childKindFor, citeFull, citeShort, compositeAiBrief, compositeBacklinks, compositeBasketsOf, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFocusKey, compositeFocusOf, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, cslOf, cslTypeOptions, defaultBaskets, defaultCompositeKinds, derivationOf, derivationState, documentCompositeMarkdown, flattenCompositesToHeadings, focusDecorations, generatedTitle, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, mergeBody, migrateLegacyContent, moveBlockInto, moveIntoVerdict, normalizeReferences, observeCompositeAnchors, parseLocator, referenceLabel, referenceMarkdown, referenceSuggestion, referenceTarget, referenceTitle, referencesFromText, renditionsOf, revealSource, seekSource, setCompositeDescription, setCompositeMetaField, setCompositeTags, sourceOf, splitBodyByLength, splitComposite, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf, titleHiddenOf, yearOf };
@@ -41,9 +41,18 @@ export interface CompositeKind {
41
41
  titlePlaceholder: string;
42
42
  descriptionPlaceholder: string;
43
43
  fields: CompositeMetaField[];
44
- /** How much of the chrome the kind shows. Absent: all of it. `tags: false` hides the tag row of this kind (the node stays in the schema, empty). */
44
+ /**
45
+ * How much of the chrome the kind shows. Absent: all of it. `tags: false` hides the tag row of this kind (the node stays in the schema, empty).
46
+ * `tone`: a CSS colour or `var(...)` that sets the kind apart: a Baustein of this kind gets `data-kind-tone` and `--sk-kind-tone` on its wrapper
47
+ * (a tinted surface and a left border in the tone) and its tree rows tint the kind icon with it. Absent: the kind looks as before.
48
+ * `controls: false` makes the chrome of a Baustein of this kind read-only although the editor is editable (for a kind whose attributes a host
49
+ * guard refuses to change): no basket menu, status menu, title-visibility toggle, tag editing or drag handle on the kind icon, and a read-only
50
+ * details popover; an existing basket, status and tags still show as chips. Default `true`.
51
+ */
45
52
  chrome?: {
46
53
  tags?: boolean;
54
+ tone?: string;
55
+ controls?: boolean;
47
56
  };
48
57
  /** Absent: the kind has no AI brief; „Baustein füllen (KI)“ is not offered for it. */
49
58
  ai?: CompositeKindAi;