@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.
Files changed (95) hide show
  1. package/README.md +82 -58
  2. package/dist/annotations.d.ts +16 -16
  3. package/dist/annotations.js +71 -79
  4. package/dist/assets.d.ts +7 -7
  5. package/dist/assets.js +15 -15
  6. package/dist/background-options.d.ts +2 -2
  7. package/dist/background-options.js +6 -6
  8. package/dist/block-controls.js +7 -7
  9. package/dist/block-convert.d.ts +7 -7
  10. package/dist/block-convert.js +23 -21
  11. package/dist/blocks.d.ts +8 -8
  12. package/dist/blocks.js +41 -40
  13. package/dist/canvas-fields.js +35 -12
  14. package/dist/canvas.d.ts +22 -30
  15. package/dist/canvas.js +57 -64
  16. package/dist/chart-data.d.ts +12 -10
  17. package/dist/chart-data.js +22 -21
  18. package/dist/chart-options-panel.d.ts +2 -2
  19. package/dist/chart-options-panel.js +82 -8
  20. package/dist/chart-options.d.ts +35 -9
  21. package/dist/chart-options.js +133 -40
  22. package/dist/checks.js +21 -0
  23. package/dist/color-authoring.js +1 -1
  24. package/dist/content-actions.d.ts +15 -15
  25. package/dist/content-actions.js +71 -70
  26. package/dist/content-controls.js +12 -12
  27. package/dist/data-grid.js +179 -10
  28. package/dist/data.d.ts +23 -2
  29. package/dist/data.js +40 -1
  30. package/dist/dataset-refs.d.ts +17 -0
  31. package/dist/dataset-refs.js +45 -0
  32. package/dist/design-controls.js +66 -47
  33. package/dist/design-options.d.ts +16 -14
  34. package/dist/design-options.js +86 -74
  35. package/dist/edit-helpers.js +8 -7
  36. package/dist/exact-source.js +5 -5
  37. package/dist/export.d.ts +5 -7
  38. package/dist/export.js +40 -14
  39. package/dist/find-panel.js +5 -5
  40. package/dist/find-replace.d.ts +3 -3
  41. package/dist/find-replace.js +35 -20
  42. package/dist/font-gate.js +49 -58
  43. package/dist/galleries.js +36 -52
  44. package/dist/grid-model.d.ts +99 -24
  45. package/dist/grid-model.js +577 -101
  46. package/dist/image-crop.d.ts +4 -4
  47. package/dist/image-crop.js +20 -20
  48. package/dist/image-cropper.js +3 -3
  49. package/dist/index.d.ts +28 -28
  50. package/dist/index.js +74 -90
  51. package/dist/json-options.js +17 -16
  52. package/dist/layout-handles.js +5 -5
  53. package/dist/layout-placeholders.js +4 -4
  54. package/dist/layout.d.ts +2 -2
  55. package/dist/layout.js +8 -7
  56. package/dist/numbering-panel.js +3 -5
  57. package/dist/numbering.d.ts +3 -5
  58. package/dist/numbering.js +14 -26
  59. package/dist/outline-view.js +24 -24
  60. package/dist/outline.d.ts +12 -12
  61. package/dist/outline.js +52 -50
  62. package/dist/persistence.d.ts +1 -1
  63. package/dist/persistence.js +19 -18
  64. package/dist/presentation-ids.js +2 -2
  65. package/dist/react.js +3 -3
  66. package/dist/review-panel.d.ts +30 -13
  67. package/dist/review-panel.js +154 -53
  68. package/dist/review.d.ts +36 -43
  69. package/dist/review.js +92 -53
  70. package/dist/rich-text-input.js +4 -3
  71. package/dist/rich-text-toolbar.js +5 -3
  72. package/dist/rich-text.js +5 -2
  73. package/dist/schema-inspector.d.ts +2 -2
  74. package/dist/schema-inspector.js +16 -11
  75. package/dist/schema.d.ts +1 -1
  76. package/dist/schema.js +25 -5
  77. package/dist/slide-manager.d.ts +2 -2
  78. package/dist/slide-manager.js +18 -18
  79. package/dist/slides.d.ts +20 -20
  80. package/dist/slides.js +99 -97
  81. package/dist/svelte.js +1 -1
  82. package/dist/switches.d.ts +10 -10
  83. package/dist/switches.js +136 -109
  84. package/dist/table-options.d.ts +8 -8
  85. package/dist/table-options.js +41 -30
  86. package/dist/table-structure.d.ts +10 -10
  87. package/dist/table-structure.js +21 -21
  88. package/dist/template-panel.d.ts +3 -3
  89. package/dist/template-panel.js +37 -13
  90. package/dist/templates.d.ts +22 -11
  91. package/dist/templates.js +48 -55
  92. package/dist/transfer.d.ts +4 -4
  93. package/dist/transfer.js +74 -54
  94. package/package.json +10 -6
  95. package/dist/font-defaults.js +0 -25
@@ -2,7 +2,7 @@
2
2
  // split and merge, as editor transactions. The pure transforms live in core (`@openpresentation/opf/convert`);
3
3
  // each action here finds its target in the document, calls the transform, turns the result into a guarded patch
4
4
  // (`test` of what was read, then `replace`, or per-slide `remove` and `add`), validates the document and, in the
5
- // apply form, applies it as ONE undoable step. Every prepare function returns `{ document, patches, changed,
5
+ // apply form, applies it as ONE undoable step. Every prepare function returns `{ presentation, patches, changed,
6
6
  // lossless, loss, path }` without touching a session; a refusal throws `content-action-refused`.
7
7
  import {
8
8
  OPFConversionError,
@@ -19,9 +19,10 @@ import {
19
19
  unwrapGroup,
20
20
  wrapBlocks,
21
21
  } from "@openpresentation/opf/convert";
22
- import { applyJsonPatch, getValueAtPath, opfPathToJsonPointer, splitOpfPath, validateOpfDocument } from "./index.js";
22
+ import { applyJsonPatch, getValueAtPath, opfPathToJsonPointer, splitOpfPath } from "./index.js";
23
23
  import { readBlockContent } from "./block-convert.js";
24
24
  import { checkedDocument, fail } from "./edit-helpers.js";
25
+ import { checkFormat } from "./checks.js";
25
26
 
26
27
  const refuse = (message, details) => fail("content-action-refused", message, details);
27
28
 
@@ -39,14 +40,14 @@ function requireEditor(editor) {
39
40
  if (!editor || typeof editor.applyPatch !== "function") throw fail("invalid-editor", "Expected an editor session created by createEditorSession.");
40
41
  }
41
42
 
42
- function slideParts(document, path, what) {
43
+ function slideParts(presentation, path, what) {
43
44
  let parts;
44
45
  try {
45
46
  parts = splitOpfPath(path);
46
47
  } catch {
47
48
  parts = undefined;
48
49
  }
49
- if (!parts || parts[0] !== "slides" || !/^(0|[1-9][0-9]*)$/.test(parts[1] ?? "") || !document?.slides?.[Number(parts[1])]) throw refuse(`Choose ${what} on a slide.`, { path });
50
+ if (!parts || parts[0] !== "slides" || !/^(0|[1-9][0-9]*)$/.test(parts[1] ?? "") || !presentation?.slides?.[Number(parts[1])]) throw refuse(`Choose ${what} on a slide.`, { path });
50
51
  return { slideIndex: Number(parts[1]), relative: parts.slice(2), parts };
51
52
  }
52
53
 
@@ -54,27 +55,27 @@ const asNumbers = (path) => path.map((part) => (/^(0|[1-9][0-9]*)$/.test(String(
54
55
  const toDocumentPath = (slideIndex, relative) => ["slides", String(slideIndex), ...(relative ?? []).map(String)].join(".");
55
56
 
56
57
  /** Replace one value (a slide, a block, a list) as `test` + `replace`, validated like every other edit. */
57
- function replacePatches(document, parts, next) {
58
+ function replacePatches(presentation, parts, next) {
58
59
  const pointer = opfPathToJsonPointer(parts);
59
60
  return [
60
- { op: "test", path: pointer, value: structuredClone(getValueAtPath(document, parts)) },
61
+ { op: "test", path: pointer, value: structuredClone(getValueAtPath(presentation, parts)) },
61
62
  { op: "replace", path: pointer, value: next },
62
63
  ];
63
64
  }
64
65
  // `validate: false` skips the whole-document check, for a dry run that only needs the loss report (core has already
65
66
  // validated the changed slide); applying always validates.
66
- function finish(document, patches, extra, validate = true) {
67
- if (!validate) return { document: applyJsonPatch(document, patches), patches, ...extra };
68
- const before = validateOpfDocument(document);
69
- return { document: checkedDocument(document, patches, before), patches, ...extra };
67
+ function finish(presentation, patches, extra, validate = true) {
68
+ if (!validate) return { presentation: applyJsonPatch(presentation, patches), patches, ...extra };
69
+ const before = checkFormat(presentation);
70
+ return { presentation: checkedDocument(presentation, patches, before), patches, ...extra };
70
71
  }
71
72
  function apply(editor, prepared, meta, source) {
72
- if (!prepared.changed) return { ...prepared, document: editor.document, patches: [], inversePatches: [], validation: editor.validation };
73
+ if (!prepared.changed) return { ...prepared, presentation: editor.presentation, patches: [], inversePatches: [], validation: editor.validation };
73
74
  const change = editor.applyPatch(prepared.patches, { ...meta, source: meta.source ?? source, path: prepared.path });
74
75
  const extra = Object.fromEntries(["levels", "range", "slideCount", "pages"].filter((key) => prepared[key] !== undefined).map((key) => [key, prepared[key]]));
75
76
  return { ...change, changed: true, lossless: prepared.lossless, loss: prepared.loss, path: prepared.path, ...extra };
76
77
  }
77
- const unchanged = (document, path, reason) => ({ document: structuredClone(document), patches: [], path, changed: false, lossless: true, loss: [], ...(reason ? { reason } : {}) });
78
+ const unchanged = (presentation, path, reason) => ({ presentation: structuredClone(presentation), patches: [], path, changed: false, lossless: true, loss: [], ...(reason ? { reason } : {}) });
78
79
 
79
80
  // --- list levels -------------------------------------------------------------------------------
80
81
 
@@ -91,75 +92,75 @@ export function listItemIndexForSelection(selectedPath, blockPath) {
91
92
  * item cannot be nested, and items under a moved item move with it (`options.withChildren`, default true).
92
93
  * `changed` is false, with a `reason`, when nothing can move.
93
94
  */
94
- export function prepareListShift(document, blockPath, indices, delta, options = {}) {
95
- const found = readBlockContent(document, blockPath);
95
+ export function prepareListShift(presentation, blockPath, indices, delta, options = {}) {
96
+ const found = readBlockContent(presentation, blockPath);
96
97
  if (!found || found.kind !== "list") throw refuse("Choose a list block.", { path: blockPath });
97
98
  const result = core(() => shiftListLevels(found.owner, indices, delta, options));
98
99
  const path = found.path.join(".");
99
- if (!result.changed) return unchanged(document, path, result.reason);
100
- return finish(document, replacePatches(document, found.path, result.payload), { path, changed: true, lossless: result.lossless, loss: result.loss, levels: result.levels }, options.validate !== false);
100
+ if (!result.changed) return unchanged(presentation, path, result.reason);
101
+ return finish(presentation, replacePatches(presentation, found.path, result.payload), { path, changed: true, lossless: result.lossless, loss: result.loss, levels: result.levels }, options.validate !== false);
101
102
  }
102
103
  /** Nest or un-nest list items as one undoable step. Returns the session change plus `changed`, `reason`, `levels`, `lossless` and `loss`. */
103
104
  export function shiftListItems(editor, blockPath, indices, delta, options = {}, meta = {}) {
104
105
  requireEditor(editor);
105
- return apply(editor, prepareListShift(editor.document, blockPath, indices, delta, options), meta, "list-level");
106
+ return apply(editor, prepareListShift(editor.presentation, blockPath, indices, delta, options), meta, "list-level");
106
107
  }
107
108
 
108
109
  // --- structure inside one slide ----------------------------------------------------------------
109
110
 
110
111
  /** One slide-level transform as a guarded replace of that slide. */
111
- function slideAction(document, slideIndex, transform, targetPath, validate = true) {
112
- const slide = document.slides[slideIndex];
112
+ function slideAction(presentation, slideIndex, transform, targetPath, validate = true) {
113
+ const slide = presentation.slides[slideIndex];
113
114
  const result = core(() => transform(slide));
114
115
  const path = result.path ? toDocumentPath(slideIndex, result.path) : (targetPath ?? `slides.${slideIndex}`);
115
- if (!result.changed) return unchanged(document, path);
116
- const patches = replacePatches(document, ["slides", String(slideIndex)], result.slide);
117
- return finish(document, patches, { path, changed: true, lossless: result.lossless, loss: result.loss }, validate);
116
+ if (!result.changed) return unchanged(presentation, path);
117
+ const patches = replacePatches(presentation, ["slides", String(slideIndex)], result.slide);
118
+ return finish(presentation, patches, { path, changed: true, lossless: result.lossless, loss: result.loss }, validate);
118
119
  }
119
120
 
120
121
  /** Wrap the blocks at `indices` of the container at `containerPath` (a slide `slides.0`, a group or a region group) in a new group. */
121
- export function prepareGroupBlocks(document, containerPath, indices, options = {}) {
122
- const { slideIndex, relative } = slideParts(document, containerPath, "a container");
123
- return slideAction(document, slideIndex, (slide) => wrapBlocks(slide, indices, { container: asNumbers(relative), ...(options.composition ? { composition: options.composition } : {}) }), undefined, options.validate !== false);
122
+ export function prepareGroupBlocks(presentation, containerPath, indices, options = {}) {
123
+ const { slideIndex, relative } = slideParts(presentation, containerPath, "a container");
124
+ return slideAction(presentation, slideIndex, (slide) => wrapBlocks(slide, indices, { container: asNumbers(relative), ...(options.composition ? { composition: options.composition } : {}) }), undefined, options.validate !== false);
124
125
  }
125
126
  /** Replace the group at `groupPath` by its blocks. What the group carried (composition, id) is reported in `loss`. */
126
- export function prepareUngroupBlock(document, groupPath, options = {}) {
127
- const { slideIndex, relative } = slideParts(document, groupPath, "a group");
128
- return slideAction(document, slideIndex, (slide) => unwrapGroup(slide, asNumbers(relative)), undefined, options.validate !== false);
127
+ export function prepareUngroupBlock(presentation, groupPath, options = {}) {
128
+ const { slideIndex, relative } = slideParts(presentation, groupPath, "a group");
129
+ return slideAction(presentation, slideIndex, (slide) => unwrapGroup(slide, asNumbers(relative)), undefined, options.validate !== false);
129
130
  }
130
131
  /** Place every block of a slide in its own named region: `regions[i]` is block i's region (`left`, `right`, `top:left`, ...). */
131
- export function prepareBlocksToRegions(document, slideIndex, regions, options = {}) {
132
- slideParts(document, `slides.${slideIndex}`, "a slide");
133
- return slideAction(document, slideIndex, (slide) => blocksToRegions(slide, regions), undefined, options.validate !== false);
132
+ export function prepareBlocksToRegions(presentation, slideIndex, regions, options = {}) {
133
+ slideParts(presentation, `slides.${slideIndex}`, "a slide");
134
+ return slideAction(presentation, slideIndex, (slide) => blocksToRegions(slide, regions), undefined, options.validate !== false);
134
135
  }
135
136
  /** Turn the named regions of a slide into ordinary blocks in reading order. The regions' placement is reported in `loss`. */
136
- export function prepareRegionsToBlocks(document, slideIndex, options = {}) {
137
- slideParts(document, `slides.${slideIndex}`, "a slide");
138
- return slideAction(document, slideIndex, (slide) => regionsToBlocks(slide), undefined, options.validate !== false);
137
+ export function prepareRegionsToBlocks(presentation, slideIndex, options = {}) {
138
+ slideParts(presentation, `slides.${slideIndex}`, "a slide");
139
+ return slideAction(presentation, slideIndex, (slide) => regionsToBlocks(slide), undefined, options.validate !== false);
139
140
  }
140
141
  /** Move the content of region `from` to region `to`, or swap them when `to` is taken and `options.swap` is true. */
141
- export function prepareMoveRegion(document, slideIndex, from, to, options = {}) {
142
- slideParts(document, `slides.${slideIndex}`, "a slide");
143
- return slideAction(document, slideIndex, (slide) => moveRegion(slide, from, to, options), undefined, options.validate !== false);
142
+ export function prepareMoveRegion(presentation, slideIndex, from, to, options = {}) {
143
+ slideParts(presentation, `slides.${slideIndex}`, "a slide");
144
+ return slideAction(presentation, slideIndex, (slide) => moveRegion(slide, from, to, options), undefined, options.validate !== false);
144
145
  }
145
146
  /** Move the image block at `blockPath` into the slide's design as `slideImage`, `background` or `watermark`. */
146
- export function prepareImageToDesign(document, blockPath, target, options = {}) {
147
- const { slideIndex, relative } = slideParts(document, blockPath, "an image block");
148
- return slideAction(document, slideIndex, (slide) => promoteImage(slide, asNumbers(relative), target, options), `slides.${slideIndex}`, options.validate !== false);
147
+ export function prepareImageToDesign(presentation, blockPath, target, options = {}) {
148
+ const { slideIndex, relative } = slideParts(presentation, blockPath, "an image block");
149
+ return slideAction(presentation, slideIndex, (slide) => promoteImage(slide, asNumbers(relative), target, options), `slides.${slideIndex}`, options.validate !== false);
149
150
  }
150
151
  /** Move a slide's own `slideImage`, `background` image or `watermark` back into its content as an image block. */
151
- export function prepareImageToContent(document, slideIndex, source, options = {}) {
152
- slideParts(document, `slides.${slideIndex}`, "a slide");
153
- return slideAction(document, slideIndex, (slide) => demoteImage(slide, source, options), undefined, options.validate !== false);
152
+ export function prepareImageToContent(presentation, slideIndex, source, options = {}) {
153
+ slideParts(presentation, `slides.${slideIndex}`, "a slide");
154
+ return slideAction(presentation, slideIndex, (slide) => demoteImage(slide, source, options), undefined, options.validate !== false);
154
155
  }
155
156
 
156
- export const groupBlocks = (editor, containerPath, indices, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareGroupBlocks(editor.document, containerPath, indices, options), meta, "group-blocks"));
157
- export const ungroupBlock = (editor, groupPath, meta = {}) => (requireEditor(editor), apply(editor, prepareUngroupBlock(editor.document, groupPath), meta, "ungroup-block"));
158
- export const placeBlocksInRegions = (editor, slideIndex, regions, meta = {}) => (requireEditor(editor), apply(editor, prepareBlocksToRegions(editor.document, slideIndex, regions), meta, "blocks-to-regions"));
159
- export const regionsAsBlocks = (editor, slideIndex, meta = {}) => (requireEditor(editor), apply(editor, prepareRegionsToBlocks(editor.document, slideIndex), meta, "regions-to-blocks"));
160
- export const moveSlideRegion = (editor, slideIndex, from, to, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareMoveRegion(editor.document, slideIndex, from, to, options), meta, "move-region"));
161
- export const moveImageToDesign = (editor, blockPath, target, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareImageToDesign(editor.document, blockPath, target, options), meta, "image-to-design"));
162
- export const moveImageToContent = (editor, slideIndex, source, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareImageToContent(editor.document, slideIndex, source, options), meta, "image-to-content"));
157
+ export const groupBlocks = (editor, containerPath, indices, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareGroupBlocks(editor.presentation, containerPath, indices, options), meta, "group-blocks"));
158
+ export const ungroupBlock = (editor, groupPath, meta = {}) => (requireEditor(editor), apply(editor, prepareUngroupBlock(editor.presentation, groupPath), meta, "ungroup-block"));
159
+ export const placeBlocksInRegions = (editor, slideIndex, regions, meta = {}) => (requireEditor(editor), apply(editor, prepareBlocksToRegions(editor.presentation, slideIndex, regions), meta, "blocks-to-regions"));
160
+ export const regionsAsBlocks = (editor, slideIndex, meta = {}) => (requireEditor(editor), apply(editor, prepareRegionsToBlocks(editor.presentation, slideIndex), meta, "regions-to-blocks"));
161
+ export const moveSlideRegion = (editor, slideIndex, from, to, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareMoveRegion(editor.presentation, slideIndex, from, to, options), meta, "move-region"));
162
+ export const moveImageToDesign = (editor, blockPath, target, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareImageToDesign(editor.presentation, blockPath, target, options), meta, "image-to-design"));
163
+ export const moveImageToContent = (editor, slideIndex, source, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareImageToContent(editor.presentation, slideIndex, source, options), meta, "image-to-content"));
163
164
 
164
165
  // --- slides ------------------------------------------------------------------------------------
165
166
 
@@ -168,8 +169,8 @@ export const moveImageToContent = (editor, slideIndex, source, options = {}, met
168
169
  * replaced slide, a `replace` for each one that changed, `remove` for the surplus old slides and `add` for the
169
170
  * surplus new ones, so a split or merge stays one guarded, undoable transaction without rewriting the other slides.
170
171
  */
171
- function slidePatches(document, range, slides) {
172
- const old = document.slides.slice(range.start, range.start + range.deleteCount);
172
+ function slidePatches(presentation, range, slides) {
173
+ const old = presentation.slides.slice(range.start, range.start + range.deleteCount);
173
174
  const patches = old.map((slide, offset) => ({ op: "test", path: `/slides/${range.start + offset}`, value: structuredClone(slide) }));
174
175
  const common = Math.min(old.length, slides.length);
175
176
  for (let offset = 0; offset < common; offset++) if (JSON.stringify(old[offset]) !== JSON.stringify(slides[offset])) patches.push({ op: "replace", path: `/slides/${range.start + offset}`, value: structuredClone(slides[offset]) });
@@ -177,31 +178,31 @@ function slidePatches(document, range, slides) {
177
178
  for (let offset = common; offset < slides.length; offset++) patches.push({ op: "add", path: `/slides/${range.start + offset}`, value: structuredClone(slides[offset]) });
178
179
  return patches;
179
180
  }
180
- function slidesAction(document, result, extra = {}) {
181
+ function slidesAction(presentation, result, extra = {}) {
181
182
  const path = `slides.${result.range.start}`;
182
- if (!result.changed) return unchanged(document, path, "Nothing to change.");
183
- return finish(document, slidePatches(document, result.range, result.slides), { path, changed: true, lossless: result.lossless, loss: result.loss, range: result.range, slideCount: result.slides.length, ...extra });
183
+ if (!result.changed) return unchanged(presentation, path, "Nothing to change.");
184
+ return finish(presentation, slidePatches(presentation, result.range, result.slides), { path, changed: true, lossless: result.lossless, loss: result.loss, range: result.range, slideCount: result.slides.length, ...extra });
184
185
  }
185
186
 
186
187
  /** Split a slide by its blocks (`options.at`: block indexes where a new slide starts, or `options.each`). See core's `splitSlide`. */
187
- export function prepareSplitSlide(document, slideIndex, options = {}) {
188
- return slidesAction(document, core(() => splitSlide(document, slideIndex, options)));
188
+ export function prepareSplitSlide(presentation, slideIndex, options = {}) {
189
+ return slidesAction(presentation, core(() => splitSlide(presentation, slideIndex, options)));
189
190
  }
190
- /** Split a slide that overflows into pages with the existing pagination (`options`: text measurement, fonts, as for `paginatePresentation`). `pages` maps the new slides back for `prepareUnpaginate`. */
191
- export function prepareSplitSlideOnOverflow(document, slideIndex, options = {}) {
192
- const result = core(() => splitSlideOnOverflowCore(document, slideIndex, options));
193
- return slidesAction(document, result, { pages: result.pages });
191
+ /** Split a slide that overflows into pages with the existing pagination (`options`: text measurement, fonts, as for core `paginate`). `pages` maps the new slides back for `prepareUnpaginate`. */
192
+ export function prepareSplitSlideOnOverflow(presentation, slideIndex, options = {}) {
193
+ const result = core(() => splitSlideOnOverflowCore(presentation, slideIndex, options));
194
+ return slidesAction(presentation, result, { pages: result.pages });
194
195
  }
195
196
  /** Merge `count` consecutive slides from `start`. The first slide's id, headings and design win; what is dropped is reported in `loss`. */
196
- export function prepareMergeSlides(document, start, count = 2) {
197
- return slidesAction(document, core(() => mergeSlidesCore(document, start, count)));
197
+ export function prepareMergeSlides(presentation, start, count = 2) {
198
+ return slidesAction(presentation, core(() => mergeSlidesCore(presentation, start, count)));
198
199
  }
199
- /** Put the continuation slides of a pagination back into one slide each. `pages` is the mapping `splitSlideOnOverflow` or `paginatePresentation` returned. */
200
- export function prepareUnpaginate(document, pages, options = {}) {
201
- return slidesAction(document, core(() => unpaginate(document, pages, options)));
200
+ /** Put the continuation slides of a pagination back into one slide each. `pages` is the mapping `splitSlideOnOverflow` or core `paginate` returned. */
201
+ export function prepareUnpaginate(presentation, pages, options = {}) {
202
+ return slidesAction(presentation, core(() => unpaginate(presentation, pages, options)));
202
203
  }
203
204
 
204
- export const splitSlideByBlocks = (editor, slideIndex, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareSplitSlide(editor.document, slideIndex, options), meta, "split-slide"));
205
- export const splitSlideOnOverflow = (editor, slideIndex, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareSplitSlideOnOverflow(editor.document, slideIndex, options), meta, "split-slide-overflow"));
206
- export const mergeSlides = (editor, start, count = 2, meta = {}) => (requireEditor(editor), apply(editor, prepareMergeSlides(editor.document, start, count), meta, "merge-slides"));
207
- export const unpaginateSlides = (editor, pages, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareUnpaginate(editor.document, pages, options), meta, "unpaginate-slides"));
205
+ export const splitSlideByBlocks = (editor, slideIndex, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareSplitSlide(editor.presentation, slideIndex, options), meta, "split-slide"));
206
+ export const splitSlideOnOverflow = (editor, slideIndex, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareSplitSlideOnOverflow(editor.presentation, slideIndex, options), meta, "split-slide-overflow"));
207
+ export const mergeSlides = (editor, start, count = 2, meta = {}) => (requireEditor(editor), apply(editor, prepareMergeSlides(editor.presentation, start, count), meta, "merge-slides"));
208
+ export const unpaginateSlides = (editor, pages, options = {}, meta = {}) => (requireEditor(editor), apply(editor, prepareUnpaginate(editor.presentation, pages, options), meta, "unpaginate-slides"));
@@ -104,7 +104,7 @@ export function createContentControls(ctx) {
104
104
  const prepare = (delta) => (state) => {
105
105
  const item = index(state);
106
106
  if (item === undefined) return { changed: false, loss: [], reason: "Select a list item to change its level." };
107
- return prepareListShift(editor.document, state.blockPath, [item], delta, { validate: false });
107
+ return prepareListShift(editor.presentation, state.blockPath, [item], delta, { validate: false });
108
108
  };
109
109
  const apply = (delta) => () => {
110
110
  const state = ctxState.current;
@@ -140,7 +140,7 @@ export function createContentControls(ctx) {
140
140
  updaters.push((state) => {
141
141
  metrics.wrap.hidden = !state.metricGroupPath;
142
142
  if (!state.metricGroupPath) return;
143
- const targets = blockConversionTargets(editor.document, state.metricGroupPath);
143
+ const targets = blockConversionTargets(editor.presentation, state.metricGroupPath);
144
144
  metrics.setOptions(
145
145
  targets.map((target) => ({
146
146
  value: target.kind,
@@ -172,7 +172,7 @@ export function createContentControls(ctx) {
172
172
  prepare: (state) => {
173
173
  const indices = next(state);
174
174
  if (!indices) return { changed: false, loss: [], reason: "There is no block after this one in its container." };
175
- return prepareGroupBlocks(editor.document, containerPath(state), indices, { validate: false });
175
+ return prepareGroupBlocks(editor.presentation, containerPath(state), indices, { validate: false });
176
176
  },
177
177
  apply: () => {
178
178
  const state = ctxState.current;
@@ -190,7 +190,7 @@ export function createContentControls(ctx) {
190
190
  prepare: (state) => {
191
191
  const path = parentGroup(state);
192
192
  if (!path) return { changed: false, loss: [], reason: "This block is not inside a group." };
193
- return prepareUngroupBlock(editor.document, path, { validate: false });
193
+ return prepareUngroupBlock(editor.presentation, path, { validate: false });
194
194
  },
195
195
  apply: () => ungroupBlock(editor, parentGroup(ctxState.current)),
196
196
  selectAfter: (change) => change.path,
@@ -222,7 +222,7 @@ export function createContentControls(ctx) {
222
222
  image.setOptions(
223
223
  IMAGE_DESTINATIONS.map((entry) => {
224
224
  try {
225
- const prepared = prepareImageToDesign(editor.document, state.blockPath, entry.target, { ...entry.options, validate: false });
225
+ const prepared = prepareImageToDesign(editor.presentation, state.blockPath, entry.target, { ...entry.options, validate: false });
226
226
  return { value: entry.value, label: `${entry.label}${prepared.loss.length ? ` (loses ${prepared.loss.join(", ")})` : ""}` };
227
227
  } catch (error) {
228
228
  return { value: entry.value, label: `${entry.label} (unavailable)`, disabled: true, title: messageOf(error) };
@@ -251,21 +251,21 @@ export function createContentControls(ctx) {
251
251
  });
252
252
  const toBlocks = action("Turn regions into blocks", {
253
253
  role: "regions-to-blocks",
254
- prepare: () => prepareRegionsToBlocks(editor.document, getSlide(), { validate: false }),
254
+ prepare: () => prepareRegionsToBlocks(editor.presentation, getSlide(), { validate: false }),
255
255
  apply: () => regionsAsBlocks(editor, getSlide()),
256
256
  done: "Regions are now blocks, in reading order.",
257
257
  });
258
258
  const designImages = Object.keys(DESIGN_IMAGE_LABELS).map((source) =>
259
259
  action(`Move the ${DESIGN_IMAGE_LABELS[source]} into the content`, {
260
260
  role: `back-${source}`,
261
- prepare: () => prepareImageToContent(editor.document, getSlide(), source, { validate: false }),
261
+ prepare: () => prepareImageToContent(editor.presentation, getSlide(), source, { validate: false }),
262
262
  apply: () => moveImageToContent(editor, getSlide(), source),
263
263
  done: `The ${DESIGN_IMAGE_LABELS[source]} is now an image block.`,
264
264
  }),
265
265
  );
266
266
  slideBox.append(layouts.wrap, toBlocks.wrap, ...designImages.map((entry) => entry.wrap));
267
267
  updaters.push((state) => {
268
- const slide = editor.document.slides?.[state.slideIndex];
268
+ const slide = editor.presentation.slides?.[state.slideIndex];
269
269
  if (!slide) return;
270
270
  const regions = regionKeysOfSlide(slide);
271
271
  const count = blockCount(state.slideIndex);
@@ -275,7 +275,7 @@ export function createContentControls(ctx) {
275
275
  layouts.setOptions(
276
276
  choices.map((choice) => {
277
277
  try {
278
- const prepared = prepareBlocksToRegions(editor.document, state.slideIndex, choice.regions, { validate: false });
278
+ const prepared = prepareBlocksToRegions(editor.presentation, state.slideIndex, choice.regions, { validate: false });
279
279
  return { value: choice.id, label: `${choice.label}${prepared.loss.length ? ` (loses ${prepared.loss.join(", ")})` : ""}` };
280
280
  } catch (error) {
281
281
  return { value: choice.id, label: `${choice.label} (unavailable)`, disabled: true, title: messageOf(error) };
@@ -296,7 +296,7 @@ export function createContentControls(ctx) {
296
296
 
297
297
  /** The number of blocks a slide can place in regions: its `blocks`, or the content fields it holds inline. */
298
298
  function blockCount(slideIndex) {
299
- const slide = editor.document.slides?.[slideIndex];
299
+ const slide = editor.presentation.slides?.[slideIndex];
300
300
  if (!slide) return 0;
301
301
  if (Array.isArray(slide.blocks)) return slide.blocks.length;
302
302
  return ["text", "items", "bullets", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"].filter((key) => slide[key] !== undefined).length;
@@ -309,9 +309,9 @@ export function createContentControls(ctx) {
309
309
  slideNode: slideBox,
310
310
  /** Update every control from the session and the current selection. */
311
311
  sync(state) {
312
- const slide = editor.document.slides?.[state.slideIndex];
312
+ const slide = editor.presentation.slides?.[state.slideIndex];
313
313
  const imageBlock = state.blockPath ? isImageBlock(editor, state.blockPath) : false;
314
- const full = { ...state, imageBlock, metricGroupPath: state.selectedPath ? metricGroupForSelection(editor.document, state.selectedPath) : undefined, slide };
314
+ const full = { ...state, imageBlock, metricGroupPath: state.selectedPath ? metricGroupForSelection(editor.presentation, state.selectedPath) : undefined, slide };
315
315
  ctxState.current = full;
316
316
  for (const update of updaters) update(full);
317
317
  },