@openpresentation/opf-editor 0.14.2 → 0.16.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/README.md +93 -35
- package/dist/assets.js +1 -1
- package/dist/background-options.d.ts +10 -3
- package/dist/background-options.js +38 -13
- package/dist/canvas.d.ts +8 -1
- package/dist/canvas.js +25 -10
- package/dist/catalog-control.js +21 -0
- package/dist/catalogs.d.ts +48 -0
- package/dist/catalogs.js +217 -0
- package/dist/checks.js +9 -7
- package/dist/content-actions.d.ts +2 -2
- package/dist/content-actions.js +3 -3
- package/dist/content-controls.js +9 -9
- package/dist/design-controls.d.ts +12 -5
- package/dist/design-controls.js +286 -82
- package/dist/design-options.d.ts +4 -4
- package/dist/design-options.js +6 -26
- package/dist/export.d.ts +8 -1
- package/dist/export.js +14 -4
- package/dist/find-replace.js +1 -0
- package/dist/font-gate.js +0 -11
- package/dist/galleries.js +32 -67
- package/dist/image-crop.js +8 -9
- package/dist/image-options.d.ts +45 -0
- package/dist/image-options.js +195 -0
- package/dist/index.d.ts +26 -8
- package/dist/index.js +107 -51
- package/dist/json-editor.js +2 -2
- package/dist/json-menu.js +2 -2
- package/dist/json-options.d.ts +3 -3
- package/dist/json-options.js +37 -47
- package/dist/layout-handles.js +13 -0
- package/dist/layout-placeholders.js +15 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +6 -2
- package/dist/review-panel.js +8 -2
- package/dist/schema-inspector.js +1 -1
- package/dist/schema.js +1 -1
- package/dist/slide-manager.js +4 -2
- package/dist/slides.d.ts +1 -1
- package/dist/slides.js +6 -5
- package/dist/svelte.d.ts +1 -0
- package/dist/svelte.js +4 -4
- package/dist/switches.d.ts +31 -16
- package/dist/switches.js +194 -92
- package/dist/table-options.d.ts +6 -1
- package/dist/table-options.js +43 -0
- package/dist/transfer.d.ts +12 -1
- package/dist/transfer.js +87 -131
- package/package.json +22 -9
package/dist/review-panel.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// document state: every fix is an undoable edit through the editor session. Importing this module does not need a DOM;
|
|
7
7
|
// mounting does.
|
|
8
8
|
import { validate } from "@openpresentation/opf";
|
|
9
|
+
import { mergeCatalogs } from "./catalogs.js";
|
|
9
10
|
import {
|
|
10
11
|
applyReviewFix,
|
|
11
12
|
countFindings,
|
|
@@ -115,6 +116,11 @@ function summaryText(counts, scopeLabel) {
|
|
|
115
116
|
*/
|
|
116
117
|
export function createReviewPanel(container, options) {
|
|
117
118
|
const { editor, getSlideIndex, getValidateOptions, onGoTo, onFocusField, onStatus, onIgnoredChange, onChange, review } = options;
|
|
119
|
+
// Core resolves the deck's references with the session's registered catalogs (and any the host adds): the same list as the preview.
|
|
120
|
+
const validateOptions = () => {
|
|
121
|
+
const host = getValidateOptions?.(editor.presentation) ?? {};
|
|
122
|
+
return { ...host, catalogs: mergeCatalogs(editor.catalogs, host.catalogs) };
|
|
123
|
+
};
|
|
118
124
|
if (review !== undefined && typeof review !== "function") throw new TypeError("The Review panel's review hook must be a function (presentation, options) returning a FindingReport.");
|
|
119
125
|
if (!editor || typeof editor.subscribe !== "function") throw new Error("The Review panel needs an editor session created by createEditorSession.");
|
|
120
126
|
const doc = container.ownerDocument;
|
|
@@ -171,7 +177,7 @@ export function createReviewPanel(container, options) {
|
|
|
171
177
|
function validateNow() {
|
|
172
178
|
lastAuditError = undefined;
|
|
173
179
|
try {
|
|
174
|
-
coreReport = validate(editor.presentation,
|
|
180
|
+
coreReport = validate(editor.presentation, validateOptions());
|
|
175
181
|
} catch (error) {
|
|
176
182
|
coreReport = undefined;
|
|
177
183
|
lastAuditError = error;
|
|
@@ -204,7 +210,7 @@ export function createReviewPanel(container, options) {
|
|
|
204
210
|
if (!coreReport && !lastAuditError) validateNow();
|
|
205
211
|
renderList();
|
|
206
212
|
try {
|
|
207
|
-
const result = await review(editor.presentation, { signal: controller.signal, report: coreReport, validateOptions:
|
|
213
|
+
const result = await review(editor.presentation, { signal: controller.signal, report: coreReport, validateOptions: validateOptions() });
|
|
208
214
|
if (destroyed || hookRunning !== running) return;
|
|
209
215
|
if (!result || !Array.isArray(result.findings)) throw new TypeError("The review hook must resolve a FindingReport ({ valid, findings, counts }).");
|
|
210
216
|
hookRunning = undefined;
|
package/dist/schema-inspector.js
CHANGED
|
@@ -18,7 +18,7 @@ export function createSchemaInspector(container, {editor,path='',onDraft,onCommi
|
|
|
18
18
|
function showError(message){errorBox.textContent=message;}
|
|
19
19
|
function check(){
|
|
20
20
|
// The draft must be valid OPF (the format category, as every edit); unresolved references (an unknown variable, a missing asset) are listed as notes.
|
|
21
|
-
const report=validate(draft,{only:['format','references']});
|
|
21
|
+
const report=validate(draft,{only:['format','references'],...(editor?.catalogs?.length?{catalogs:editor.catalogs}:{})});
|
|
22
22
|
const errors=report.findings.filter(finding=>finding.severity==='error'&&finding.category==='format'),warnings=report.findings.filter(finding=>finding.category!=='format'&&finding.severity!=='info');
|
|
23
23
|
const validation={valid:!errors.length};
|
|
24
24
|
apply.disabled=!dirty||!validation.valid;
|
package/dist/schema.js
CHANGED
|
@@ -69,7 +69,7 @@ export function schemaAtPath(presentation, path, root = schemas.presentation) {
|
|
|
69
69
|
const parts=splitOpfPath(path);let current=root,value=presentation;
|
|
70
70
|
for(let index=0; index<parts.length;index++) {
|
|
71
71
|
const key=parts[index], resolved=activeSchema(current,value,root);
|
|
72
|
-
if(parts[0]==='catalogs' && parts[2]
|
|
72
|
+
if(parts[0]==='catalogs' && index===3 && catalogSchemaNames[parts[2]]) current=schemas[catalogSchemaNames[parts[2]]]??{};
|
|
73
73
|
else current=Array.isArray(value)||resolved.type==='array' ? resolved.items??{} : resolved.properties?.[key] ?? Object.entries(resolved.patternProperties??{}).find(([pattern])=>new RegExp(pattern).test(key))?.[1] ?? (typeof resolved.additionalProperties==='object'?resolved.additionalProperties:{});
|
|
74
74
|
value=value?.[key];
|
|
75
75
|
}
|
package/dist/slide-manager.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
addSection, addSlide, duplicateSlides, hasSections, listSections, moveSection, moveSlides, moveSlidesBy, removeSection, removeSlides, renameSection, setHidden, setSection, slideTitle,
|
|
8
8
|
} from "./slides.js";
|
|
9
9
|
import { listSwitchOptions } from "./switches.js";
|
|
10
|
+
import { layoutSlotSummary } from "./layout-placeholders.js";
|
|
10
11
|
|
|
11
12
|
let instances = 0;
|
|
12
13
|
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
@@ -482,7 +483,7 @@ export function createSlideManager(container, options) {
|
|
|
482
483
|
});
|
|
483
484
|
}
|
|
484
485
|
function layoutChoices() {
|
|
485
|
-
return options.layoutOptions ? options.layoutOptions(deck()) : listSwitchOptions(deck(), "layouts");
|
|
486
|
+
return options.layoutOptions ? options.layoutOptions(deck()) : listSwitchOptions(deck(), "layouts", { catalogs: editor.catalogs });
|
|
486
487
|
}
|
|
487
488
|
function openLayoutPicker() {
|
|
488
489
|
const choices = layoutChoices();
|
|
@@ -503,7 +504,8 @@ export function createSlideManager(container, options) {
|
|
|
503
504
|
};
|
|
504
505
|
const describe = () => {
|
|
505
506
|
const choice = choices.find((entry) => entry.id === select.value);
|
|
506
|
-
|
|
507
|
+
// FA-26: nested placeholder groups show with their mode, for example `title, column (text, text), chart`.
|
|
508
|
+
const slots = layoutSlotSummary(choice?.record);
|
|
507
509
|
detail.textContent = choice ? `${choice.record?.description ?? ""}${slots ? ` Slots: ${slots}.` : choice.record?.placeholders ? " An empty slide." : ""}`.trim() : "No layout matches.";
|
|
508
510
|
};
|
|
509
511
|
const form = el("form", { method: "dialog" },
|
package/dist/slides.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export type MoveSectionMode = "adopt" | "keep" | string | null;
|
|
|
48
48
|
export interface AddSlideOptions {
|
|
49
49
|
/** The index the slide takes (default: the end). */
|
|
50
50
|
at?: number;
|
|
51
|
-
/** A
|
|
51
|
+
/** A layout reference (`id` or `name:id`); the layout's placeholders are added as empty slots. */
|
|
52
52
|
layout?: string;
|
|
53
53
|
title?: string;
|
|
54
54
|
text?: string;
|
package/dist/slides.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { checkedDocument, fail, same } from "./edit-helpers.js";
|
|
12
12
|
import { collectReservedPresentationIds, remapSlideTreeIds } from "./presentation-ids.js";
|
|
13
13
|
import { prepareDimensionSwitch } from "./switches.js";
|
|
14
|
+
import { mergeCatalogs } from "./catalogs.js";
|
|
14
15
|
import { checkFormat } from "./checks.js";
|
|
15
16
|
|
|
16
17
|
const isIndex = (value) => Number.isInteger(value) && value >= 0;
|
|
@@ -130,10 +131,10 @@ function newSlideId(presentation) {
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
/**
|
|
133
|
-
* Compute adding a slide. Options: `at` (the index the slide takes, default the end), `layout` (a
|
|
134
|
-
*
|
|
134
|
+
* Compute adding a slide. Options: `at` (the index the slide takes, default the end), `layout` (a layout
|
|
135
|
+
* reference, `id` or `name:id`; the layout's placeholders are added as empty slots, exactly like switching a slide's layout),
|
|
135
136
|
* `title`, `text`, `id`, `section` (default: the section of the slide before it), `slide` (a ready slide to
|
|
136
|
-
* insert, for hosts that build their own), `catalogs`/`record` for catalog lookup (as `prepareDimensionSwitch`).
|
|
137
|
+
* insert, for hosts that build their own), `catalogs`/`record`/`recordSource` for catalog lookup (as `prepareDimensionSwitch`).
|
|
137
138
|
*/
|
|
138
139
|
export function prepareAddSlide(presentation, options = {}) {
|
|
139
140
|
const slides = requireSlides(presentation);
|
|
@@ -153,7 +154,7 @@ export function prepareAddSlide(presentation, options = {}) {
|
|
|
153
154
|
// Switch the layout on a scratch copy to reuse the placeholder rules and the catalog lookup.
|
|
154
155
|
const scratch = { ...clone(presentation), slides: [...clone(slides)] };
|
|
155
156
|
scratch.slides.splice(at, 0, slide);
|
|
156
|
-
const switched = prepareDimensionSwitch(scratch, "layouts", options.layout, { slideIndex: at, catalogs: options.catalogs, record: options.record });
|
|
157
|
+
const switched = prepareDimensionSwitch(scratch, "layouts", options.layout, { slideIndex: at, catalogs: options.catalogs, record: options.record, recordSource: options.recordSource });
|
|
157
158
|
const catalogOps = switched.patches.filter((patch) => !patch.path.startsWith("/slides/"));
|
|
158
159
|
slide = switched.presentation.slides[at];
|
|
159
160
|
const patches = [...catalogOps, { op: "add", path: slidePointer(at), value: slide }];
|
|
@@ -164,7 +165,7 @@ export function prepareAddSlide(presentation, options = {}) {
|
|
|
164
165
|
/** Add a slide (see `prepareAddSlide`) as one undoable step. The change reports `index`, `id` and `selection`. */
|
|
165
166
|
export function addSlide(editor, options = {}, meta) {
|
|
166
167
|
requireEditor(editor);
|
|
167
|
-
return apply(editor, prepareAddSlide(editor.presentation, options), meta, "add");
|
|
168
|
+
return apply(editor, prepareAddSlide(editor.presentation, { ...options, catalogs: mergeCatalogs(editor.catalogs, options.catalogs) }), meta, "add");
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
// --- duplicate -------------------------------------------------------------------------------------
|
package/dist/svelte.d.ts
CHANGED
package/dist/svelte.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { commitCatalogControl } from "./catalog-control.js";
|
|
1
2
|
import {
|
|
2
3
|
createSvgTraceBinding,
|
|
3
4
|
getCatalogOptions,
|
|
@@ -50,8 +51,8 @@ export function opfCatalogSelect(node, params) {
|
|
|
50
51
|
node.setAttribute?.("data-opf-catalog-kind", catalogKind);
|
|
51
52
|
if (label) node.setAttribute?.("aria-label", label);
|
|
52
53
|
replaceOptions(node, getCatalogOptions(catalogKind, {
|
|
54
|
+
editor,
|
|
53
55
|
catalogs: nextParams.catalogs,
|
|
54
|
-
catalogSources: nextParams.catalogSources,
|
|
55
56
|
presentation: nextParams.presentation ?? editor.presentation
|
|
56
57
|
}));
|
|
57
58
|
|
|
@@ -59,12 +60,11 @@ export function opfCatalogSelect(node, params) {
|
|
|
59
60
|
const value = editor.get(path);
|
|
60
61
|
node.value = value && typeof value === "object" ? value.id : value ?? "";
|
|
61
62
|
};
|
|
62
|
-
const onChange = () => setCatalogId(editor, path, catalogKind, node.value, {
|
|
63
|
+
const onChange = () => commitCatalogControl(node, nextParams.onError, sync, () => setCatalogId(editor, path, catalogKind, node.value, {
|
|
63
64
|
catalogs: nextParams.catalogs,
|
|
64
|
-
catalogSources: nextParams.catalogSources,
|
|
65
65
|
presentation: nextParams.presentation,
|
|
66
66
|
source: "svelte-catalog-select"
|
|
67
|
-
});
|
|
67
|
+
}));
|
|
68
68
|
const unsubscribe = editor.subscribe(sync);
|
|
69
69
|
|
|
70
70
|
node.addEventListener?.("change", onChange);
|
package/dist/switches.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { ConvertOptions } from "@openpresentation/opf/convert";
|
|
2
|
+
import type { Catalog } from "@openpresentation/opf";
|
|
2
3
|
import type { EditorChange, EditorSession, JsonPatchOperation } from "./index.js";
|
|
3
4
|
|
|
5
|
+
/** Display metadata for the engine vocabularies, in the shape of `catalogDisplay` (`@openpresentation/opf/catalog`): records by id, or a list of records with `id` (`bcp47` for a language). */
|
|
6
|
+
export interface SwitchVocabularies {
|
|
7
|
+
languages?: unknown;
|
|
8
|
+
chartTypes?: unknown;
|
|
9
|
+
socialPlatforms?: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
4
12
|
/** The schema's DimensionPreset values: the values of the slide-sizes switch. */
|
|
5
13
|
export declare const SLIDE_SIZE_PRESETS: readonly ["16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"];
|
|
6
14
|
export type SlideSizePreset = (typeof SLIDE_SIZE_PRESETS)[number];
|
|
@@ -29,14 +37,17 @@ export type SwitchDimension = (typeof SWITCH_DIMENSIONS)[number];
|
|
|
29
37
|
export interface DimensionSwitchOptions {
|
|
30
38
|
/** Required for layouts and charts; for design dimensions it scopes the switch to one slide (default: the deck). */
|
|
31
39
|
slideIndex?: number;
|
|
32
|
-
/** blocks: the complete block (`slides.0.blocks.1`) or one-payload slide/region to replace. charts: the block holding the chart (default: the slide's first chart). */
|
|
40
|
+
/** blocks: the complete block (`slides.0.blocks.1`) or one-payload slide/region to replace. charts: the block holding the chart (default: the slide's first chart). image-treatments: the image block. */
|
|
33
41
|
path?: string | string[];
|
|
34
|
-
/** A gallery item's catalog record,
|
|
42
|
+
/** A gallery item's catalog record, embedded in the same transaction (under the group of `recordSource`, else `custom`) when it is not embedded yet. */
|
|
35
43
|
record?: Record<string, unknown> & { id: string };
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
/** The catalog source of `record` (for example "https://www.pptx.gallery"). */
|
|
45
|
+
recordSource?: string;
|
|
46
|
+
/** Host catalogs (`Catalog[]`): references resolve in the document, then in these. */
|
|
47
|
+
catalogs?: readonly Catalog[];
|
|
48
|
+
/** Display metadata for languages, chart types and social platforms (labels in pickers). */
|
|
49
|
+
vocabularies?: SwitchVocabularies;
|
|
50
|
+
/** themes: the theme's own color scheme, font scheme and background (and, for the deck, dimensions) apply: overrides of those at the switched scope are removed; on a slide whose deck sets one, the theme's value is written on the slide (default true). */
|
|
40
51
|
bundle?: boolean;
|
|
41
52
|
/** Deck-scope design switches: remove slide-level values that would hide the switch. */
|
|
42
53
|
clearSlideOverrides?: boolean;
|
|
@@ -55,12 +66,11 @@ export interface DimensionSwitchOptions {
|
|
|
55
66
|
|
|
56
67
|
export type DimensionSwitchValue =
|
|
57
68
|
| null /* backgrounds: remove it */
|
|
58
|
-
| string /* slide-sizes: a SlideSizePreset. purposes: a catalog
|
|
59
|
-
| string[] /* audiences: catalog
|
|
69
|
+
| string /* slide-sizes: a SlideSizePreset. purposes: a catalog reference or free-form goal text. languages: a BCP-47 tag. Catalog dimensions: a reference, `id` or `name:id`. */
|
|
70
|
+
| string[] /* audiences: catalog references */
|
|
60
71
|
| { platform: string; handle: string }
|
|
61
72
|
| { header?: unknown; footer?: unknown }
|
|
62
|
-
|
|
|
63
|
-
| Record<string, unknown>;
|
|
73
|
+
| Record<string, unknown> /* image-treatments: fit, focus, aspectRatio, shape, cornerRadius, border, opacity, recolor, overlay, placement (null removes) */;
|
|
64
74
|
|
|
65
75
|
export interface PreparedDimensionSwitch {
|
|
66
76
|
dimension: SwitchDimension;
|
|
@@ -92,18 +102,23 @@ export declare function prepareDimensionSwitch(presentation: unknown, dimension:
|
|
|
92
102
|
export declare function switchDimension(editor: EditorSession, dimension: SwitchDimension, value: DimensionSwitchValue, options?: DimensionSwitchOptions): DimensionSwitchChange;
|
|
93
103
|
|
|
94
104
|
export interface SwitchOption {
|
|
105
|
+
/** The value to switch to: for a catalog dimension the reference, `id` or `name:id`. */
|
|
95
106
|
id: string;
|
|
96
107
|
label: string;
|
|
97
108
|
record?: Record<string, unknown>;
|
|
109
|
+
reference?: string;
|
|
110
|
+
group?: string;
|
|
111
|
+
source?: string;
|
|
112
|
+
origin?: "document" | "host";
|
|
98
113
|
}
|
|
99
114
|
export interface CompatibleChartType extends SwitchOption {
|
|
100
115
|
/** True for the chart's present type, which is always listed. */
|
|
101
116
|
current: boolean;
|
|
102
117
|
}
|
|
103
|
-
/** Values a picker can offer
|
|
104
|
-
export declare function listSwitchOptions(presentation: unknown, dimension: SwitchDimension, options?: Pick<DimensionSwitchOptions, "catalogs" | "
|
|
105
|
-
/** Chart types the chart's inline data can use as it is (data-shape compatibility
|
|
106
|
-
export declare function compatibleChartTypes(presentation: unknown, options?: Pick<DimensionSwitchOptions, "slideIndex" | "path" | "catalogs" | "
|
|
107
|
-
/** The value a dimension currently has: `{ value, scope }`, with the
|
|
108
|
-
export declare function currentSwitchValue(presentation: unknown, dimension: SwitchDimension, options?: Pick<DimensionSwitchOptions, "slideIndex" | "path" | "owner" | "index">): { value: unknown; scope: "deck" | "slide" | "block" };
|
|
118
|
+
/** Values a picker can offer: a catalog dimension lists core's `catalogRecords` (embedded records, then `catalogs`); `charts` and `socials` list core's vocabularies, `languages` core's `LANGUAGES` tags; `blocks` lists the content kinds and `slide-sizes` the presets. `purposes` lists the catalogs; any other goal text is also a valid switch value. */
|
|
119
|
+
export declare function listSwitchOptions(presentation: unknown, dimension: SwitchDimension, options?: Pick<DimensionSwitchOptions, "catalogs" | "vocabularies">): SwitchOption[];
|
|
120
|
+
/** Chart types the chart's inline data can use as it is (data-shape compatibility from `vocabularies.chartTypes`, not an engine-support claim). `path` or `slideIndex` picks the chart. */
|
|
121
|
+
export declare function compatibleChartTypes(presentation: unknown, options?: Pick<DimensionSwitchOptions, "slideIndex" | "path" | "catalogs" | "vocabularies">): CompatibleChartType[];
|
|
122
|
+
/** The value a dimension currently has: `{ value, scope }`, with the reference (`id` or `name:id`) for catalog dimensions. `slide-sizes` reads the deck's design.dimensions, else its theme's (a preset string, or the object for a custom size); `purposes` reads the goal text or Purpose id. */
|
|
123
|
+
export declare function currentSwitchValue(presentation: unknown, dimension: SwitchDimension, options?: Pick<DimensionSwitchOptions, "slideIndex" | "path" | "owner" | "index" | "catalogs">): { value: unknown; scope: "deck" | "slide" | "block" };
|
|
109
124
|
export { blockConversionTargets } from "./block-convert.js";
|