@ecsplico/editor 3.5.1 → 3.6.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.
- package/CHANGELOG.md +6 -0
- package/dist/code/CodeSurface.vue.d.ts +3 -3
- package/dist/document/DocumentSurface.vue.d.ts +3 -3
- package/dist/features/composites/kinds.d.ts +6 -0
- package/dist/features/composites/kinds.js.map +1 -1
- package/dist/features/composites/merge.d.ts +4 -3
- package/dist/features/composites/merge.js +29 -3
- package/dist/features/composites/merge.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
- package/dist/server/handlers/ai.d.ts +2 -2
- package/dist/vue/AdvancedEditor.vue.d.ts +4 -4
- package/dist/vue/SimpleEditor.vue.d.ts +4 -4
- package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.6.0 - 2026-10-21
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `CompositeKind.nestedAfterContent?: boolean` (default `false`): the sub-Bausteine of a Baustein of that kind follow its own content, and `mergeCompositeWithNext` keeps that order. Merging A = `[Ca, Na]` and B = `[Cb, Nb]` (C the leading blocks of the body that are not Bausteine, N the rest from the first sub-Baustein on) gives `[Ca, Cb, Na, Nb]`; without the flag the result stays `[Ca, Na, Cb, Nb]`. Still one undo step, the empty-paragraph rule and the `accepts` check are unchanged.
|
|
8
|
+
|
|
3
9
|
## 3.5.1 - 2026-10-21
|
|
4
10
|
|
|
5
11
|
### Added
|
|
@@ -11,16 +11,16 @@ type __VLS_Props = {
|
|
|
11
11
|
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
|
-
ready: (view: EditorView) => any;
|
|
15
14
|
"update:modelValue": (text: string) => any;
|
|
15
|
+
ready: (view: EditorView) => any;
|
|
16
16
|
save: (text: string) => any;
|
|
17
17
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
18
|
-
onReady?: ((view: EditorView) => any) | undefined;
|
|
19
18
|
"onUpdate:modelValue"?: ((text: string) => any) | undefined;
|
|
19
|
+
onReady?: ((view: EditorView) => any) | undefined;
|
|
20
20
|
onSave?: ((text: string) => any) | undefined;
|
|
21
21
|
}>, {
|
|
22
|
-
editable: boolean;
|
|
23
22
|
modelValue: string;
|
|
23
|
+
editable: boolean;
|
|
24
24
|
wordWrap: boolean;
|
|
25
25
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
26
26
|
declare const _default: typeof __VLS_export;
|
|
@@ -32,16 +32,16 @@ type __VLS_Slots = {} & { [K in NonNullable<typeof __VLS_13>]?: (props: typeof _
|
|
|
32
32
|
binary?: (props: typeof __VLS_26) => any;
|
|
33
33
|
};
|
|
34
34
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
35
|
-
ready: (target: DocumentSurfaceTarget) => any;
|
|
36
35
|
"update:modelValue": (text: string) => any;
|
|
36
|
+
ready: (target: DocumentSurfaceTarget) => any;
|
|
37
37
|
save: (text: string) => any;
|
|
38
38
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
39
|
-
onReady?: ((target: DocumentSurfaceTarget) => any) | undefined;
|
|
40
39
|
"onUpdate:modelValue"?: ((text: string) => any) | undefined;
|
|
40
|
+
onReady?: ((target: DocumentSurfaceTarget) => any) | undefined;
|
|
41
41
|
onSave?: ((text: string) => any) | undefined;
|
|
42
42
|
}>, {
|
|
43
|
-
editable: boolean;
|
|
44
43
|
modelValue: string;
|
|
44
|
+
editable: boolean;
|
|
45
45
|
wordWrap: boolean;
|
|
46
46
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
47
47
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -62,6 +62,12 @@ export interface CompositeKind {
|
|
|
62
62
|
* Only new moves are checked; documents that already nest against it stay as they are.
|
|
63
63
|
*/
|
|
64
64
|
accepts?: readonly string[] | 'all';
|
|
65
|
+
/**
|
|
66
|
+
* Sub-Bausteine follow the Baustein's own content; a merge keeps that order. `mergeCompositeWithNext` merging A = [Ca, Na] and B = [Cb, Nb]
|
|
67
|
+
* (C the leading blocks of the body that are not Bausteine, N the rest from the first sub-Baustein on) gives [Ca, Cb, Na, Nb] instead
|
|
68
|
+
* of [Ca, Na, Cb, Nb]. Default `false`.
|
|
69
|
+
*/
|
|
70
|
+
nestedAfterContent?: boolean;
|
|
65
71
|
/** Present on source-holding kinds: the media block types the kind's source may be; `sourceOf` returns the first body child of one of these. */
|
|
66
72
|
source?: readonly (typeof SOURCE_MEDIA_TYPES)[number][];
|
|
67
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kinds.js","names":[],"sources":["../../../src/features/composites/kinds.ts"],"sourcesContent":["// Vue-free and server-importable: the kind registry of the composite block family („Bausteine“).\nimport { createTranslator, type Translate } from '../../i18n'\n\n/** Media block types a source-holding kind's source may be (`CompositeKind.source`). */\nexport const SOURCE_MEDIA_TYPES = ['image', 'audio', 'video', 'file'] as const\n\n/** One metadata field of a composite kind, stored under `key` in the composite's `meta` attribute. */\nexport interface CompositeMetaField {\n key: string\n label: string\n /**\n * `bibliography`: CSL-JSON item under `meta.bib`; `derivation`: read-only provenance of a derived Baustein; `reference`: block id of another Baustein;\n * `multiselect`: several of `options`, stored as `string[]` (the key is removed when none is chosen).\n */\n type: 'text' | 'textarea' | 'date' | 'number' | 'select' | 'multiselect' | 'reference' | 'bibliography' | 'derivation'\n /** Choices of a `select` or `multiselect` field (required for `multiselect`). */\n options?: { value: string, label: string }[]\n /** `reference`: kind ids the field may point to; absent = any Baustein. */\n targets?: readonly string[]\n}\n\n/**\n * What a kind tells the model beyond its fields. `purpose` goes into every AI request's block model (chat, generate\n * tasks); `instructions`, `instructionsField` and `skeleton` are read only by „Baustein füllen (KI)“ (`fillComposite`).\n */\nexport interface CompositeKindAi {\n /** One or two German sentences: what a Baustein of this kind is for and what its body holds. */\n purpose: string\n /** Default instruction for filling the body of a Baustein of this kind (what to write, structure, tone). */\n instructions?: string\n /** Key of a `textarea` field of this kind; a Baustein whose value is non-empty replaces `instructions` with it. */\n instructionsField?: string\n /** Target text (Vorlage) as Markdown; `{key}` placeholders are replaced by the Baustein's `meta[key]` before it goes to the model, unknown ones stay. */\n skeleton?: string\n}\n\n/** A composite kind: what its `kind` attribute selects (label, icon, chrome placeholders, meta fields). */\nexport interface CompositeKind {\n id: string\n label: string\n icon: string\n titlePlaceholder: string\n descriptionPlaceholder: string\n fields: CompositeMetaField[]\n /**\n * 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).\n * `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\n * (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.\n * `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\n * 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\n * details popover; an existing basket, status and tags still show as chips. Default `true`.\n */\n chrome?: { tags?: boolean, tone?: string, controls?: boolean }\n /** Absent: the kind has no AI brief; „Baustein füllen (KI)“ is not offered for it. */\n ai?: CompositeKindAi\n /**\n * Baustein kinds this kind accepts as nested Bausteine: a list of kind ids, or `'all'`. Absent: `folder` and `document`\n * accept `'all'`, every other kind accepts none. Non-Baustein content (paragraphs, lists, ...) is always allowed.\n * Only new moves are checked; documents that already nest against it stay as they are.\n */\n accepts?: readonly string[] | 'all'\n /** Present on source-holding kinds: the media block types the kind's source may be; `sourceOf` returns the first body child of one of these. */\n source?: readonly (typeof SOURCE_MEDIA_TYPES)[number][]\n}\n\n/**\n * The built-in kinds in the language of `t`. The default set is produced from the translator (labels, placeholders, field\n * labels and status choices are catalog messages), so it is built per translator and memoized; hosts that pass their own\n * kinds (`compositeFeature({ kinds })`, `Composite.configure({ kinds })`) keep their labels untouched. Ids, field keys and\n * stored values (`open`, `doing`, `done`) do not depend on the language.\n */\nexport function defaultCompositeKinds(t: Translate): readonly CompositeKind[] {\n let kinds = DEFAULT_KINDS.get(t)\n if (!kinds) DEFAULT_KINDS.set(t, kinds = buildDefaultKinds(t))\n return kinds\n}\n\nconst DEFAULT_KINDS = new WeakMap<Translate, readonly CompositeKind[]>()\n\nfunction buildDefaultKinds(t: Translate): readonly CompositeKind[] {\n return [\n { id: 'section', label: t('composites.kind.section.label'), icon: 'i-lucide-layers', titlePlaceholder: t('composites.kind.section.title'), descriptionPlaceholder: t('composites.kind.section.description'), fields: [], accepts: 'all' },\n { id: 'task', label: t('composites.kind.task.label'), icon: 'i-lucide-square-check', titlePlaceholder: t('composites.kind.task.title'), descriptionPlaceholder: t('composites.kind.task.description'), fields: [\n { key: 'status', label: t('composites.kind.task.field.status'), type: 'select', options: [\n { value: 'open', label: t('composites.kind.task.status.open') },\n { value: 'doing', label: t('composites.kind.task.status.doing') },\n { value: 'done', label: t('composites.kind.task.status.done') },\n ] },\n { key: 'due', label: t('composites.kind.task.field.due'), type: 'date' },\n { key: 'assignee', label: t('composites.kind.task.field.assignee'), type: 'text' },\n ] },\n // i18n-ignore: model-facing kind purpose (German prompt text, not UI)\n { id: 'note', label: t('composites.kind.note.label'), icon: 'i-lucide-sticky-note', titlePlaceholder: t('composites.kind.note.title'), descriptionPlaceholder: t('composites.kind.note.description'), fields: [], ai: { purpose: 'Eigene Notiz zu einer Quelle oder einem Thema: Zusammenfassung, Gedanken, offene Fragen.' } },\n { id: 'document', label: t('composites.kind.document.label'), icon: 'i-lucide-file-text', titlePlaceholder: t('composites.kind.document.title'), descriptionPlaceholder: t('composites.kind.document.description'), source: [...SOURCE_MEDIA_TYPES], fields: [\n { key: 'filename', label: t('composites.kind.document.field.filename'), type: 'text' },\n { key: 'mimeType', label: t('composites.kind.document.field.mimeType'), type: 'text' },\n { key: 'size', label: t('composites.kind.document.field.size'), type: 'number' },\n { key: 'importedAt', label: t('composites.kind.document.field.importedAt'), type: 'date' },\n ] },\n // i18n-ignore-start: model-facing kind purposes and instructions (German prompt text, not UI)\n { id: 'recording', label: t('composites.kind.recording.label'), icon: 'i-lucide-mic', titlePlaceholder: t('composites.kind.recording.title'), descriptionPlaceholder: t('composites.kind.recording.description'), accepts: 'all', source: ['audio', 'video'], fields: [\n ...importFields(t, 'recording'),\n { key: 'recordedAt', label: t('composites.kind.recording.field.recordedAt'), type: 'date' },\n { key: 'participants', label: t('composites.kind.recording.field.participants'), type: 'text' },\n { key: 'durationSeconds', label: t('composites.kind.recording.field.durationSeconds'), type: 'number' },\n ], ai: { purpose: 'Aufnahme (Audio oder Video) als Quelle; der Inhalt hält Lesefassungen wie das Transkript und eigene Notizen.' } },\n { id: 'paper', label: t('composites.kind.paper.label'), icon: 'i-lucide-scroll-text', titlePlaceholder: t('composites.kind.paper.title'), descriptionPlaceholder: t('composites.kind.paper.description'), accepts: 'all', source: ['file'], fields: [\n ...importFields(t, 'paper'),\n { key: 'bib', label: t('composites.kind.paper.field.bib'), type: 'bibliography' },\n { key: 'doi', label: t('composites.kind.paper.field.doi'), type: 'text' },\n ], ai: { purpose: 'Wissenschaftliche Arbeit als Quelle (PDF) mit Literaturangabe; der Inhalt hält Volltext, Zusammenfassungen und Notizen.' } },\n { id: 'book', label: t('composites.kind.book.label'), icon: 'i-lucide-book', titlePlaceholder: t('composites.kind.book.title'), descriptionPlaceholder: t('composites.kind.book.description'), accepts: 'all', source: ['file'], fields: [\n ...importFields(t, 'book'),\n { key: 'bib', label: t('composites.kind.book.field.bib'), type: 'bibliography' },\n { key: 'isbn', label: t('composites.kind.book.field.isbn'), type: 'text' },\n ], ai: { purpose: 'Buch als Quelle (PDF) mit Literaturangabe; der Inhalt hält den Volltext, gegliedert in Kapitel, und Notizen.' } },\n { id: 'figure', label: t('composites.kind.figure.label'), icon: 'i-lucide-image', titlePlaceholder: t('composites.kind.figure.title'), descriptionPlaceholder: t('composites.kind.figure.description'), accepts: 'all', source: ['image'], fields: [\n ...importFields(t, 'figure'),\n { key: 'credit', label: t('composites.kind.figure.field.credit'), type: 'text' },\n ], ai: { purpose: 'Bild als Quelle; der Inhalt hält die Bildbeschreibung und eigene Notizen.' } },\n { id: 'rendition', label: t('composites.kind.rendition.label'), icon: 'i-lucide-captions', titlePlaceholder: t('composites.kind.rendition.title'), descriptionPlaceholder: t('composites.kind.rendition.description'), accepts: 'all', fields: [\n { key: 'derivation', label: t('composites.kind.rendition.field.derivation'), type: 'derivation' },\n { key: 'language', label: t('composites.kind.rendition.field.language'), type: 'text' },\n ], ai: {\n purpose: 'Lesbare Fassung einer Quelle (Transkript, Volltext, Beschreibung, Übersetzung)',\n instructions: 'Übertrage den Inhalt vollständig und gut lesbar; nichts weglassen, nichts hinzuerfinden.',\n } },\n // i18n-ignore-end\n { id: 'folder', label: t('composites.kind.folder.label'), icon: 'i-lucide-folder', titlePlaceholder: t('composites.kind.folder.title'), descriptionPlaceholder: t('composites.kind.folder.description'), fields: [] },\n ]\n}\n\n/** The four fields the import of a file fills in (`wrapImport` of `composite-media`), shared by every source-holding kind. */\nfunction importFields(t: Translate, kind: 'recording' | 'paper' | 'book' | 'figure'): CompositeMetaField[] {\n return [\n { key: 'filename', label: t(`composites.kind.${kind}.field.filename`), type: 'text' },\n { key: 'mimeType', label: t(`composites.kind.${kind}.field.mimeType`), type: 'text' },\n { key: 'size', label: t(`composites.kind.${kind}.field.size`), type: 'number' },\n { key: 'importedAt', label: t(`composites.kind.${kind}.field.importedAt`), type: 'date' },\n ]\n}\n\n/** The built-in kinds in the default language, for server-side and context-free code (`Composite`'s default option, an editor without a context). */\nexport const fallbackCompositeKinds = (): readonly CompositeKind[] => defaultCompositeKinds(DEFAULT_TRANSLATE)\n\nconst DEFAULT_TRANSLATE = createTranslator()\n\n/** Kind `id` from `kinds`; an unknown id gets the `section` kind's presentation (else the first kind's) under its own id and label. */\nexport function compositeKind(kinds: readonly CompositeKind[], id: string): CompositeKind {\n const known = kinds.find(kind => kind.id === id)\n if (known) return known\n const base = kinds.find(kind => kind.id === 'section') ?? kinds[0] ?? fallbackCompositeKinds()[0]!\n return { ...base, id, label: id }\n}\n\n/** Kinds that accept every Baustein kind when their definition sets no `accepts`. */\nconst ACCEPTS_ALL_BY_DEFAULT: Record<string, true> = { folder: true, document: true }\n\n/**\n * Whether a Baustein of kind `parentKind` accepts one of kind `childKind` as nested Baustein. The `accepts` of the kind\n * in `kinds` decides; without one (or for a kind `kinds` does not list) only `folder` and `document` accept all.\n */\nexport function kindAccepts(kinds: readonly CompositeKind[], parentKind: string, childKind: string): boolean {\n const accepts = kinds.find(kind => kind.id === parentKind)?.accepts\n if (accepts === undefined) return Object.hasOwn(ACCEPTS_ALL_BY_DEFAULT, parentKind)\n return accepts === 'all' || accepts.includes(childKind)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kinds.js","names":[],"sources":["../../../src/features/composites/kinds.ts"],"sourcesContent":["// Vue-free and server-importable: the kind registry of the composite block family („Bausteine“).\nimport { createTranslator, type Translate } from '../../i18n'\n\n/** Media block types a source-holding kind's source may be (`CompositeKind.source`). */\nexport const SOURCE_MEDIA_TYPES = ['image', 'audio', 'video', 'file'] as const\n\n/** One metadata field of a composite kind, stored under `key` in the composite's `meta` attribute. */\nexport interface CompositeMetaField {\n key: string\n label: string\n /**\n * `bibliography`: CSL-JSON item under `meta.bib`; `derivation`: read-only provenance of a derived Baustein; `reference`: block id of another Baustein;\n * `multiselect`: several of `options`, stored as `string[]` (the key is removed when none is chosen).\n */\n type: 'text' | 'textarea' | 'date' | 'number' | 'select' | 'multiselect' | 'reference' | 'bibliography' | 'derivation'\n /** Choices of a `select` or `multiselect` field (required for `multiselect`). */\n options?: { value: string, label: string }[]\n /** `reference`: kind ids the field may point to; absent = any Baustein. */\n targets?: readonly string[]\n}\n\n/**\n * What a kind tells the model beyond its fields. `purpose` goes into every AI request's block model (chat, generate\n * tasks); `instructions`, `instructionsField` and `skeleton` are read only by „Baustein füllen (KI)“ (`fillComposite`).\n */\nexport interface CompositeKindAi {\n /** One or two German sentences: what a Baustein of this kind is for and what its body holds. */\n purpose: string\n /** Default instruction for filling the body of a Baustein of this kind (what to write, structure, tone). */\n instructions?: string\n /** Key of a `textarea` field of this kind; a Baustein whose value is non-empty replaces `instructions` with it. */\n instructionsField?: string\n /** Target text (Vorlage) as Markdown; `{key}` placeholders are replaced by the Baustein's `meta[key]` before it goes to the model, unknown ones stay. */\n skeleton?: string\n}\n\n/** A composite kind: what its `kind` attribute selects (label, icon, chrome placeholders, meta fields). */\nexport interface CompositeKind {\n id: string\n label: string\n icon: string\n titlePlaceholder: string\n descriptionPlaceholder: string\n fields: CompositeMetaField[]\n /**\n * 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).\n * `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\n * (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.\n * `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\n * 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\n * details popover; an existing basket, status and tags still show as chips. Default `true`.\n */\n chrome?: { tags?: boolean, tone?: string, controls?: boolean }\n /** Absent: the kind has no AI brief; „Baustein füllen (KI)“ is not offered for it. */\n ai?: CompositeKindAi\n /**\n * Baustein kinds this kind accepts as nested Bausteine: a list of kind ids, or `'all'`. Absent: `folder` and `document`\n * accept `'all'`, every other kind accepts none. Non-Baustein content (paragraphs, lists, ...) is always allowed.\n * Only new moves are checked; documents that already nest against it stay as they are.\n */\n accepts?: readonly string[] | 'all'\n /**\n * Sub-Bausteine follow the Baustein's own content; a merge keeps that order. `mergeCompositeWithNext` merging A = [Ca, Na] and B = [Cb, Nb]\n * (C the leading blocks of the body that are not Bausteine, N the rest from the first sub-Baustein on) gives [Ca, Cb, Na, Nb] instead\n * of [Ca, Na, Cb, Nb]. Default `false`.\n */\n nestedAfterContent?: boolean\n /** Present on source-holding kinds: the media block types the kind's source may be; `sourceOf` returns the first body child of one of these. */\n source?: readonly (typeof SOURCE_MEDIA_TYPES)[number][]\n}\n\n/**\n * The built-in kinds in the language of `t`. The default set is produced from the translator (labels, placeholders, field\n * labels and status choices are catalog messages), so it is built per translator and memoized; hosts that pass their own\n * kinds (`compositeFeature({ kinds })`, `Composite.configure({ kinds })`) keep their labels untouched. Ids, field keys and\n * stored values (`open`, `doing`, `done`) do not depend on the language.\n */\nexport function defaultCompositeKinds(t: Translate): readonly CompositeKind[] {\n let kinds = DEFAULT_KINDS.get(t)\n if (!kinds) DEFAULT_KINDS.set(t, kinds = buildDefaultKinds(t))\n return kinds\n}\n\nconst DEFAULT_KINDS = new WeakMap<Translate, readonly CompositeKind[]>()\n\nfunction buildDefaultKinds(t: Translate): readonly CompositeKind[] {\n return [\n { id: 'section', label: t('composites.kind.section.label'), icon: 'i-lucide-layers', titlePlaceholder: t('composites.kind.section.title'), descriptionPlaceholder: t('composites.kind.section.description'), fields: [], accepts: 'all' },\n { id: 'task', label: t('composites.kind.task.label'), icon: 'i-lucide-square-check', titlePlaceholder: t('composites.kind.task.title'), descriptionPlaceholder: t('composites.kind.task.description'), fields: [\n { key: 'status', label: t('composites.kind.task.field.status'), type: 'select', options: [\n { value: 'open', label: t('composites.kind.task.status.open') },\n { value: 'doing', label: t('composites.kind.task.status.doing') },\n { value: 'done', label: t('composites.kind.task.status.done') },\n ] },\n { key: 'due', label: t('composites.kind.task.field.due'), type: 'date' },\n { key: 'assignee', label: t('composites.kind.task.field.assignee'), type: 'text' },\n ] },\n // i18n-ignore: model-facing kind purpose (German prompt text, not UI)\n { id: 'note', label: t('composites.kind.note.label'), icon: 'i-lucide-sticky-note', titlePlaceholder: t('composites.kind.note.title'), descriptionPlaceholder: t('composites.kind.note.description'), fields: [], ai: { purpose: 'Eigene Notiz zu einer Quelle oder einem Thema: Zusammenfassung, Gedanken, offene Fragen.' } },\n { id: 'document', label: t('composites.kind.document.label'), icon: 'i-lucide-file-text', titlePlaceholder: t('composites.kind.document.title'), descriptionPlaceholder: t('composites.kind.document.description'), source: [...SOURCE_MEDIA_TYPES], fields: [\n { key: 'filename', label: t('composites.kind.document.field.filename'), type: 'text' },\n { key: 'mimeType', label: t('composites.kind.document.field.mimeType'), type: 'text' },\n { key: 'size', label: t('composites.kind.document.field.size'), type: 'number' },\n { key: 'importedAt', label: t('composites.kind.document.field.importedAt'), type: 'date' },\n ] },\n // i18n-ignore-start: model-facing kind purposes and instructions (German prompt text, not UI)\n { id: 'recording', label: t('composites.kind.recording.label'), icon: 'i-lucide-mic', titlePlaceholder: t('composites.kind.recording.title'), descriptionPlaceholder: t('composites.kind.recording.description'), accepts: 'all', source: ['audio', 'video'], fields: [\n ...importFields(t, 'recording'),\n { key: 'recordedAt', label: t('composites.kind.recording.field.recordedAt'), type: 'date' },\n { key: 'participants', label: t('composites.kind.recording.field.participants'), type: 'text' },\n { key: 'durationSeconds', label: t('composites.kind.recording.field.durationSeconds'), type: 'number' },\n ], ai: { purpose: 'Aufnahme (Audio oder Video) als Quelle; der Inhalt hält Lesefassungen wie das Transkript und eigene Notizen.' } },\n { id: 'paper', label: t('composites.kind.paper.label'), icon: 'i-lucide-scroll-text', titlePlaceholder: t('composites.kind.paper.title'), descriptionPlaceholder: t('composites.kind.paper.description'), accepts: 'all', source: ['file'], fields: [\n ...importFields(t, 'paper'),\n { key: 'bib', label: t('composites.kind.paper.field.bib'), type: 'bibliography' },\n { key: 'doi', label: t('composites.kind.paper.field.doi'), type: 'text' },\n ], ai: { purpose: 'Wissenschaftliche Arbeit als Quelle (PDF) mit Literaturangabe; der Inhalt hält Volltext, Zusammenfassungen und Notizen.' } },\n { id: 'book', label: t('composites.kind.book.label'), icon: 'i-lucide-book', titlePlaceholder: t('composites.kind.book.title'), descriptionPlaceholder: t('composites.kind.book.description'), accepts: 'all', source: ['file'], fields: [\n ...importFields(t, 'book'),\n { key: 'bib', label: t('composites.kind.book.field.bib'), type: 'bibliography' },\n { key: 'isbn', label: t('composites.kind.book.field.isbn'), type: 'text' },\n ], ai: { purpose: 'Buch als Quelle (PDF) mit Literaturangabe; der Inhalt hält den Volltext, gegliedert in Kapitel, und Notizen.' } },\n { id: 'figure', label: t('composites.kind.figure.label'), icon: 'i-lucide-image', titlePlaceholder: t('composites.kind.figure.title'), descriptionPlaceholder: t('composites.kind.figure.description'), accepts: 'all', source: ['image'], fields: [\n ...importFields(t, 'figure'),\n { key: 'credit', label: t('composites.kind.figure.field.credit'), type: 'text' },\n ], ai: { purpose: 'Bild als Quelle; der Inhalt hält die Bildbeschreibung und eigene Notizen.' } },\n { id: 'rendition', label: t('composites.kind.rendition.label'), icon: 'i-lucide-captions', titlePlaceholder: t('composites.kind.rendition.title'), descriptionPlaceholder: t('composites.kind.rendition.description'), accepts: 'all', fields: [\n { key: 'derivation', label: t('composites.kind.rendition.field.derivation'), type: 'derivation' },\n { key: 'language', label: t('composites.kind.rendition.field.language'), type: 'text' },\n ], ai: {\n purpose: 'Lesbare Fassung einer Quelle (Transkript, Volltext, Beschreibung, Übersetzung)',\n instructions: 'Übertrage den Inhalt vollständig und gut lesbar; nichts weglassen, nichts hinzuerfinden.',\n } },\n // i18n-ignore-end\n { id: 'folder', label: t('composites.kind.folder.label'), icon: 'i-lucide-folder', titlePlaceholder: t('composites.kind.folder.title'), descriptionPlaceholder: t('composites.kind.folder.description'), fields: [] },\n ]\n}\n\n/** The four fields the import of a file fills in (`wrapImport` of `composite-media`), shared by every source-holding kind. */\nfunction importFields(t: Translate, kind: 'recording' | 'paper' | 'book' | 'figure'): CompositeMetaField[] {\n return [\n { key: 'filename', label: t(`composites.kind.${kind}.field.filename`), type: 'text' },\n { key: 'mimeType', label: t(`composites.kind.${kind}.field.mimeType`), type: 'text' },\n { key: 'size', label: t(`composites.kind.${kind}.field.size`), type: 'number' },\n { key: 'importedAt', label: t(`composites.kind.${kind}.field.importedAt`), type: 'date' },\n ]\n}\n\n/** The built-in kinds in the default language, for server-side and context-free code (`Composite`'s default option, an editor without a context). */\nexport const fallbackCompositeKinds = (): readonly CompositeKind[] => defaultCompositeKinds(DEFAULT_TRANSLATE)\n\nconst DEFAULT_TRANSLATE = createTranslator()\n\n/** Kind `id` from `kinds`; an unknown id gets the `section` kind's presentation (else the first kind's) under its own id and label. */\nexport function compositeKind(kinds: readonly CompositeKind[], id: string): CompositeKind {\n const known = kinds.find(kind => kind.id === id)\n if (known) return known\n const base = kinds.find(kind => kind.id === 'section') ?? kinds[0] ?? fallbackCompositeKinds()[0]!\n return { ...base, id, label: id }\n}\n\n/** Kinds that accept every Baustein kind when their definition sets no `accepts`. */\nconst ACCEPTS_ALL_BY_DEFAULT: Record<string, true> = { folder: true, document: true }\n\n/**\n * Whether a Baustein of kind `parentKind` accepts one of kind `childKind` as nested Baustein. The `accepts` of the kind\n * in `kinds` decides; without one (or for a kind `kinds` does not list) only `folder` and `document` accept all.\n */\nexport function kindAccepts(kinds: readonly CompositeKind[], parentKind: string, childKind: string): boolean {\n const accepts = kinds.find(kind => kind.id === parentKind)?.accepts\n if (accepts === undefined) return Object.hasOwn(ACCEPTS_ALL_BY_DEFAULT, parentKind)\n return accepts === 'all' || accepts.includes(childKind)\n}\n"],"mappings":"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"}
|
|
@@ -3,16 +3,17 @@ import { Extension } from "@tiptap/core";
|
|
|
3
3
|
import { Fragment, Node as Node$1 } from "@tiptap/pm/model";
|
|
4
4
|
//#region src/features/composites/merge.d.ts
|
|
5
5
|
/**
|
|
6
|
-
* What a merge appends to the
|
|
7
|
-
*
|
|
6
|
+
* What a merge appends to the first Baustein's body: the whole body of `next`, its own sub-Bausteine included, in document
|
|
7
|
+
* order. A body that is one empty paragraph (a Baustein nothing was written in) adds nothing.
|
|
8
8
|
* Null when `first`'s kind does not accept the kind of a Baustein nested in that body (the merge is refused).
|
|
9
|
+
* Where it goes is the command's call: at the end, or, for a kind with `nestedAfterContent`, split by `splitAtSubComposites`.
|
|
9
10
|
*/
|
|
10
11
|
export declare function mergeBody(kinds: readonly CompositeKind[], first: Node$1, next: Node$1): Fragment | null;
|
|
11
12
|
declare module '@tiptap/core' {
|
|
12
13
|
interface Commands<ReturnType> {
|
|
13
14
|
compositeMerge: {
|
|
14
15
|
/**
|
|
15
|
-
* The Baustein at `pos` (default: the caret's innermost one) absorbs the Baustein that directly follows it in the same parent: that one's body, with its sub-Bausteine, is appended to the end of this one's body and the following Baustein is gone. Title, description, tags, id, kind and meta stay those of the first. One transaction. Refused when no Baustein follows, when the first kind does not accept a Baustein nested in the following one, when either Baustein has a kind with `chrome.controls === false` (host-managed), or when the editor is not editable.
|
|
16
|
+
* The Baustein at `pos` (default: the caret's innermost one) absorbs the Baustein that directly follows it in the same parent: that one's body, with its sub-Bausteine, is appended to the end of this one's body and the following Baustein is gone. For a kind with `nestedAfterContent` the following body's own content (the leading blocks that are not Bausteine) goes in right before the first one's first sub-Baustein and only its sub-Bausteine go to the end, so the content stays ahead of the sub-Bausteine. Title, description, tags, id, kind and meta stay those of the first. One transaction. Refused when no Baustein follows, when the first kind does not accept a Baustein nested in the following one, when either Baustein has a kind with `chrome.controls === false` (host-managed), or when the editor is not editable.
|
|
16
17
|
*/
|
|
17
18
|
mergeCompositeWithNext: (pos?: number) => ReturnType;
|
|
18
19
|
};
|
|
@@ -5,9 +5,10 @@ import { Extension } from "@tiptap/core";
|
|
|
5
5
|
import { Fragment } from "@tiptap/pm/model";
|
|
6
6
|
//#region src/features/composites/merge.ts
|
|
7
7
|
/**
|
|
8
|
-
* What a merge appends to the
|
|
9
|
-
*
|
|
8
|
+
* What a merge appends to the first Baustein's body: the whole body of `next`, its own sub-Bausteine included, in document
|
|
9
|
+
* order. A body that is one empty paragraph (a Baustein nothing was written in) adds nothing.
|
|
10
10
|
* Null when `first`'s kind does not accept the kind of a Baustein nested in that body (the merge is refused).
|
|
11
|
+
* Where it goes is the command's call: at the end, or, for a kind with `nestedAfterContent`, split by `splitAtSubComposites`.
|
|
11
12
|
*/
|
|
12
13
|
function mergeBody(kinds, first, next) {
|
|
13
14
|
let chrome = 0;
|
|
@@ -18,6 +19,20 @@ function mergeBody(kinds, first, next) {
|
|
|
18
19
|
const only = body.childCount === 1 ? body.firstChild : null;
|
|
19
20
|
return only?.type.name === "paragraph" && only.content.size === 0 ? Fragment.empty : body;
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Splits a merge body (see `mergeBody`) at its first sub-Baustein: `content` is the leading run of blocks that are not
|
|
24
|
+
* Bausteine, `nested` the rest from the first sub-Baustein on (empty when there is none).
|
|
25
|
+
*/
|
|
26
|
+
function splitAtSubComposites(body) {
|
|
27
|
+
let at = 0;
|
|
28
|
+
while (at < body.childCount && body.child(at).type.name !== "composite") at++;
|
|
29
|
+
let size = 0;
|
|
30
|
+
for (let i = 0; i < at; i++) size += body.child(i).nodeSize;
|
|
31
|
+
return {
|
|
32
|
+
content: body.cut(0, size),
|
|
33
|
+
nested: body.cut(size)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
21
36
|
/** Client-only, no schema: the merge command of Bausteine. */
|
|
22
37
|
const CompositeMerge = Extension.create({
|
|
23
38
|
name: "compositeMerge",
|
|
@@ -36,7 +51,18 @@ const CompositeMerge = Extension.create({
|
|
|
36
51
|
if (!appended) return false;
|
|
37
52
|
if (dispatch) {
|
|
38
53
|
const nextPos = found.pos + found.node.nodeSize;
|
|
39
|
-
|
|
54
|
+
const end = nextPos - 1;
|
|
55
|
+
if (compositeKind(kinds, String(found.node.attrs.kind)).nestedAfterContent && appended.size > 0) {
|
|
56
|
+
const { content, nested } = splitAtSubComposites(appended);
|
|
57
|
+
let subPos = found.pos + 1;
|
|
58
|
+
for (let i = 0; i < found.node.childCount; i++) {
|
|
59
|
+
const child = found.node.child(i);
|
|
60
|
+
if (i >= 3 && child.type.name === "composite") break;
|
|
61
|
+
subPos += child.nodeSize;
|
|
62
|
+
}
|
|
63
|
+
tr.insert(end, nested);
|
|
64
|
+
tr.insert(subPos, content);
|
|
65
|
+
} else tr.insert(end, appended);
|
|
40
66
|
const shifted = nextPos + appended.size;
|
|
41
67
|
tr.delete(shifted, shifted + next.nodeSize);
|
|
42
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","names":[],"sources":["../../../src/features/composites/merge.ts"],"sourcesContent":["// Merging a Baustein with its next sibling: the counterpart of the split. The pure part (`mergeBody`) knows nothing about\n// the editor; the `CompositeMerge` extension wraps it into the command `mergeCompositeWithNext`.\nimport { Extension } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport { outermostComposites } from './accepted-children'\nimport { type CompositeKind, compositeKind, kindAccepts } from './kinds'\nimport { COMPOSITE_CHROME_COUNT, compositeAt, compositeKindsOf } from './nodes'\n\n/**\n * What a merge appends to the
|
|
1
|
+
{"version":3,"file":"merge.js","names":[],"sources":["../../../src/features/composites/merge.ts"],"sourcesContent":["// Merging a Baustein with its next sibling: the counterpart of the split. The pure part (`mergeBody`) knows nothing about\n// the editor; the `CompositeMerge` extension wraps it into the command `mergeCompositeWithNext`.\nimport { Extension } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport { outermostComposites } from './accepted-children'\nimport { type CompositeKind, compositeKind, kindAccepts } from './kinds'\nimport { COMPOSITE_CHROME_COUNT, compositeAt, compositeKindsOf } from './nodes'\n\n/**\n * What a merge appends to the first Baustein's body: the whole body of `next`, its own sub-Bausteine included, in document\n * order. A body that is one empty paragraph (a Baustein nothing was written in) adds nothing.\n * Null when `first`'s kind does not accept the kind of a Baustein nested in that body (the merge is refused).\n * Where it goes is the command's call: at the end, or, for a kind with `nestedAfterContent`, split by `splitAtSubComposites`.\n */\nexport function mergeBody(kinds: readonly CompositeKind[], first: PMNode, next: PMNode): Fragment | null {\n let chrome = 0\n for (let i = 0; i < COMPOSITE_CHROME_COUNT; i++) chrome += next.child(i).nodeSize\n const body = next.content.cut(chrome)\n const firstKind = String(first.attrs.kind)\n for (let i = 0; i < body.childCount; i++) {\n for (const child of outermostComposites(body.child(i))) {\n if (!kindAccepts(kinds, firstKind, String(child.attrs.kind))) return null\n }\n }\n const only = body.childCount === 1 ? body.firstChild! : null\n return only?.type.name === 'paragraph' && only.content.size === 0 ? Fragment.empty : body\n}\n\n/**\n * Splits a merge body (see `mergeBody`) at its first sub-Baustein: `content` is the leading run of blocks that are not\n * Bausteine, `nested` the rest from the first sub-Baustein on (empty when there is none).\n */\nfunction splitAtSubComposites(body: Fragment): { content: Fragment, nested: Fragment } {\n let at = 0\n while (at < body.childCount && body.child(at).type.name !== 'composite') at++\n let size = 0\n for (let i = 0; i < at; i++) size += body.child(i).nodeSize\n return { content: body.cut(0, size), nested: body.cut(size) }\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n compositeMerge: {\n /**\n * The Baustein at `pos` (default: the caret's innermost one) absorbs the Baustein that directly follows it in the same parent: that one's body, with its sub-Bausteine, is appended to the end of this one's body and the following Baustein is gone. For a kind with `nestedAfterContent` the following body's own content (the leading blocks that are not Bausteine) goes in right before the first one's first sub-Baustein and only its sub-Bausteine go to the end, so the content stays ahead of the sub-Bausteine. Title, description, tags, id, kind and meta stay those of the first. One transaction. Refused when no Baustein follows, when the first kind does not accept a Baustein nested in the following one, when either Baustein has a kind with `chrome.controls === false` (host-managed), or when the editor is not editable.\n */\n mergeCompositeWithNext: (pos?: number) => ReturnType\n }\n }\n}\n\n/** Client-only, no schema: the merge command of Bausteine. */\nexport const CompositeMerge = Extension.create({\n name: 'compositeMerge',\n addCommands() {\n return {\n mergeCompositeWithNext: pos => ({ state, tr, dispatch }) => {\n if (!this.editor.isEditable) return false\n const found = compositeAt(state, pos)\n if (!found) return false\n const $pos = state.doc.resolve(found.pos)\n const next = $pos.parent.maybeChild($pos.index() + 1)\n if (next?.type.name !== 'composite') return false\n const kinds = compositeKindsOf(this.editor)\n // A kind with `chrome.controls === false` is host-managed: neither absorbing nor being absorbed is the editor's call.\n const hostManaged = (node: PMNode) => compositeKind(kinds, String(node.attrs.kind)).chrome?.controls === false\n if (hostManaged(found.node) || hostManaged(next)) return false\n const appended = mergeBody(kinds, found.node, next)\n if (!appended) return false\n if (dispatch) {\n const nextPos = found.pos + found.node.nodeSize\n const end = nextPos - 1\n // `nestedAfterContent`: the content of the second body goes ahead of the first one's sub-Bausteine, the sub-Bausteine of the second one to the end.\n if (compositeKind(kinds, String(found.node.attrs.kind)).nestedAfterContent && appended.size > 0) {\n const { content, nested } = splitAtSubComposites(appended)\n let subPos = found.pos + 1\n for (let i = 0; i < found.node.childCount; i++) {\n const child = found.node.child(i)\n if (i >= COMPOSITE_CHROME_COUNT && child.type.name === 'composite') break\n subPos += child.nodeSize\n }\n // Back to front, so no position moves under the next insert.\n tr.insert(end, nested)\n tr.insert(subPos, content)\n }\n else {\n // The body goes in at the end of the first Baustein, then the second one is cut out behind it.\n tr.insert(end, appended)\n }\n const shifted = nextPos + appended.size\n tr.delete(shifted, shifted + next.nodeSize)\n }\n return true\n },\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;AAcA,SAAgB,UAAU,OAAiC,OAAe,MAA+B;CACvG,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAA,GAA4B,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC;CACzE,MAAM,OAAO,KAAK,QAAQ,IAAI,MAAM;CACpC,MAAM,YAAY,OAAO,MAAM,MAAM,IAAI;CACzC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,YAAY,KACnC,KAAK,MAAM,SAAS,oBAAoB,KAAK,MAAM,CAAC,CAAC,GACnD,IAAI,CAAC,YAAY,OAAO,WAAW,OAAO,MAAM,MAAM,IAAI,CAAC,GAAG,OAAO;CAGzE,MAAM,OAAO,KAAK,eAAe,IAAI,KAAK,aAAc;CACxD,OAAO,MAAM,KAAK,SAAS,eAAe,KAAK,QAAQ,SAAS,IAAI,SAAS,QAAQ;AACvF;;;;;AAMA,SAAS,qBAAqB,MAAyD;CACrF,IAAI,KAAK;CACT,OAAO,KAAK,KAAK,cAAc,KAAK,MAAM,EAAE,CAAC,CAAC,KAAK,SAAS,aAAa;CACzE,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC;CACnD,OAAO;EAAE,SAAS,KAAK,IAAI,GAAG,IAAI;EAAG,QAAQ,KAAK,IAAI,IAAI;CAAE;AAC9D;;AAcA,MAAa,iBAAiB,UAAU,OAAO;CAC7C,MAAM;CACN,cAAc;EACZ,OAAO,EACL,yBAAwB,SAAQ,EAAE,OAAO,IAAI,eAAe;GAC1D,IAAI,CAAC,KAAK,OAAO,YAAY,OAAO;GACpC,MAAM,QAAQ,YAAY,OAAO,GAAG;GACpC,IAAI,CAAC,OAAO,OAAO;GACnB,MAAM,OAAO,MAAM,IAAI,QAAQ,MAAM,GAAG;GACxC,MAAM,OAAO,KAAK,OAAO,WAAW,KAAK,MAAM,IAAI,CAAC;GACpD,IAAI,MAAM,KAAK,SAAS,aAAa,OAAO;GAC5C,MAAM,QAAQ,iBAAiB,KAAK,MAAM;GAE1C,MAAM,eAAe,SAAiB,cAAc,OAAO,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,QAAQ,aAAa;GACzG,IAAI,YAAY,MAAM,IAAI,KAAK,YAAY,IAAI,GAAG,OAAO;GACzD,MAAM,WAAW,UAAU,OAAO,MAAM,MAAM,IAAI;GAClD,IAAI,CAAC,UAAU,OAAO;GACtB,IAAI,UAAU;IACZ,MAAM,UAAU,MAAM,MAAM,MAAM,KAAK;IACvC,MAAM,MAAM,UAAU;IAEtB,IAAI,cAAc,OAAO,OAAO,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,sBAAsB,SAAS,OAAO,GAAG;KAC/F,MAAM,EAAE,SAAS,WAAW,qBAAqB,QAAQ;KACzD,IAAI,SAAS,MAAM,MAAM;KACzB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK,YAAY,KAAK;MAC9C,MAAM,QAAQ,MAAM,KAAK,MAAM,CAAC;MAChC,IAAI,KAAA,KAA+B,MAAM,KAAK,SAAS,aAAa;MACpE,UAAU,MAAM;KAClB;KAEA,GAAG,OAAO,KAAK,MAAM;KACrB,GAAG,OAAO,QAAQ,OAAO;IAC3B,OAGE,GAAG,OAAO,KAAK,QAAQ;IAEzB,MAAM,UAAU,UAAU,SAAS;IACnC,GAAG,OAAO,SAAS,UAAU,KAAK,QAAQ;GAC5C;GACA,OAAO;EACT,EACF;CACF;AACF,CAAC"}
|
|
@@ -41,29 +41,29 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
41
41
|
settingsOpen: import("vue").WritableComputedRef<boolean, boolean>;
|
|
42
42
|
settingsTab: import("vue").WritableComputedRef<string | undefined, string | undefined>;
|
|
43
43
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
44
|
+
settingsOpen: (tab?: string | undefined) => any;
|
|
44
45
|
"update:sidebarOpen": (value: boolean) => any;
|
|
45
46
|
"update:commentsOpen": (value: boolean) => any;
|
|
46
|
-
ready: (editor: Editor) => any;
|
|
47
47
|
"update:modelValue": (markdown: string) => any;
|
|
48
|
+
frontmatter: (frontmatter: string | null) => any;
|
|
49
|
+
ready: (editor: Editor) => any;
|
|
48
50
|
metadataCreate: (list: string, item: MetadataItem) => any;
|
|
49
51
|
contentError: (error: Error) => any;
|
|
50
|
-
settingsOpen: (tab?: string | undefined) => any;
|
|
51
|
-
frontmatter: (frontmatter: string | null) => any;
|
|
52
52
|
diagnostics: (diagnostics: MarkdownDiagnostic[]) => any;
|
|
53
53
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
54
|
+
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
54
55
|
"onUpdate:sidebarOpen"?: ((value: boolean) => any) | undefined;
|
|
55
56
|
"onUpdate:commentsOpen"?: ((value: boolean) => any) | undefined;
|
|
56
|
-
onReady?: ((editor: Editor) => any) | undefined;
|
|
57
57
|
"onUpdate:modelValue"?: ((markdown: string) => any) | undefined;
|
|
58
|
+
onFrontmatter?: ((frontmatter: string | null) => any) | undefined;
|
|
59
|
+
onReady?: ((editor: Editor) => any) | undefined;
|
|
58
60
|
onMetadataCreate?: ((list: string, item: MetadataItem) => any) | undefined;
|
|
59
61
|
onContentError?: ((error: Error) => any) | undefined;
|
|
60
|
-
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
61
|
-
onFrontmatter?: ((frontmatter: string | null) => any) | undefined;
|
|
62
62
|
onDiagnostics?: ((diagnostics: MarkdownDiagnostic[]) => any) | undefined;
|
|
63
63
|
}>, {
|
|
64
|
+
modelValue: string;
|
|
64
65
|
editable: boolean;
|
|
65
66
|
settingsUi: "internal" | "external";
|
|
66
|
-
modelValue: string;
|
|
67
67
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
68
68
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
69
69
|
declare const _default: typeof __VLS_export;
|
|
@@ -11,9 +11,9 @@ export declare const chatBodySchema: z.ZodObject<{
|
|
|
11
11
|
feedback: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
12
12
|
op: z.ZodString;
|
|
13
13
|
type: z.ZodEnum<{
|
|
14
|
-
add: "add";
|
|
15
|
-
delete: "delete";
|
|
16
14
|
update: "update";
|
|
15
|
+
delete: "delete";
|
|
16
|
+
add: "add";
|
|
17
17
|
convert: "convert";
|
|
18
18
|
}>;
|
|
19
19
|
target: z.ZodNullable<z.ZodString>;
|
|
@@ -71,21 +71,21 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
71
71
|
editor: import("vue").ComputedRef<Editor | undefined>;
|
|
72
72
|
preset: ComposedEditor<Component>;
|
|
73
73
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
74
|
+
settingsOpen: (tab?: string | undefined) => any;
|
|
74
75
|
"update:sidebarOpen": (value: boolean) => any;
|
|
75
76
|
"update:commentsOpen": (value: boolean) => any;
|
|
76
|
-
ready: (editor: Editor) => any;
|
|
77
77
|
"update:modelValue": (content: JSONContent) => any;
|
|
78
|
+
ready: (editor: Editor) => any;
|
|
78
79
|
metadataCreate: (list: string, item: MetadataItem) => any;
|
|
79
80
|
contentError: (error: Error) => any;
|
|
80
|
-
settingsOpen: (tab?: string | undefined) => any;
|
|
81
81
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
82
|
+
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
82
83
|
"onUpdate:sidebarOpen"?: ((value: boolean) => any) | undefined;
|
|
83
84
|
"onUpdate:commentsOpen"?: ((value: boolean) => any) | undefined;
|
|
84
|
-
onReady?: ((editor: Editor) => any) | undefined;
|
|
85
85
|
"onUpdate:modelValue"?: ((content: JSONContent) => any) | undefined;
|
|
86
|
+
onReady?: ((editor: Editor) => any) | undefined;
|
|
86
87
|
onMetadataCreate?: ((list: string, item: MetadataItem) => any) | undefined;
|
|
87
88
|
onContentError?: ((error: Error) => any) | undefined;
|
|
88
|
-
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
89
89
|
}>, {
|
|
90
90
|
content: ContentLevel | readonly FeatureId[];
|
|
91
91
|
ai: boolean;
|
|
@@ -41,21 +41,21 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
41
41
|
editor: import("vue").ComputedRef<Editor | undefined>;
|
|
42
42
|
preset: EditorPreset<Component>;
|
|
43
43
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
44
|
+
settingsOpen: (tab?: string | undefined) => any;
|
|
44
45
|
"update:sidebarOpen": (value: boolean) => any;
|
|
45
46
|
"update:commentsOpen": (value: boolean) => any;
|
|
46
|
-
ready: (editor: Editor) => any;
|
|
47
47
|
"update:modelValue": (content: JSONContent) => any;
|
|
48
|
+
ready: (editor: Editor) => any;
|
|
48
49
|
metadataCreate: (list: string, item: MetadataItem) => any;
|
|
49
50
|
contentError: (error: Error) => any;
|
|
50
|
-
settingsOpen: (tab?: string | undefined) => any;
|
|
51
51
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
52
|
+
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
52
53
|
"onUpdate:sidebarOpen"?: ((value: boolean) => any) | undefined;
|
|
53
54
|
"onUpdate:commentsOpen"?: ((value: boolean) => any) | undefined;
|
|
54
|
-
onReady?: ((editor: Editor) => any) | undefined;
|
|
55
55
|
"onUpdate:modelValue"?: ((content: JSONContent) => any) | undefined;
|
|
56
|
+
onReady?: ((editor: Editor) => any) | undefined;
|
|
56
57
|
onMetadataCreate?: ((list: string, item: MetadataItem) => any) | undefined;
|
|
57
58
|
onContentError?: ((error: Error) => any) | undefined;
|
|
58
|
-
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
59
59
|
}>, {
|
|
60
60
|
editable: boolean;
|
|
61
61
|
settingsUi: "internal" | "external";
|
|
@@ -43,21 +43,21 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
43
43
|
settingsOpen: import("vue").Ref<boolean, boolean>;
|
|
44
44
|
settingsTab: import("vue").Ref<string | undefined, string | undefined>;
|
|
45
45
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
46
|
+
settingsOpen: (tab?: string | undefined) => any;
|
|
46
47
|
"update:sidebarOpen": (value: boolean) => any;
|
|
47
48
|
"update:commentsOpen": (value: boolean) => any;
|
|
48
|
-
ready: (editor: Editor) => any;
|
|
49
49
|
"update:modelValue": (content: JSONContent) => any;
|
|
50
|
+
ready: (editor: Editor) => any;
|
|
50
51
|
metadataCreate: (list: string, item: MetadataItem) => any;
|
|
51
52
|
contentError: (error: Error) => any;
|
|
52
|
-
settingsOpen: (tab?: string | undefined) => any;
|
|
53
53
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
54
|
+
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
54
55
|
"onUpdate:sidebarOpen"?: ((value: boolean) => any) | undefined;
|
|
55
56
|
"onUpdate:commentsOpen"?: ((value: boolean) => any) | undefined;
|
|
56
|
-
onReady?: ((editor: Editor) => any) | undefined;
|
|
57
57
|
"onUpdate:modelValue"?: ((content: JSONContent) => any) | undefined;
|
|
58
|
+
onReady?: ((editor: Editor) => any) | undefined;
|
|
58
59
|
onMetadataCreate?: ((list: string, item: MetadataItem) => any) | undefined;
|
|
59
60
|
onContentError?: ((error: Error) => any) | undefined;
|
|
60
|
-
onSettingsOpen?: ((tab?: string | undefined) => any) | undefined;
|
|
61
61
|
}>, {
|
|
62
62
|
editable: boolean;
|
|
63
63
|
settingsUi: "internal" | "external";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecsplico/editor",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vue and React editor library on TipTap v3 (Vue: Nuxt UI; React: shadcn/ui): framework-free features with Vue and React bindings, simple and advanced presets, tree-shakeable entries. Built ESM with type declarations.",
|
|
6
6
|
"license": "MIT",
|