@openpresentation/opf-editor 0.11.3 → 0.14.2
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/README.md +82 -58
- package/dist/annotations.d.ts +16 -16
- package/dist/annotations.js +71 -79
- package/dist/assets.d.ts +7 -7
- package/dist/assets.js +15 -15
- package/dist/background-options.d.ts +2 -2
- package/dist/background-options.js +6 -6
- package/dist/block-controls.js +7 -7
- package/dist/block-convert.d.ts +7 -7
- package/dist/block-convert.js +23 -21
- package/dist/blocks.d.ts +8 -8
- package/dist/blocks.js +41 -40
- package/dist/canvas-fields.js +35 -12
- package/dist/canvas.d.ts +22 -30
- package/dist/canvas.js +57 -64
- package/dist/chart-data.d.ts +12 -10
- package/dist/chart-data.js +22 -21
- package/dist/chart-options-panel.d.ts +2 -2
- package/dist/chart-options-panel.js +82 -8
- package/dist/chart-options.d.ts +35 -9
- package/dist/chart-options.js +133 -40
- package/dist/checks.js +21 -0
- package/dist/color-authoring.js +1 -1
- package/dist/content-actions.d.ts +15 -15
- package/dist/content-actions.js +71 -70
- package/dist/content-controls.js +12 -12
- package/dist/data-grid.js +179 -10
- package/dist/data.d.ts +23 -2
- package/dist/data.js +40 -1
- package/dist/dataset-refs.d.ts +17 -0
- package/dist/dataset-refs.js +45 -0
- package/dist/design-controls.js +66 -47
- package/dist/design-options.d.ts +16 -14
- package/dist/design-options.js +86 -74
- package/dist/edit-helpers.js +8 -7
- package/dist/exact-source.js +5 -5
- package/dist/export.d.ts +5 -7
- package/dist/export.js +40 -14
- package/dist/find-panel.js +5 -5
- package/dist/find-replace.d.ts +3 -3
- package/dist/find-replace.js +35 -20
- package/dist/font-gate.js +49 -58
- package/dist/galleries.js +36 -52
- package/dist/grid-model.d.ts +99 -24
- package/dist/grid-model.js +577 -101
- package/dist/image-crop.d.ts +4 -4
- package/dist/image-crop.js +20 -20
- package/dist/image-cropper.js +3 -3
- package/dist/index.d.ts +28 -28
- package/dist/index.js +74 -90
- package/dist/json-options.js +17 -16
- package/dist/layout-handles.js +5 -5
- package/dist/layout-placeholders.js +4 -4
- package/dist/layout.d.ts +2 -2
- package/dist/layout.js +8 -7
- package/dist/numbering-panel.js +3 -5
- package/dist/numbering.d.ts +3 -5
- package/dist/numbering.js +14 -26
- package/dist/outline-view.js +24 -24
- package/dist/outline.d.ts +12 -12
- package/dist/outline.js +52 -50
- package/dist/persistence.d.ts +1 -1
- package/dist/persistence.js +19 -18
- package/dist/presentation-ids.js +2 -2
- package/dist/react.js +3 -3
- package/dist/review-panel.d.ts +30 -13
- package/dist/review-panel.js +154 -53
- package/dist/review.d.ts +36 -43
- package/dist/review.js +92 -53
- package/dist/rich-text-input.js +4 -3
- package/dist/rich-text-toolbar.js +5 -3
- package/dist/rich-text.js +5 -2
- package/dist/schema-inspector.d.ts +2 -2
- package/dist/schema-inspector.js +16 -11
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +25 -5
- package/dist/slide-manager.d.ts +2 -2
- package/dist/slide-manager.js +18 -18
- package/dist/slides.d.ts +20 -20
- package/dist/slides.js +99 -97
- package/dist/svelte.js +1 -1
- package/dist/switches.d.ts +10 -10
- package/dist/switches.js +136 -109
- package/dist/table-options.d.ts +8 -8
- package/dist/table-options.js +41 -30
- package/dist/table-structure.d.ts +10 -10
- package/dist/table-structure.js +21 -21
- package/dist/template-panel.d.ts +3 -3
- package/dist/template-panel.js +37 -13
- package/dist/templates.d.ts +22 -11
- package/dist/templates.js +48 -55
- package/dist/transfer.d.ts +4 -4
- package/dist/transfer.js +74 -54
- package/package.json +10 -6
- package/dist/font-defaults.js +0 -25
package/dist/annotations.js
CHANGED
|
@@ -6,15 +6,16 @@
|
|
|
6
6
|
// canvas redraws and Undo restores the document. Nothing here invents text or ids: a reference is
|
|
7
7
|
// what the caller supplies, and removing a cited reference refuses unless `force` also removes its
|
|
8
8
|
// cites. Numbering comes from core (`collectCitations`), so the panel shows what the engines draw.
|
|
9
|
-
import { getValueAtPath, opfPathToJsonPointer, splitOpfPath
|
|
9
|
+
import { getValueAtPath, opfPathToJsonPointer, splitOpfPath } from "./index.js";
|
|
10
10
|
import { checkedDocument, fail } from "./edit-helpers.js";
|
|
11
|
-
|
|
12
|
-
import
|
|
11
|
+
import { captionSettings, collectCitations, referencesSlide, walkCitationRuns } from "@openpresentation/opf/composition";
|
|
12
|
+
import { checkFormat } from "./checks.js";
|
|
13
13
|
|
|
14
14
|
export const CAPTION_POSITIONS = Object.freeze(["below", "above"]);
|
|
15
15
|
export const CAPTION_ALIGNMENTS = Object.freeze(["left", "center", "right"]);
|
|
16
16
|
export const CAPTIONABLE_FIELDS = Object.freeze(["image", "chart", "table", "video"]);
|
|
17
|
-
|
|
17
|
+
// Fields whose runs can carry a marker: the slide heading group (FA-10) plus text, quote text, bullets and items.
|
|
18
|
+
const TEXT_FIELDS = ["title", "subtitle", "tag", "text", "bullets", "items"];
|
|
18
19
|
|
|
19
20
|
const isObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
20
21
|
const clone = (value) => structuredClone(value);
|
|
@@ -24,29 +25,29 @@ function checkEditor(editor) {
|
|
|
24
25
|
if (!editor || typeof editor.applyPatch !== "function" || typeof editor.subscribe !== "function") throw fail("invalid-editor", "Expected an editor session created by createEditorSession.");
|
|
25
26
|
}
|
|
26
27
|
function commit(editor, prepared, meta = {}) {
|
|
27
|
-
const {
|
|
28
|
-
void
|
|
29
|
-
if (!prepared.changed) return { ...summary,
|
|
28
|
+
const { presentation, patches, ...summary } = prepared;
|
|
29
|
+
void presentation;
|
|
30
|
+
if (!prepared.changed) return { ...summary, presentation: editor.presentation, patches: [], inversePatches: [], validation: editor.validation };
|
|
30
31
|
const change = editor.applyPatch(patches, { ...meta, source: meta.source ?? "annotation", action: prepared.action, path: prepared.path });
|
|
31
32
|
return { ...change, ...summary };
|
|
32
33
|
}
|
|
33
34
|
// One guarded replace of the container at `parts`; the candidate must validate when the document did.
|
|
34
|
-
function transaction(
|
|
35
|
-
const current = getValueAtPath(
|
|
35
|
+
function transaction(presentation, parts, next, extra) {
|
|
36
|
+
const current = getValueAtPath(presentation, parts);
|
|
36
37
|
const pointer = opfPathToJsonPointer(parts);
|
|
37
38
|
const changed = JSON.stringify(current) !== JSON.stringify(next);
|
|
38
39
|
const patches = changed ? [{ op: "test", path: pointer, value: clone(current) }, { op: "replace", path: pointer, value: clone(next) }] : [];
|
|
39
|
-
const before =
|
|
40
|
-
const result = changed ? checkedDocument(
|
|
41
|
-
return { ...extra, path: parts.join("."),
|
|
40
|
+
const before = checkFormat(presentation);
|
|
41
|
+
const result = changed ? checkedDocument(presentation, patches, before) : presentation;
|
|
42
|
+
return { ...extra, path: parts.join("."), presentation: clone(result), patches, changed };
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
// --- captions -----------------------------------------------------------------------------------
|
|
45
46
|
|
|
46
|
-
function captionHost(
|
|
47
|
+
function captionHost(presentation, blockPath) {
|
|
47
48
|
let parts;
|
|
48
49
|
try { parts = splitOpfPath(blockPath); } catch { throw fail("invalid-path", `Invalid block path ${JSON.stringify(blockPath)}.`); }
|
|
49
|
-
const host = getValueAtPath(
|
|
50
|
+
const host = getValueAtPath(presentation, parts);
|
|
50
51
|
if (!isObject(host)) throw fail("invalid-path", `No block at ${parts.join(".")}.`);
|
|
51
52
|
if (Array.isArray(host.blocks)) throw fail("caption-unsupported", "A group cannot carry a caption; choose one of its blocks.", { path: parts.join(".") });
|
|
52
53
|
const fields = CAPTIONABLE_FIELDS.filter((field) => host[field] !== undefined);
|
|
@@ -56,15 +57,11 @@ function captionHost(document, blockPath) {
|
|
|
56
57
|
|
|
57
58
|
/** Normalize a caption value to `{ text, position, align }`, or undefined. */
|
|
58
59
|
export function normalizeCaption(value) {
|
|
59
|
-
|
|
60
|
-
if (value === undefined || value === null) return undefined;
|
|
61
|
-
if (typeof value === "string" || Array.isArray(value)) return { text: value, position: "below", align: "left" };
|
|
62
|
-
if (!isObject(value) || value.text === undefined) return undefined;
|
|
63
|
-
return { text: value.text, position: value.position === "above" ? "above" : "below", align: CAPTION_ALIGNMENTS.includes(value.align) ? value.align : "left" };
|
|
60
|
+
return captionSettings(value);
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
/** Every block (and one-payload slide root) that can carry a caption, with its current caption. */
|
|
67
|
-
export function captionTargets(
|
|
64
|
+
export function captionTargets(presentation) {
|
|
68
65
|
const targets = [];
|
|
69
66
|
const visit = (host, path) => {
|
|
70
67
|
if (!isObject(host)) return;
|
|
@@ -72,7 +69,7 @@ export function captionTargets(document) {
|
|
|
72
69
|
const fields = CAPTIONABLE_FIELDS.filter((field) => host[field] !== undefined);
|
|
73
70
|
if (fields.length === 1) targets.push({ blockPath: path, field: fields[0], caption: normalizeCaption(host.caption) });
|
|
74
71
|
};
|
|
75
|
-
(
|
|
72
|
+
(presentation?.slides ?? []).forEach((slide, index) => {
|
|
76
73
|
if (!isObject(slide)) return;
|
|
77
74
|
const regions = Object.keys(slide).filter((key) => /^(top|middle|bottom|left|center|right)([+:]|$)/.test(key) && isObject(slide[key])).sort();
|
|
78
75
|
if (regions.length) for (const key of regions) visit(slide[key], `slides.${index}.${key}`);
|
|
@@ -82,8 +79,8 @@ export function captionTargets(document) {
|
|
|
82
79
|
}
|
|
83
80
|
|
|
84
81
|
/** The caption of the block at `blockPath` (`{ field, caption }`; `caption` undefined when none). */
|
|
85
|
-
export function readCaption(
|
|
86
|
-
const { host, field } = captionHost(
|
|
82
|
+
export function readCaption(presentation, blockPath) {
|
|
83
|
+
const { host, field } = captionHost(presentation, blockPath);
|
|
87
84
|
return { blockPath: splitOpfPath(blockPath).join("."), field, caption: normalizeCaption(host.caption) };
|
|
88
85
|
}
|
|
89
86
|
|
|
@@ -91,8 +88,8 @@ export function readCaption(document, blockPath) {
|
|
|
91
88
|
* Set (a string, TextRun[] or `{ text, position?, align? }`) or remove (`null`) the caption of the
|
|
92
89
|
* block at `blockPath`. A caption at the default position and alignment is stored in its short form.
|
|
93
90
|
*/
|
|
94
|
-
export function prepareCaption(
|
|
95
|
-
const { parts, host, field } = captionHost(
|
|
91
|
+
export function prepareCaption(presentation, blockPath, caption) {
|
|
92
|
+
const { parts, host, field } = captionHost(presentation, blockPath);
|
|
96
93
|
const next = clone(host);
|
|
97
94
|
if (caption === null || caption === undefined) delete next.caption;
|
|
98
95
|
else {
|
|
@@ -102,21 +99,17 @@ export function prepareCaption(document, blockPath, caption) {
|
|
|
102
99
|
throw fail("invalid-caption", "A caption is a string, TextRun[] or { text, position: below|above, align: left|center|right }.");
|
|
103
100
|
next.caption = settings.position === "below" && settings.align === "left" ? clone(settings.text) : { text: clone(settings.text), position: settings.position, align: settings.align };
|
|
104
101
|
}
|
|
105
|
-
return transaction(
|
|
102
|
+
return transaction(presentation, parts, next, { action: "caption", field });
|
|
106
103
|
}
|
|
107
104
|
export function setCaption(editor, blockPath, caption, meta = {}) {
|
|
108
105
|
checkEditor(editor);
|
|
109
|
-
return commit(editor, prepareCaption(editor.
|
|
106
|
+
return commit(editor, prepareCaption(editor.presentation, blockPath, caption), meta);
|
|
110
107
|
}
|
|
111
108
|
|
|
112
109
|
// --- references ---------------------------------------------------------------------------------
|
|
113
110
|
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
return opfCore.collectCitations(document);
|
|
117
|
-
}
|
|
118
|
-
function referenceList(document) {
|
|
119
|
-
return Array.isArray(document?.references) ? document.references : [];
|
|
111
|
+
function referenceList(presentation) {
|
|
112
|
+
return Array.isArray(presentation?.references) ? presentation.references : [];
|
|
120
113
|
}
|
|
121
114
|
function checkReference(reference, existing, { allowExisting = false } = {}) {
|
|
122
115
|
if (!isObject(reference) || typeof reference.id !== "string" || !reference.id) throw fail("invalid-reference", "A reference needs a non-empty string id.");
|
|
@@ -129,46 +122,46 @@ function checkReference(reference, existing, { allowExisting = false } = {}) {
|
|
|
129
122
|
}
|
|
130
123
|
|
|
131
124
|
/** The deck's references with their marker numbers and whether a run cites them. */
|
|
132
|
-
export function listReferences(
|
|
133
|
-
const list = referenceList(
|
|
134
|
-
const citations =
|
|
125
|
+
export function listReferences(presentation) {
|
|
126
|
+
const list = referenceList(presentation);
|
|
127
|
+
const citations = collectCitations(presentation);
|
|
135
128
|
return list.map((reference, index) => {
|
|
136
|
-
const note = citations
|
|
129
|
+
const note = citations.references.find((item) => item.id === reference?.id);
|
|
137
130
|
return { index, id: reference?.id, text: reference?.text, url: reference?.url, cited: Boolean(note), ...(note ? { number: note.number } : {}) };
|
|
138
131
|
});
|
|
139
132
|
}
|
|
140
133
|
/** Append a reference `{ id, text, url? }`; ids must be unique. */
|
|
141
|
-
export function prepareReference(
|
|
142
|
-
const list = referenceList(
|
|
134
|
+
export function prepareReference(presentation, reference) {
|
|
135
|
+
const list = referenceList(presentation);
|
|
143
136
|
const next = [...clone(list), checkReference(reference, list)];
|
|
144
|
-
return transaction(
|
|
137
|
+
return transaction(presentation, ["references"], next, { action: "add-reference", id: reference.id });
|
|
145
138
|
}
|
|
146
139
|
export function addReference(editor, reference, meta = {}) {
|
|
147
140
|
checkEditor(editor);
|
|
148
|
-
return commit(editor, prepareReference(editor.
|
|
141
|
+
return commit(editor, prepareReference(editor.presentation, reference), meta);
|
|
149
142
|
}
|
|
150
143
|
/** Change the text and/or url of the reference `id` (`url: null` removes the url); the id itself does not change. */
|
|
151
|
-
export function prepareReferenceUpdate(
|
|
152
|
-
const list = referenceList(
|
|
144
|
+
export function prepareReferenceUpdate(presentation, id, fields) {
|
|
145
|
+
const list = referenceList(presentation), index = list.findIndex((item) => item?.id === id);
|
|
153
146
|
if (index < 0) throw fail("unknown-reference", `No reference '${id}'.`, { id });
|
|
154
147
|
const merged = { ...list[index], ...(fields?.text !== undefined ? { text: fields.text } : {}), ...(fields?.url !== undefined ? { url: fields.url } : {}) };
|
|
155
148
|
if (fields?.url === null) delete merged.url;
|
|
156
149
|
const next = clone(list);
|
|
157
150
|
next[index] = checkReference(merged, list, { allowExisting: true });
|
|
158
|
-
return transaction(
|
|
151
|
+
return transaction(presentation, ["references"], next, { action: "update-reference", id });
|
|
159
152
|
}
|
|
160
153
|
export function updateReference(editor, id, fields, meta = {}) {
|
|
161
154
|
checkEditor(editor);
|
|
162
|
-
return commit(editor, prepareReferenceUpdate(editor.
|
|
155
|
+
return commit(editor, prepareReferenceUpdate(editor.presentation, id, fields), meta);
|
|
163
156
|
}
|
|
164
157
|
/** Remove the reference `id`. Refuses while a run cites it unless `force`, which also removes those cites. */
|
|
165
|
-
export function prepareReferenceRemoval(
|
|
166
|
-
const list = referenceList(
|
|
158
|
+
export function prepareReferenceRemoval(presentation, id, { force = false } = {}) {
|
|
159
|
+
const list = referenceList(presentation), index = list.findIndex((item) => item?.id === id);
|
|
167
160
|
if (index < 0) throw fail("unknown-reference", `No reference '${id}'.`, { id });
|
|
168
161
|
const citing = [];
|
|
169
|
-
|
|
162
|
+
(presentation.slides ?? []).forEach((slide, slideIndex) => walkCitationRuns(slide, `slides.${slideIndex}`, (entry) => { if (entry.cite.includes(id)) citing.push(entry.path); }));
|
|
170
163
|
if (citing.length && !force) throw fail("reference-cited", `Reference '${id}' is cited by ${citing.length} run${citing.length === 1 ? "" : "s"}; pass force to remove the citations too.`, { id, runs: citing });
|
|
171
|
-
const next = clone(
|
|
164
|
+
const next = clone(presentation);
|
|
172
165
|
next.references = list.filter((_, position) => position !== index);
|
|
173
166
|
if (!next.references.length) delete next.references;
|
|
174
167
|
for (const runPath of citing) {
|
|
@@ -177,15 +170,15 @@ export function prepareReferenceRemoval(document, id, { force = false } = {}) {
|
|
|
177
170
|
runs[runIndex] = withoutCite(run, id);
|
|
178
171
|
}
|
|
179
172
|
const pointer = "";
|
|
180
|
-
const changed = JSON.stringify(
|
|
181
|
-
const patches = changed ? [{ op: "test", path: pointer, value: clone(
|
|
182
|
-
const before =
|
|
183
|
-
const result = changed ? checkedDocument(
|
|
184
|
-
return { action: "remove-reference", id, removedCites: citing, path: "references",
|
|
173
|
+
const changed = JSON.stringify(presentation) !== JSON.stringify(next);
|
|
174
|
+
const patches = changed ? [{ op: "test", path: pointer, value: clone(presentation) }, { op: "replace", path: pointer, value: clone(next) }] : [];
|
|
175
|
+
const before = checkFormat(presentation);
|
|
176
|
+
const result = changed ? checkedDocument(presentation, patches, before) : presentation;
|
|
177
|
+
return { action: "remove-reference", id, removedCites: citing, path: "references", presentation: clone(result), patches, changed };
|
|
185
178
|
}
|
|
186
179
|
export function removeReference(editor, id, options = {}, meta = {}) {
|
|
187
180
|
checkEditor(editor);
|
|
188
|
-
return commit(editor, prepareReferenceRemoval(editor.
|
|
181
|
+
return commit(editor, prepareReferenceRemoval(editor.presentation, id, options), meta);
|
|
189
182
|
}
|
|
190
183
|
|
|
191
184
|
// --- citations and footnotes --------------------------------------------------------------------
|
|
@@ -199,56 +192,56 @@ function withoutCite(run, id) {
|
|
|
199
192
|
const simplifyRun = (run) => Object.keys(run).length === 1 && typeof run.text === "string" ? run.text : run;
|
|
200
193
|
|
|
201
194
|
/** The run at `runPath` (`slides.0.text.2`, `slides.0.blocks.1.items.0.text.1`): its run array path, index and value. */
|
|
202
|
-
export function runAt(
|
|
195
|
+
export function runAt(presentation, runPath) {
|
|
203
196
|
let parts;
|
|
204
197
|
try { parts = splitOpfPath(runPath); } catch { throw fail("invalid-path", `Invalid run path ${JSON.stringify(runPath)}.`); }
|
|
205
198
|
if (parts.length < 3 || !/^(0|[1-9]\d*)$/.test(parts[parts.length - 1])) throw fail("invalid-path", `${parts.join(".")} is not a run path.`);
|
|
206
199
|
const arrayParts = parts.slice(0, -1), index = Number(parts[parts.length - 1]);
|
|
207
|
-
const runs = getValueAtPath(
|
|
200
|
+
const runs = getValueAtPath(presentation, arrayParts);
|
|
208
201
|
const field = [...arrayParts].reverse().find((segment) => TEXT_FIELDS.includes(segment));
|
|
209
|
-
if (!Array.isArray(runs) || !field || !(index in runs)) throw fail("invalid-path", `${parts.join(".")} is not a run of a text, bullets or items
|
|
202
|
+
if (!Array.isArray(runs) || !field || !(index in runs)) throw fail("invalid-path", `${parts.join(".")} is not a run of a title, subtitle, tag, text, bullets or items field.`);
|
|
210
203
|
const run = runs[index];
|
|
211
204
|
if (typeof run !== "string" && !(isObject(run) && typeof run.text === "string")) throw fail("invalid-path", `${parts.join(".")} is not a text run.`);
|
|
212
205
|
return { parts: arrayParts, index, run };
|
|
213
206
|
}
|
|
214
207
|
|
|
215
208
|
/** Make the run at `runPath` cite `ids` (a string or array; replaces its current cites). The ids must exist in references. */
|
|
216
|
-
export function prepareCite(
|
|
209
|
+
export function prepareCite(presentation, runPath, ids) {
|
|
217
210
|
const list = Array.isArray(ids) ? ids : [ids];
|
|
218
211
|
if (!list.length || !list.every((id) => typeof id === "string" && id)) throw fail("invalid-reference", "cite needs one or more reference ids.");
|
|
219
|
-
const known = new Set(referenceList(
|
|
212
|
+
const known = new Set(referenceList(presentation).map((item) => item?.id));
|
|
220
213
|
const unknown = list.filter((id) => !known.has(id));
|
|
221
214
|
if (unknown.length) throw fail("unknown-reference", `Unknown reference${unknown.length === 1 ? "" : "s"} ${unknown.map((id) => `'${id}'`).join(", ")}; add them with addReference first.`, { ids: unknown });
|
|
222
|
-
const { parts, index, run } = runAt(
|
|
223
|
-
const runs = clone(getValueAtPath(
|
|
215
|
+
const { parts, index, run } = runAt(presentation, runPath);
|
|
216
|
+
const runs = clone(getValueAtPath(presentation, parts));
|
|
224
217
|
const next = typeof run === "string" ? { text: run } : { ...clone(run) };
|
|
225
218
|
if (!next.text) throw fail("invalid-run", "An empty run cannot carry a marker.", { path: runPath });
|
|
226
219
|
const unique = [...new Set(list)];
|
|
227
220
|
next.cite = unique.length === 1 ? unique[0] : unique;
|
|
228
221
|
runs[index] = next;
|
|
229
|
-
return transaction(
|
|
222
|
+
return transaction(presentation, parts, runs, { action: "cite", runPath: [...parts, index].join("."), ids: unique });
|
|
230
223
|
}
|
|
231
224
|
export function citeRun(editor, runPath, ids, meta = {}) {
|
|
232
225
|
checkEditor(editor);
|
|
233
|
-
return commit(editor, prepareCite(editor.
|
|
226
|
+
return commit(editor, prepareCite(editor.presentation, runPath, ids), meta);
|
|
234
227
|
}
|
|
235
228
|
/** Remove every cite from the run at `runPath`. */
|
|
236
|
-
export function prepareUncite(
|
|
237
|
-
const { parts, index, run } = runAt(
|
|
238
|
-
const runs = clone(getValueAtPath(
|
|
229
|
+
export function prepareUncite(presentation, runPath) {
|
|
230
|
+
const { parts, index, run } = runAt(presentation, runPath);
|
|
231
|
+
const runs = clone(getValueAtPath(presentation, parts));
|
|
239
232
|
const next = typeof run === "string" ? run : { ...clone(run) };
|
|
240
233
|
if (typeof next === "object") delete next.cite;
|
|
241
234
|
runs[index] = typeof next === "object" ? simplifyRun(next) : next;
|
|
242
|
-
return transaction(
|
|
235
|
+
return transaction(presentation, parts, runs, { action: "uncite", runPath: [...parts, index].join(".") });
|
|
243
236
|
}
|
|
244
237
|
export function unciteRun(editor, runPath, meta = {}) {
|
|
245
238
|
checkEditor(editor);
|
|
246
|
-
return commit(editor, prepareUncite(editor.
|
|
239
|
+
return commit(editor, prepareUncite(editor.presentation, runPath), meta);
|
|
247
240
|
}
|
|
248
241
|
/** Set (a string or TextRun[]) or remove (`null`) the inline footnote of the run at `runPath`. */
|
|
249
|
-
export function prepareFootnote(
|
|
250
|
-
const { parts, index, run } = runAt(
|
|
251
|
-
const runs = clone(getValueAtPath(
|
|
242
|
+
export function prepareFootnote(presentation, runPath, text) {
|
|
243
|
+
const { parts, index, run } = runAt(presentation, runPath);
|
|
244
|
+
const runs = clone(getValueAtPath(presentation, parts));
|
|
252
245
|
const next = typeof run === "string" ? { text: run } : { ...clone(run) };
|
|
253
246
|
if (text === null || text === undefined) delete next.footnote;
|
|
254
247
|
else {
|
|
@@ -257,16 +250,16 @@ export function prepareFootnote(document, runPath, text) {
|
|
|
257
250
|
next.footnote = clone(text);
|
|
258
251
|
}
|
|
259
252
|
runs[index] = simplifyRun(next);
|
|
260
|
-
return transaction(
|
|
253
|
+
return transaction(presentation, parts, runs, { action: "footnote", runPath: [...parts, index].join(".") });
|
|
261
254
|
}
|
|
262
255
|
export function setFootnote(editor, runPath, text, meta = {}) {
|
|
263
256
|
checkEditor(editor);
|
|
264
|
-
return commit(editor, prepareFootnote(editor.
|
|
257
|
+
return commit(editor, prepareFootnote(editor.presentation, runPath, text), meta);
|
|
265
258
|
}
|
|
266
259
|
|
|
267
260
|
/** The deck numbering the engines draw: notes in number order, cited references, per-slide markers, unused ids. */
|
|
268
|
-
export function listCitations(
|
|
269
|
-
const citations =
|
|
261
|
+
export function listCitations(presentation) {
|
|
262
|
+
const citations = collectCitations(presentation);
|
|
270
263
|
return {
|
|
271
264
|
notes: citations.notes.map((note) => ({ ...note })),
|
|
272
265
|
references: citations.references.map((note) => ({ ...note })),
|
|
@@ -275,7 +268,6 @@ export function listCitations(document) {
|
|
|
275
268
|
};
|
|
276
269
|
}
|
|
277
270
|
/** An ordinary list slide of the cited references (core `referencesSlide`), ready for `prepareBlockInsert` or a slide insert. */
|
|
278
|
-
export function referencesSlideFor(
|
|
279
|
-
|
|
280
|
-
return opfCore.referencesSlide(document, options);
|
|
271
|
+
export function referencesSlideFor(presentation, options = {}) {
|
|
272
|
+
return referencesSlide(presentation, options);
|
|
281
273
|
}
|
package/dist/assets.d.ts
CHANGED
|
@@ -28,8 +28,8 @@ export interface ImageUploadOptions {
|
|
|
28
28
|
onAddAsset?: (image: { name: string; mediaType: string; bytes: Uint8Array; size: number; alt?: string; file: unknown }) => string | { src: string } | Promise<string | { src: string }>;
|
|
29
29
|
meta?: Record<string, unknown>;
|
|
30
30
|
}
|
|
31
|
-
export interface ImageUploadChange extends Omit<EditorChange, "
|
|
32
|
-
|
|
31
|
+
export interface ImageUploadChange extends Omit<EditorChange, "presentation" | "patches"> {
|
|
32
|
+
presentation: unknown;
|
|
33
33
|
patches: JsonPatchOperation[];
|
|
34
34
|
/** The new asset's id (absent with `onAddAsset`). */
|
|
35
35
|
assetId?: string;
|
|
@@ -46,21 +46,21 @@ export declare function checkImageBytes(bytes: Uint8Array, options?: { name?: st
|
|
|
46
46
|
export declare function readImageFile(file: { name?: string; type?: string; size?: number; arrayBuffer(): Promise<ArrayBuffer> }, options?: { maxBytes?: number }): Promise<ValidatedImage>;
|
|
47
47
|
export declare function imageDataUri(bytes: Uint8Array, mediaType: string): string;
|
|
48
48
|
/** A free asset id for a file name (`logo`, then `logo-2`). */
|
|
49
|
-
export declare function uniqueAssetId(
|
|
49
|
+
export declare function uniqueAssetId(presentation: unknown, name: string): string;
|
|
50
50
|
/** The patch that adds one validated image to `assets`. */
|
|
51
|
-
export declare function prepareImageAsset(
|
|
51
|
+
export declare function prepareImageAsset(presentation: unknown, image: ValidatedImage, options?: { alt?: string; id?: string }): PreparedImageAsset;
|
|
52
52
|
/**
|
|
53
|
-
* Add an uploaded image and use it in one undoable transaction. `build(reference,
|
|
53
|
+
* Add an uploaded image and use it in one undoable transaction. `build(reference, presentation)` returns the prepared change
|
|
54
54
|
* that uses the image (any `prepare...` function of this package); its patches run after the asset patch.
|
|
55
55
|
*/
|
|
56
56
|
export declare function applyImageUpload(
|
|
57
57
|
editor: EditorSession,
|
|
58
58
|
file: { name?: string; type?: string; size?: number; arrayBuffer(): Promise<ArrayBuffer> },
|
|
59
|
-
build: (reference: string,
|
|
59
|
+
build: (reference: string, presentation: any) => { patches: JsonPatchOperation[] },
|
|
60
60
|
options?: ImageUploadOptions,
|
|
61
61
|
): Promise<ImageUploadChange>;
|
|
62
62
|
/** The patch that sets (or, for an empty string, removes) an asset's alt text. */
|
|
63
|
-
export declare function prepareAssetAlt(
|
|
63
|
+
export declare function prepareAssetAlt(presentation: unknown, assetId: string, alt: string): { assetId: string; patches: JsonPatchOperation[]; changed: boolean };
|
|
64
64
|
/** Set an asset's alt text as one undoable transaction. */
|
|
65
65
|
export declare function setAssetAlt(editor: EditorSession, assetId: string, alt: string, meta?: Record<string, unknown>): unknown;
|
|
66
66
|
/** The `assets` id a reference names (`asset:logo` gives `logo`), or undefined for a URL or data address. */
|
package/dist/assets.js
CHANGED
|
@@ -90,9 +90,9 @@ export function imageDataUri(bytes, mediaType) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/** An asset id for a file name that is free in the document (`logo`, then `logo-2`, ...). */
|
|
93
|
-
export function uniqueAssetId(
|
|
93
|
+
export function uniqueAssetId(presentation, name) {
|
|
94
94
|
const base = String(name ?? "image").replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "image";
|
|
95
|
-
const taken =
|
|
95
|
+
const taken = presentation?.assets && typeof presentation.assets === "object" ? presentation.assets : {};
|
|
96
96
|
if (!Object.hasOwn(taken, base)) return base;
|
|
97
97
|
for (let n = 2; ; n += 1) if (!Object.hasOwn(taken, `${base}-${n}`)) return `${base}-${n}`;
|
|
98
98
|
}
|
|
@@ -101,19 +101,19 @@ export function uniqueAssetId(document, name) {
|
|
|
101
101
|
* The patch that adds one validated image to `assets` (the entry is `{ src: dataUri, mediaType, title, alt? }`),
|
|
102
102
|
* with the `asset:<id>` reference to use. Pure: touches no session.
|
|
103
103
|
*/
|
|
104
|
-
export function prepareImageAsset(
|
|
105
|
-
const assetId = id ?? uniqueAssetId(
|
|
106
|
-
if (
|
|
104
|
+
export function prepareImageAsset(presentation, image, { alt, id } = {}) {
|
|
105
|
+
const assetId = id ?? uniqueAssetId(presentation, image.name);
|
|
106
|
+
if (presentation?.assets && Object.hasOwn(presentation.assets, assetId)) throw fail("asset-exists", `An asset named "${assetId}" already exists.`, { id: assetId });
|
|
107
107
|
const entry = { src: imageDataUri(image.bytes, image.mediaType), mediaType: image.mediaType, title: image.name };
|
|
108
108
|
if (typeof alt === "string" && alt.trim()) entry.alt = alt.trim();
|
|
109
|
-
const patches =
|
|
109
|
+
const patches = presentation?.assets && typeof presentation.assets === "object" && !Array.isArray(presentation.assets)
|
|
110
110
|
? [{ op: "add", path: opfPathToJsonPointer(["assets", assetId]), value: entry }]
|
|
111
111
|
: [{ op: "add", path: "/assets", value: { [assetId]: entry } }];
|
|
112
112
|
return { id: assetId, reference: `asset:${assetId}`, entry, patches };
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
|
-
* Add an uploaded image and use it in one undoable transaction. `build(reference,
|
|
116
|
+
* Add an uploaded image and use it in one undoable transaction. `build(reference, presentation)` returns the
|
|
117
117
|
* prepared change that uses the image (any `prepare...` function of this package, for example
|
|
118
118
|
* `(ref, doc) => prepareLogoVariant(doc, "light", ref)`); its patches run after the asset patch.
|
|
119
119
|
*
|
|
@@ -134,23 +134,23 @@ export async function applyImageUpload(editor, file, build, options = {}) {
|
|
|
134
134
|
if (typeof reference !== "string" || !reference.trim()) throw fail("invalid-asset-reference", "The host's onAddAsset must return the image's reference (a web address or an asset: id).", {});
|
|
135
135
|
} else {
|
|
136
136
|
// Build against the document as it is after the read: the file may have taken a moment to arrive.
|
|
137
|
-
const added = prepareImageAsset(editor.
|
|
137
|
+
const added = prepareImageAsset(editor.presentation, image, { alt });
|
|
138
138
|
reference = added.reference;
|
|
139
139
|
assetPatches = added.patches;
|
|
140
140
|
assetId = added.id;
|
|
141
141
|
}
|
|
142
|
-
const
|
|
143
|
-
const prepared = build(reference,
|
|
142
|
+
const presentation = assetPatches.length ? applyJsonPatch(editor.presentation, assetPatches) : editor.presentation;
|
|
143
|
+
const prepared = build(reference, presentation);
|
|
144
144
|
const patches = [...assetPatches, ...prepared.patches];
|
|
145
145
|
const summary = { assetId, reference, changed: patches.length > 0, prepared };
|
|
146
|
-
if (!patches.length) return { ...summary,
|
|
146
|
+
if (!patches.length) return { ...summary, presentation: editor.presentation, patches: [], inversePatches: [], validation: editor.validation };
|
|
147
147
|
const change = editor.applyPatch(patches, { ...meta, source: meta?.source ?? "image-upload", ...(assetId ? { assetId } : {}), reference });
|
|
148
148
|
return { ...change, ...summary };
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/** The patch that sets (or, for an empty string, removes) an asset's alt text. The asset must exist in `assets`. */
|
|
152
|
-
export function prepareAssetAlt(
|
|
153
|
-
const entry = getValueAtPath(
|
|
152
|
+
export function prepareAssetAlt(presentation, assetId, alt) {
|
|
153
|
+
const entry = getValueAtPath(presentation, ["assets", assetId]);
|
|
154
154
|
if (entry === undefined) throw fail("unknown-asset", `There is no asset named "${assetId}".`, { assetId });
|
|
155
155
|
const object = typeof entry === "string" ? { src: entry } : { ...entry };
|
|
156
156
|
const text = typeof alt === "string" ? alt.trim() : "";
|
|
@@ -164,8 +164,8 @@ export function prepareAssetAlt(document, assetId, alt) {
|
|
|
164
164
|
/** Set an asset's alt text as one undoable transaction. */
|
|
165
165
|
export function setAssetAlt(editor, assetId, alt, meta = {}) {
|
|
166
166
|
if (!editor || typeof editor.applyPatch !== "function") throw fail("invalid-editor", "Expected an editor session created by createEditorSession.");
|
|
167
|
-
const prepared = prepareAssetAlt(editor.
|
|
168
|
-
if (!prepared.changed) return { ...prepared,
|
|
167
|
+
const prepared = prepareAssetAlt(editor.presentation, assetId, alt);
|
|
168
|
+
if (!prepared.changed) return { ...prepared, presentation: editor.presentation, inversePatches: [], validation: editor.validation };
|
|
169
169
|
return { ...editor.applyPatch(prepared.patches, { ...meta, source: meta.source ?? "asset-alt", assetId }), assetId, changed: true };
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -26,7 +26,7 @@ export type BackgroundSpec =
|
|
|
26
26
|
export declare function isColorRef(value: unknown): boolean;
|
|
27
27
|
/** Validate a background description and return the value to store (a theme slot or plain hex stays the shorthand string). Throws `invalid-background`. */
|
|
28
28
|
export declare function normalizeBackground(spec: BackgroundSpec): string | Record<string, unknown>;
|
|
29
|
-
export declare function prepareBackground(
|
|
29
|
+
export declare function prepareBackground(presentation: unknown, spec: BackgroundSpec | null, options?: DimensionSwitchOptions): PreparedDimensionSwitch;
|
|
30
30
|
/** Set the background as one undoable transaction; `null` removes it. */
|
|
31
31
|
export declare function setBackground(editor: EditorSession, spec: BackgroundSpec | null, options?: DimensionSwitchOptions): DimensionSwitchChange;
|
|
32
32
|
export interface BackgroundState {
|
|
@@ -45,4 +45,4 @@ export interface BackgroundState {
|
|
|
45
45
|
value?: unknown;
|
|
46
46
|
}
|
|
47
47
|
/** The background that applies at a scope, flattened for a form. */
|
|
48
|
-
export declare function readBackground(
|
|
48
|
+
export declare function readBackground(presentation: unknown, options?: { slideIndex?: number }): BackgroundState;
|
|
@@ -11,7 +11,7 @@ export const IMAGE_BACKGROUND_FITS = Object.freeze(["cover", "contain", "tile"])
|
|
|
11
11
|
/** Scheme slots and roles a ColorRef may name (the schema's ColorRef enum), besides hex colors and `var:<id>`. */
|
|
12
12
|
export const COLOR_NAMES = Object.freeze([
|
|
13
13
|
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink",
|
|
14
|
-
"primary", "secondary", "accent", "background", "surface", "text", "textSecondary",
|
|
14
|
+
"primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary",
|
|
15
15
|
]);
|
|
16
16
|
/**
|
|
17
17
|
* The 54 DrawingML preset patterns (ECMA-376 ST_PresetPatternVal) by family. PPTX export writes them as
|
|
@@ -102,8 +102,8 @@ export function normalizeBackground(spec) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/** Compute the patch that sets (or, for `null`, removes) the background, without touching a session. Options as `prepareDimensionSwitch` (`slideIndex`, `clearSlideOverrides`). */
|
|
105
|
-
export function prepareBackground(
|
|
106
|
-
return prepareDimensionSwitch(
|
|
105
|
+
export function prepareBackground(presentation, spec, options = {}) {
|
|
106
|
+
return prepareDimensionSwitch(presentation, "backgrounds", spec === null ? null : normalizeBackground(spec), options);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/** Set the background as one undoable transaction; `null` removes it so the theme's (or the deck's) shows again. */
|
|
@@ -116,9 +116,9 @@ export function setBackground(editor, spec, options = {}) {
|
|
|
116
116
|
* `{ type, slot?, color?, opacity?, angle?, stops?, src?, fit?, preset?, foregroundColor?, backgroundColor?, scope, value }`.
|
|
117
117
|
* `type` is undefined when nothing is set; `scope` is "slide" when the slide sets its own, else "deck".
|
|
118
118
|
*/
|
|
119
|
-
export function readBackground(
|
|
120
|
-
const own = slideIndex === undefined ? undefined :
|
|
121
|
-
const value = own !== undefined ? own :
|
|
119
|
+
export function readBackground(presentation, { slideIndex } = {}) {
|
|
120
|
+
const own = slideIndex === undefined ? undefined : presentation.slides?.[slideIndex]?.design?.background;
|
|
121
|
+
const value = own !== undefined ? own : presentation.design?.background;
|
|
122
122
|
const scope = own !== undefined ? "slide" : "deck";
|
|
123
123
|
if (value === undefined) return { scope };
|
|
124
124
|
if (typeof value === "string") return THEME_BACKGROUND_SLOTS.includes(value) ? { type: "theme", slot: value, scope, value } : { type: "solid", color: value, scope, value };
|
package/dist/block-controls.js
CHANGED
|
@@ -13,18 +13,18 @@ export function createBlockControls(root, options) {
|
|
|
13
13
|
function apply(prepared){
|
|
14
14
|
if(!prepared?.changed){cancel();return true;}
|
|
15
15
|
// Retain changes outside the guarded containers and preflight the exact candidate.
|
|
16
|
-
const candidate=applyJsonPatch(editor.
|
|
16
|
+
const candidate=applyJsonPatch(editor.presentation,prepared.patches);
|
|
17
17
|
options.validate(candidate);
|
|
18
18
|
committing=true;
|
|
19
19
|
try{cancel();editor.applyPatch(prepared.patches,{source:'canvas-block-edit',rejectInvalid:true});options.onMove?.(prepared.path);([ ...layer.querySelectorAll("[data-block-path]")].find(node=>node.dataset.blockPath===prepared.path)??layer.querySelector('[data-block-add]'))?.focus();options.clearError?.();options.onCommit?.({path:prepared.path,editor});return true;}
|
|
20
20
|
finally{committing=false;}
|
|
21
21
|
}
|
|
22
|
-
function move(from,to,index,base=editor.
|
|
22
|
+
function move(from,to,index,base=editor.presentation){
|
|
23
23
|
try{return apply(prepareBlockMove(base,from,to,index));}catch(error){cancel();options.onError(error);return false;}
|
|
24
24
|
}
|
|
25
25
|
function open(path){
|
|
26
26
|
if(!options.beforeEdit())return;
|
|
27
|
-
cancel();returnFocus=doc.activeElement;path=opfPathToJsonPointer(path);const base=editor.
|
|
27
|
+
cancel();returnFocus=doc.activeElement;path=opfPathToJsonPointer(path);const base=editor.presentation,parts=splitOpfPath(path),container=opfPathToJsonPointer(parts.slice(0,-2)),index=Number(parts.at(-1));
|
|
28
28
|
const source=getValueAtPath(base,[...parts.slice(0,-2),'blocks']);
|
|
29
29
|
if(parts.at(-2)!=='blocks'||!Number.isInteger(index)||index<0||!Array.isArray(source)||index>=source.length){options.onError(new Error('Choose an existing content block.'));return;}
|
|
30
30
|
const count=source.length;
|
|
@@ -56,7 +56,7 @@ export function createBlockControls(root, options) {
|
|
|
56
56
|
}
|
|
57
57
|
function openInsert(containerPath,index) {
|
|
58
58
|
if(!options.beforeEdit())return;
|
|
59
|
-
cancel();returnFocus=doc.activeElement;const base=editor.
|
|
59
|
+
cancel();returnFocus=doc.activeElement;const base=editor.presentation;
|
|
60
60
|
const containers=listBlockContainers(base,{slideIndex:options.slideIndex(),includeImplicit:true});
|
|
61
61
|
if(!containers.length){options.onError(new Error('No content container is available on this slide.'));return;}
|
|
62
62
|
const requested=containerPath===undefined?containers[0].path:opfPathToJsonPointer(containerPath);
|
|
@@ -91,7 +91,7 @@ export function createBlockControls(root, options) {
|
|
|
91
91
|
panel.append(add,close);panel.onkeydown=event=>{if(event.key==='Escape'){event.preventDefault();event.stopPropagation();cancel();}};
|
|
92
92
|
layer.append(panel);kind.focus();
|
|
93
93
|
}
|
|
94
|
-
function update(
|
|
94
|
+
function update(presentation,nextGeometry){
|
|
95
95
|
geometry=nextGeometry;
|
|
96
96
|
if(drag)return;
|
|
97
97
|
cancel();layer.replaceChildren();cells=[];
|
|
@@ -99,7 +99,7 @@ export function createBlockControls(root, options) {
|
|
|
99
99
|
const add=doc.createElement('button');add.type='button';add.textContent='+ Add content';add.setAttribute('aria-label','Add content');add.dataset.blockAdd='';
|
|
100
100
|
add.style.cssText='position:absolute;right:8px;top:8px;pointer-events:auto;padding:5px 9px;background:#f6f3fc;color:#675394;border:1px solid #cfc4e7;border-radius:5px;font:12px system-ui;cursor:pointer';add.onclick=()=>openInsert();layer.append(add);
|
|
101
101
|
for(const flow of geometry.flows??[]){
|
|
102
|
-
const blocks=getValueAtPath(
|
|
102
|
+
const blocks=getValueAtPath(presentation,[...splitOpfPath(flow.path),'blocks']);
|
|
103
103
|
if(!Array.isArray(blocks)||blocks.length!==flow.itemCount)continue;
|
|
104
104
|
blocks.forEach((block,index)=>{
|
|
105
105
|
const col=flow.columns[index%flow.columns.length],row=flow.rows[Math.floor(index/flow.columns.length)];if(!col||!row)return;
|
|
@@ -116,7 +116,7 @@ export function createBlockControls(root, options) {
|
|
|
116
116
|
node.onkeydown=event=>{if(['ArrowLeft','ArrowUp','ArrowRight','ArrowDown'].includes(event.key)){event.preventDefault();event.stopPropagation();if(!options.beforeEdit())return;const delta=['ArrowLeft','ArrowUp'].includes(event.key)?-1:1;if(index+delta>=0&&index+delta<blocks.length)move(path,container,index+(delta>0?2:-1));}};
|
|
117
117
|
node.ondragstart=event=>{
|
|
118
118
|
if(!options.beforeEdit()){event.preventDefault();return;}
|
|
119
|
-
cancel();drag={from:path,container,index,base:editor.
|
|
119
|
+
cancel();drag={from:path,container,index,base:editor.presentation,signature:signature(container),cells:[...cells],prepared:null};
|
|
120
120
|
event.dataTransfer.effectAllowed='move';event.dataTransfer.setData('text/plain',path);
|
|
121
121
|
};
|
|
122
122
|
node.ondragend=()=>{cancel();options.render();};layer.append(node);
|
package/dist/block-convert.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export interface BlockConversionTarget {
|
|
|
32
32
|
reason?: string;
|
|
33
33
|
}
|
|
34
34
|
export interface PreparedBlockConversion {
|
|
35
|
-
|
|
35
|
+
presentation: unknown;
|
|
36
36
|
patches: JsonPatchOperation[];
|
|
37
37
|
path: string;
|
|
38
38
|
changed: boolean;
|
|
@@ -41,8 +41,8 @@ export interface PreparedBlockConversion {
|
|
|
41
41
|
from: BlockKind;
|
|
42
42
|
to: BlockKind;
|
|
43
43
|
}
|
|
44
|
-
export interface BlockConversionChange extends Omit<EditorChange, "
|
|
45
|
-
|
|
44
|
+
export interface BlockConversionChange extends Omit<EditorChange, "presentation" | "patches"> {
|
|
45
|
+
presentation: unknown;
|
|
46
46
|
patches: JsonPatchOperation[];
|
|
47
47
|
lossless: boolean;
|
|
48
48
|
loss: string[];
|
|
@@ -53,12 +53,12 @@ export interface BlockConversionChange extends Omit<EditorChange, "document" | "
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** The single content payload of the block at `path`, or undefined (image-only, groups and blocks with several fields have none to convert). */
|
|
56
|
-
export declare function readBlockContent(
|
|
56
|
+
export declare function readBlockContent(presentation: unknown, path: string | string[]): BlockContent | undefined;
|
|
57
57
|
/** The block that contains a selected path (slides.0.blocks.1.text maps to slides.0.blocks.1), or undefined. */
|
|
58
|
-
export declare function blockPathForSelection(
|
|
58
|
+
export declare function blockPathForSelection(presentation: unknown, selectedPath: string): string | undefined;
|
|
59
59
|
/** The kinds the block can convert to, each with its loss report or the reason it is unavailable. */
|
|
60
|
-
export declare function blockConversionTargets(
|
|
60
|
+
export declare function blockConversionTargets(presentation: unknown, path: string | string[]): BlockConversionTarget[];
|
|
61
61
|
/** Compute the conversion patch without touching a session. Throws `block-not-convertible` for an unsupported pair or content that does not fit. */
|
|
62
|
-
export declare function prepareBlockConversion(
|
|
62
|
+
export declare function prepareBlockConversion(presentation: unknown, path: string | string[], kind: BlockKind, options?: ConvertOptions): PreparedBlockConversion;
|
|
63
63
|
/** Convert one block as a single undoable transaction. */
|
|
64
64
|
export declare function convertBlock(editor: EditorSession, path: string | string[], kind: BlockKind, meta?: Record<string, unknown>, options?: ConvertOptions): BlockConversionChange;
|