@openpresentation/opf 0.15.1 → 0.17.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 +19 -1
- package/dist/{catalog-refs-BSfGELpt.d.ts → catalog-refs-C4K4y-vh.d.ts} +1 -1
- package/dist/{catalog-schemas-CinPh5WA.d.ts → catalog-schemas-g7RFQBdc.d.ts} +1 -1
- package/dist/catalog.d.ts +2 -2
- package/dist/catalog.js +3 -23224
- package/dist/{chart-data-BnNqgnC-.d.ts → chart-data-DTxdRRT1.d.ts} +1 -1
- package/dist/{chunk-3JG4YXWF.js → chunk-BIC3SWPK.js} +12 -5
- package/dist/{chunk-O744SXXA.js → chunk-CW7GEAV3.js} +350 -141
- package/dist/{chunk-374R35TJ.js → chunk-ESRYBYLY.js} +1 -1
- package/dist/chunk-IPW5BS3X.js +973 -0
- package/dist/{chunk-3RKB4RDJ.js → chunk-IS5H5JKH.js} +4 -2
- package/dist/{chunk-TWQJLI6E.js → chunk-M4UR3NPN.js} +2 -2
- package/dist/chunk-N4EVOFEA.js +58 -0
- package/dist/{chunk-QDI75P2M.js → chunk-NLNYNBTS.js} +217 -20
- package/dist/{chunk-U4J75TRG.js → chunk-O263APNI.js} +5 -2
- package/dist/{chunk-UBFJ2QHH.js → chunk-O2CX5NEH.js} +36 -14
- package/dist/{chunk-5FTUIDUH.js → chunk-O3CVNJTL.js} +1 -1
- package/dist/{chunk-VGAOJEY7.js → chunk-PPROJP2E.js} +1 -1
- package/dist/{chunk-2CJPC4HI.js → chunk-RA64UQKI.js} +203 -53
- package/dist/chunk-TCD2FB2K.js +319 -0
- package/dist/chunk-WCG3THTD.js +23712 -0
- package/dist/chunk-WWYWFVOI.js +793 -0
- package/dist/{chunk-ZPU46TFA.js → chunk-YT7FMQER.js} +1 -1
- package/dist/{composition-D2tghM82.d.ts → composition-BbZ_9C-c.d.ts} +238 -139
- package/dist/composition.d.ts +3 -3
- package/dist/composition.js +1 -1
- package/dist/conversion-SBpTOwdg.d.ts +444 -0
- package/dist/convert.d.ts +4 -4
- package/dist/convert.js +7 -7
- package/dist/data.d.ts +28 -11
- package/dist/data.js +2 -2
- package/dist/deck-report-Bx3naFlF.d.ts +40 -0
- package/dist/deck.d.ts +47 -0
- package/dist/deck.js +12 -0
- package/dist/diff.d.ts +1 -1
- package/dist/diff.js +5 -5
- package/dist/docs.js +33 -27
- package/dist/examples.d.ts +1 -1
- package/dist/examples.js +3229 -985
- package/dist/{finding-CT_f_vbD.d.ts → finding-CDQ_wH8j.d.ts} +1 -1
- package/dist/format.js +2 -2
- package/dist/index.d.ts +43 -12
- package/dist/index.js +15 -805
- package/dist/markdown.d.ts +7 -8
- package/dist/markdown.js +7 -7
- package/dist/node-engine.d.ts +94 -0
- package/dist/node-engine.js +21 -0
- package/dist/node.d.ts +60 -0
- package/dist/node.js +54 -0
- package/dist/{pagination-wedbe7eq.d.ts → pagination-BhX4M48Y.d.ts} +21 -7
- package/dist/pagination.d.ts +4 -4
- package/dist/pagination.js +4 -4
- package/dist/patch.d.ts +1 -1
- package/dist/patch.js +4 -4
- package/dist/{presentation-CDKQVkyI.d.ts → presentation-fb8CZmRq.d.ts} +28 -83
- package/dist/repo-readme.js +1 -1
- package/dist/schemas.d.ts +14 -0
- package/dist/schemas.js +1 -1
- package/dist/spec/catalogs/layouts/business-model-canvas.json +66 -1
- package/dist/spec/catalogs/layouts/capability-map.json +53 -3
- package/dist/spec/catalogs/layouts/chart-2x.json +32 -8
- package/dist/spec/catalogs/layouts/chart-3x-bottom-vertical-title-left.json +16 -10
- package/dist/spec/catalogs/layouts/chart-3x-left-title-center.json +16 -10
- package/dist/spec/catalogs/layouts/chart-3x-left.json +16 -10
- package/dist/spec/catalogs/layouts/chart-3x-right-title-center.json +16 -10
- package/dist/spec/catalogs/layouts/chart-3x-right.json +16 -10
- package/dist/spec/catalogs/layouts/chart-3x-top-vertical-title-left.json +16 -10
- package/dist/spec/catalogs/layouts/chart-3x.json +48 -12
- package/dist/spec/catalogs/layouts/dashboard.json +37 -5
- package/dist/spec/catalogs/layouts/image-2x.json +32 -8
- package/dist/spec/catalogs/layouts/image-3x.json +48 -12
- package/dist/spec/catalogs/layouts/index.json +1 -1
- package/dist/spec/catalogs/layouts/kpi-scorecard.json +48 -3
- package/dist/spec/catalogs/layouts/logic-tree.json +69 -0
- package/dist/spec/catalogs/layouts/market-size.json +26 -2
- package/dist/spec/catalogs/layouts/org-chart.json +53 -6
- package/dist/spec/catalogs/manifest.json +3 -3
- package/dist/spec/schemas/layout.schema.json +172 -5
- package/dist/spec/schemas/opf.schema.json +27 -43
- package/dist/types.d.ts +10 -32
- package/dist/{validation-types-BOcY9GTs.d.ts → validation-types-iZbXfES6.d.ts} +19 -8
- package/dist/validator.d.ts +8 -8
- package/dist/validator.js +3 -3
- package/dist/yaml.d.ts +6 -6
- package/dist/yaml.js +8 -321
- package/package.json +38 -1
|
@@ -319,7 +319,6 @@ function visitContentPayloads(slide, slidePath, visit) {
|
|
|
319
319
|
|
|
320
320
|
// src/furniture-fields.ts
|
|
321
321
|
var DEFAULT_FURNITURE_DATE_FORMAT = "M/d/yyyy";
|
|
322
|
-
var DEFAULT_SLIDE_NUMBER_FORMAT = "{current}";
|
|
323
322
|
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
324
323
|
var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
325
324
|
var tokenWidths = { y: [1, 2, 4], M: [1, 2, 3, 4], d: [1, 2], E: [1, 2, 3, 4] };
|
|
@@ -407,21 +406,6 @@ function formatFurnitureDate(iso, pattern) {
|
|
|
407
406
|
}
|
|
408
407
|
return { text: text2 };
|
|
409
408
|
}
|
|
410
|
-
function formatSlideNumber(format, current, total) {
|
|
411
|
-
if (!format.includes("{current}")) return { error: "slideNumberFormat must contain {current}." };
|
|
412
|
-
if (format.includes("{total}") && total === void 0) return { error: "slideNumberFormat uses {total}, which needs the rendered slide count." };
|
|
413
|
-
let text2 = "";
|
|
414
|
-
const fields2 = [];
|
|
415
|
-
for (const piece of format.split(/(\{current\}|\{total\})/)) {
|
|
416
|
-
if (piece === "{current}") {
|
|
417
|
-
const value = String(current);
|
|
418
|
-
fields2.push({ type: "slideNumber", start: text2.length, end: text2.length + value.length });
|
|
419
|
-
text2 += value;
|
|
420
|
-
} else if (piece === "{total}") text2 += String(total);
|
|
421
|
-
else text2 += piece;
|
|
422
|
-
}
|
|
423
|
-
return { text: text2, fields: fields2 };
|
|
424
|
-
}
|
|
425
409
|
|
|
426
410
|
// src/deck-metadata.ts
|
|
427
411
|
function recordsOf(value) {
|
|
@@ -441,6 +425,111 @@ function primaryOrganization(presentation) {
|
|
|
441
425
|
return organizations.find((item) => item.role === "primary") ?? organizations[0];
|
|
442
426
|
}
|
|
443
427
|
|
|
428
|
+
// src/slide-variables.ts
|
|
429
|
+
var SLIDE_SCOPED_BUILTINS = ["slide.number", "slide.section", "deck.slideCount"];
|
|
430
|
+
function isSlideScopedBuiltin(name) {
|
|
431
|
+
return SLIDE_SCOPED_BUILTINS.includes(name);
|
|
432
|
+
}
|
|
433
|
+
function isSlideScopedName(name) {
|
|
434
|
+
return name === "deck.slideCount" || name.startsWith("slide.");
|
|
435
|
+
}
|
|
436
|
+
var SLIDE_TOKEN_BODY = String.raw`\s*(?:slide(?:\.[A-Za-z0-9_-]+){1,2}|deck\.slideCount)\s*(?:\|[^{}]*)?\}\}`;
|
|
437
|
+
var slideTokenAhead = new RegExp(`^${SLIDE_TOKEN_BODY}`);
|
|
438
|
+
var slideTokenPattern = new RegExp(String.raw`\\\{\{(?=${SLIDE_TOKEN_BODY})|\{\{\s*(slide\.number|slide\.section|deck\.slideCount)\s*(?:\|[^{}]*)?\}\}`, "g");
|
|
439
|
+
var slideTokenSpanPattern = new RegExp(String.raw`\\?\{\{${SLIDE_TOKEN_BODY}`, "g");
|
|
440
|
+
var quickCheck = /\{\{\s*(?:slide\.|deck\.slideCount)/;
|
|
441
|
+
function slideTokenFollows(text2) {
|
|
442
|
+
return slideTokenAhead.test(text2);
|
|
443
|
+
}
|
|
444
|
+
function checkValues(values) {
|
|
445
|
+
if (!isRecord(values)) throw new TypeError("Slide variable values must be an object with slideNumber and slideCount.");
|
|
446
|
+
if (!Number.isSafeInteger(values.slideNumber) || values.slideNumber < 1) throw new RangeError("slideNumber must be a positive safe integer.");
|
|
447
|
+
if (values.slideCount !== void 0 && (!Number.isSafeInteger(values.slideCount) || values.slideCount < 1)) throw new RangeError("slideCount must be a positive safe integer.");
|
|
448
|
+
}
|
|
449
|
+
function substituteSlideTokens(text2, values) {
|
|
450
|
+
if (!text2.includes("{{")) return { text: text2, fields: [], changed: false };
|
|
451
|
+
const fields2 = [];
|
|
452
|
+
let out = "";
|
|
453
|
+
let last = 0;
|
|
454
|
+
let changed = false;
|
|
455
|
+
slideTokenPattern.lastIndex = 0;
|
|
456
|
+
for (let match = slideTokenPattern.exec(text2); match; match = slideTokenPattern.exec(text2)) {
|
|
457
|
+
const name = match[1];
|
|
458
|
+
let value;
|
|
459
|
+
if (name === void 0) value = "{{";
|
|
460
|
+
else if (name === "slide.number") value = String(values.slideNumber);
|
|
461
|
+
else if (name === "deck.slideCount") {
|
|
462
|
+
if (values.slideCount === void 0) continue;
|
|
463
|
+
value = String(values.slideCount);
|
|
464
|
+
} else value = typeof values.section === "string" ? values.section : "";
|
|
465
|
+
out += text2.slice(last, match.index);
|
|
466
|
+
if (name === "slide.number") fields2.push({ type: "slideNumber", start: out.length, end: out.length + value.length });
|
|
467
|
+
out += value;
|
|
468
|
+
last = match.index + match[0].length;
|
|
469
|
+
changed = true;
|
|
470
|
+
}
|
|
471
|
+
if (!changed) return { text: text2, fields: fields2, changed };
|
|
472
|
+
return { text: out + text2.slice(last), fields: fields2, changed };
|
|
473
|
+
}
|
|
474
|
+
function slideTokenSpans(text2) {
|
|
475
|
+
if (!text2.includes("{{")) return [];
|
|
476
|
+
return Array.from(text2.matchAll(slideTokenSpanPattern), (match) => [match.index, match.index + match[0].length]);
|
|
477
|
+
}
|
|
478
|
+
var skippedKeys = /* @__PURE__ */ new Set(["extensions"]);
|
|
479
|
+
function substitute(value, values, root) {
|
|
480
|
+
if (typeof value === "string") {
|
|
481
|
+
const result = substituteSlideTokens(value, values);
|
|
482
|
+
return result.changed ? result.text : value;
|
|
483
|
+
}
|
|
484
|
+
if (Array.isArray(value)) {
|
|
485
|
+
let changed2 = false;
|
|
486
|
+
const out2 = value.map((entry) => {
|
|
487
|
+
const next = substitute(entry, values, false);
|
|
488
|
+
if (next !== entry) changed2 = true;
|
|
489
|
+
return next;
|
|
490
|
+
});
|
|
491
|
+
return changed2 ? out2 : value;
|
|
492
|
+
}
|
|
493
|
+
if (!isRecord(value)) return value;
|
|
494
|
+
let changed = false;
|
|
495
|
+
const out = {};
|
|
496
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
497
|
+
let next = entry;
|
|
498
|
+
if (skippedKeys.has(key)) next = entry;
|
|
499
|
+
else if (root && key === "design" && isRecord(entry)) {
|
|
500
|
+
const design = {};
|
|
501
|
+
let designChanged = false;
|
|
502
|
+
for (const [designKey, designEntry] of Object.entries(entry)) {
|
|
503
|
+
const designNext = designKey === "header" || designKey === "footer" ? designEntry : substitute(designEntry, values, false);
|
|
504
|
+
if (designNext !== designEntry) designChanged = true;
|
|
505
|
+
design[designKey] = designNext;
|
|
506
|
+
}
|
|
507
|
+
next = designChanged ? design : entry;
|
|
508
|
+
} else next = substitute(entry, values, false);
|
|
509
|
+
if (next !== entry) changed = true;
|
|
510
|
+
out[key] = next;
|
|
511
|
+
}
|
|
512
|
+
return changed ? out : value;
|
|
513
|
+
}
|
|
514
|
+
function resolveSlideVariables(slide, values) {
|
|
515
|
+
if (!isRecord(slide)) return slide;
|
|
516
|
+
const full = { slideNumber: values?.slideNumber, ...values?.slideCount !== void 0 ? { slideCount: values.slideCount } : {}, section: slide.section };
|
|
517
|
+
checkValues(full);
|
|
518
|
+
if (!quickCheck.test(JSON.stringify(slide))) return slide;
|
|
519
|
+
return substitute(slide, full, true);
|
|
520
|
+
}
|
|
521
|
+
function usesSlideBuiltin(value, name) {
|
|
522
|
+
const pattern = new RegExp(String.raw`(?:^|[^\\])\{\{\s*${name.replace(".", String.raw`\.`)}\s*(?:\|[^{}]*)?\}\}`);
|
|
523
|
+
const visit = (entry) => {
|
|
524
|
+
if (typeof entry === "string") return entry.includes("{{") && pattern.test(entry);
|
|
525
|
+
if (Array.isArray(entry)) return entry.some(visit);
|
|
526
|
+
if (!isRecord(entry)) return false;
|
|
527
|
+
for (const [key, child] of Object.entries(entry)) if (!skippedKeys.has(key) && visit(child)) return true;
|
|
528
|
+
return false;
|
|
529
|
+
};
|
|
530
|
+
return visit(value);
|
|
531
|
+
}
|
|
532
|
+
|
|
444
533
|
// src/variables.ts
|
|
445
534
|
var VARIABLE_KINDS = ["color", "text", "number", "date", "image", "url", "list"];
|
|
446
535
|
var DEFAULT_VARIABLE_DATE_FORMAT = "MMMM d, yyyy";
|
|
@@ -454,10 +543,10 @@ var OPFVariableError = class extends Error {
|
|
|
454
543
|
}
|
|
455
544
|
};
|
|
456
545
|
var idPattern = /^[a-z][a-z0-9-]*$/;
|
|
457
|
-
var nameSource = String.raw`[a-z][a-z0-9-]*|(?:deck|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2}`;
|
|
546
|
+
var nameSource = String.raw`[a-z][a-z0-9-]*|(?:deck|speaker|organization|slide)(?:\.[A-Za-z0-9_-]+){1,2}`;
|
|
458
547
|
var referencePattern = new RegExp(String.raw`^var:(${nameSource})$`);
|
|
459
|
-
var builtinNamePattern = /^(?:speakers|(?:deck|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2})$/;
|
|
460
|
-
var builtinUsePattern = /\{\{\s*(?:speakers\b|(?:deck|speaker|organization)\.)|^var:(?:speakers$|(?:deck|speaker|organization)\.)/;
|
|
548
|
+
var builtinNamePattern = /^(?:speakers|(?:deck|speaker|organization|slide)(?:\.[A-Za-z0-9_-]+){1,2})$/;
|
|
549
|
+
var builtinUsePattern = /\{\{\s*(?:speakers\b|(?:deck|speaker|organization|slide)\.)|^var:(?:speakers$|(?:deck|speaker|organization|slide)\.)/;
|
|
461
550
|
var hexPattern = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
462
551
|
var urlPattern = /^(?:https?:\/\/|mailto:|tel:)\S+$/;
|
|
463
552
|
var datePrefixPattern = /^(\d{4}-\d{2}-\d{2})(?:[T ].*)?$/;
|
|
@@ -560,7 +649,7 @@ function usesBuiltins(value, root = true) {
|
|
|
560
649
|
if (Array.isArray(value)) return value.some((entry) => usesBuiltins(entry, false));
|
|
561
650
|
if (!isRecord(value)) return false;
|
|
562
651
|
for (const [key, entry] of Object.entries(value)) {
|
|
563
|
-
if (
|
|
652
|
+
if (skippedKeys2.has(key) || root && skippedRootKeys.has(key)) continue;
|
|
564
653
|
if (usesBuiltins(entry, false)) return true;
|
|
565
654
|
}
|
|
566
655
|
return false;
|
|
@@ -672,13 +761,17 @@ function builtinSource(name, doc) {
|
|
|
672
761
|
const names = speakersOf(doc).map((speaker) => present(speaker.name)).filter((entry) => typeof entry === "string");
|
|
673
762
|
return { ok: true, kind: "list", raw: names.length ? names : void 0 };
|
|
674
763
|
}
|
|
764
|
+
const list = (names) => names.map((entry) => `'${entry}'`).join(", ");
|
|
765
|
+
if (isSlideScopedName(name)) {
|
|
766
|
+
if (isSlideScopedBuiltin(name)) return { ok: false, message: `'var:${name}' is not supported: '${name}' is a slide-scoped built-in, written only as the inline token '{{${name}}}'.` };
|
|
767
|
+
return { ok: false, message: `'${name}' is not a built-in variable; the slide-scoped built-ins are ${list(SLIDE_SCOPED_BUILTINS)}.` };
|
|
768
|
+
}
|
|
675
769
|
const parts = name.split(".");
|
|
676
770
|
const root = parts[0];
|
|
677
771
|
const fields2 = builtinFields(root);
|
|
678
|
-
const list = (names) => names.map((entry) => `'${entry}'`).join(", ");
|
|
679
772
|
if (root === "deck") {
|
|
680
773
|
const field2 = parts[1];
|
|
681
|
-
if (parts.length !== 2 || !Object.hasOwn(fields2, field2)) return { ok: false, message: `'${name}' is not a built-in variable; the deck built-ins are ${list(Object.keys(fields2).map((key) => `deck.${key}`))}.` };
|
|
774
|
+
if (parts.length !== 2 || !Object.hasOwn(fields2, field2)) return { ok: false, message: `'${name}' is not a built-in variable; the deck built-ins are ${list(Object.keys(fields2).map((key) => `deck.${key}`))} and the slide-scoped 'deck.slideCount'.` };
|
|
682
775
|
const value = doc[field2];
|
|
683
776
|
return { ok: true, kind: "text", raw: field2 === "author" && Array.isArray(value) ? present(value.filter((entry) => typeof entry === "string").join(", ")) : present(value) };
|
|
684
777
|
}
|
|
@@ -742,15 +835,16 @@ function lookupVariable(id, path, context) {
|
|
|
742
835
|
}
|
|
743
836
|
function interpolate(text2, path, context) {
|
|
744
837
|
let changed = false;
|
|
745
|
-
const value = text2.replace(tokenPattern, (match, id, format) => {
|
|
838
|
+
const value = text2.replace(tokenPattern, (match, id, format, offset) => {
|
|
746
839
|
if (id === void 0) {
|
|
747
|
-
if (context.unescape) {
|
|
840
|
+
if (context.unescape && !slideTokenFollows(text2.slice(offset + match.length))) {
|
|
748
841
|
changed = true;
|
|
749
842
|
return "{{";
|
|
750
843
|
}
|
|
751
844
|
return match;
|
|
752
845
|
}
|
|
753
846
|
context.uses.push({ id, path, form: "token" });
|
|
847
|
+
if (isSlideScopedBuiltin(id)) return match;
|
|
754
848
|
const effective = lookupVariable(id, path, context);
|
|
755
849
|
if (!effective) {
|
|
756
850
|
if (!isBuiltinName(id)) diag(context, { code: "variable-unknown", severity: "warning", path, id, message: `'{{${id}}}' names no declared variable; declare '${id}' in the top-level variables map, or write '\\{{' for literal braces.` }, `unk:${id}:${path}`);
|
|
@@ -803,7 +897,7 @@ function reduceString(text2, path, parentIsArray, context) {
|
|
|
803
897
|
const result = interpolate(text2, path, context);
|
|
804
898
|
return result.changed ? { kind: "replace", value: result.value } : { kind: "keep" };
|
|
805
899
|
}
|
|
806
|
-
var
|
|
900
|
+
var skippedKeys2 = /* @__PURE__ */ new Set(["extensions"]);
|
|
807
901
|
var skippedRootKeys = /* @__PURE__ */ new Set(["variables", "catalogs", "$schema", "template"]);
|
|
808
902
|
function walk(value, path, parentIsArray, context) {
|
|
809
903
|
if (typeof value === "string") {
|
|
@@ -836,7 +930,7 @@ function walk(value, path, parentIsArray, context) {
|
|
|
836
930
|
let changed = false;
|
|
837
931
|
const entries = [];
|
|
838
932
|
for (const [key, entry] of Object.entries(value)) {
|
|
839
|
-
if (
|
|
933
|
+
if (skippedKeys2.has(key) || path === "" && skippedRootKeys.has(key)) {
|
|
840
934
|
entries.push([key, entry]);
|
|
841
935
|
continue;
|
|
842
936
|
}
|
|
@@ -940,6 +1034,21 @@ function rebuildVariables(presentation, built, keepAll) {
|
|
|
940
1034
|
}
|
|
941
1035
|
return out.length ? Object.fromEntries(out) : void 0;
|
|
942
1036
|
}
|
|
1037
|
+
function slideSectionDiagnostics(presentation, uses) {
|
|
1038
|
+
const paths = uses.filter((use) => use.id === "slide.section").map((use) => use.path);
|
|
1039
|
+
if (!paths.length || !Array.isArray(presentation.slides)) return [];
|
|
1040
|
+
const out = [];
|
|
1041
|
+
presentation.slides.forEach((slide, index) => {
|
|
1042
|
+
if (!isRecord(slide) || typeof slide.section === "string" && slide.section !== "") return;
|
|
1043
|
+
const own2 = `/slides/${index}/`;
|
|
1044
|
+
const design = isRecord(slide.design) ? slide.design : {};
|
|
1045
|
+
const inherited = ["header", "footer"].filter((kind2) => design[kind2] === void 0).map((kind2) => `/design/${kind2}/`);
|
|
1046
|
+
const where = paths.find((path) => path.startsWith(own2) || inherited.some((prefix) => path.startsWith(prefix)));
|
|
1047
|
+
if (where === void 0) return;
|
|
1048
|
+
out.push({ code: "variable-builtin-missing", severity: "warning", path: `/slides/${index}`, id: "slide.section", message: `Slide ${index + 1} has no section, so '{{slide.section}}' (used at ${where}) resolves to nothing on it; give the slide a section or remove the token.` });
|
|
1049
|
+
});
|
|
1050
|
+
return out;
|
|
1051
|
+
}
|
|
943
1052
|
function finish(presentation, built, options) {
|
|
944
1053
|
const { context } = built;
|
|
945
1054
|
const complete = built.unfilled.length === 0;
|
|
@@ -958,6 +1067,7 @@ function finish(presentation, built, options) {
|
|
|
958
1067
|
}
|
|
959
1068
|
}
|
|
960
1069
|
}
|
|
1070
|
+
if (context.shape) context.diagnostics.push(...slideSectionDiagnostics(presentation, context.uses));
|
|
961
1071
|
const diagnostics = context.diagnostics;
|
|
962
1072
|
if (options.strict && diagnostics.some((entry) => entry.severity === "error")) throw new OPFVariableError(diagnostics);
|
|
963
1073
|
return { presentation: result, diagnostics, unfilled: built.unfilled, examplesUsed: built.examplesUsed, complete };
|
|
@@ -991,6 +1101,7 @@ function listVariables(presentation, values = {}) {
|
|
|
991
1101
|
};
|
|
992
1102
|
});
|
|
993
1103
|
}
|
|
1104
|
+
var SLIDE_SCOPED_LABELS = { "slide.number": "Slide number", "slide.section": "Section", "deck.slideCount": "Slide count" };
|
|
994
1105
|
var FIELD_LABELS = { name: "name", legalName: "legal name", tagline: "tagline", domain: "domain", email: "email", phone: "phone", logo: "logo", title: "title", bio: "bio", photo: "photo", description: "description", author: "author" };
|
|
995
1106
|
function listBuiltinVariables(presentation) {
|
|
996
1107
|
if (!isRecord(presentation)) return [];
|
|
@@ -1013,7 +1124,12 @@ function listBuiltinVariables(presentation) {
|
|
|
1013
1124
|
const source = builtinSource(name, presentation);
|
|
1014
1125
|
if (!source.ok) continue;
|
|
1015
1126
|
const coerced = source.raw === void 0 ? void 0 : coerceVariableValue(source.kind, source.raw);
|
|
1016
|
-
out.push({ name, kind: source.kind, label, ...coerced?.ok ? { value: coerced.value } : {}, available: coerced?.ok === true, uses: built.context.uses.filter((use) => use.id === name) });
|
|
1127
|
+
out.push({ name, kind: source.kind, label, scope: "deck", ...coerced?.ok ? { value: coerced.value } : {}, available: coerced?.ok === true, uses: built.context.uses.filter((use) => use.id === name) });
|
|
1128
|
+
}
|
|
1129
|
+
const slides = Array.isArray(presentation.slides) ? presentation.slides : [];
|
|
1130
|
+
for (const name of SLIDE_SCOPED_BUILTINS) {
|
|
1131
|
+
const available = name !== "slide.section" || slides.some((slide) => isRecord(slide) && typeof slide.section === "string" && slide.section !== "");
|
|
1132
|
+
out.push({ name, kind: "text", label: SLIDE_SCOPED_LABELS[name], scope: "slide", available, uses: built.context.uses.filter((use) => use.id === name) });
|
|
1017
1133
|
}
|
|
1018
1134
|
return out;
|
|
1019
1135
|
}
|
|
@@ -1771,6 +1887,75 @@ function readingRows(items) {
|
|
|
1771
1887
|
return rows3.map((row) => row.items.sort((a, b) => index.get(a) - index.get(b)));
|
|
1772
1888
|
}
|
|
1773
1889
|
|
|
1890
|
+
// src/layout-content.ts
|
|
1891
|
+
var LAYOUT_BODY_KINDS = ["text", "list", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
|
|
1892
|
+
var MAX_PLACEHOLDER_GROUP_DEPTH = 3;
|
|
1893
|
+
var bodyKinds = new Set(LAYOUT_BODY_KINDS);
|
|
1894
|
+
var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1895
|
+
function isPlaceholderGroup(placeholder) {
|
|
1896
|
+
return record4(placeholder).type === "group";
|
|
1897
|
+
}
|
|
1898
|
+
function layoutSlots(layout, base = "layout.placeholders") {
|
|
1899
|
+
const walk2 = (entries, path, depth) => (Array.isArray(entries) ? entries : []).map((entry, index) => {
|
|
1900
|
+
const placeholder = record4(entry), slotPath = `${path}.${index}`;
|
|
1901
|
+
const type = typeof placeholder.type === "string" ? placeholder.type : "";
|
|
1902
|
+
if (type !== "group") {
|
|
1903
|
+
if (depth > 0 && !bodyKinds.has(type)) throw new RangeError(`${slotPath}: a placeholder group holds body regions only, not '${type}'.`);
|
|
1904
|
+
return { type, path: slotPath, depth, placeholder };
|
|
1905
|
+
}
|
|
1906
|
+
if (depth >= MAX_PLACEHOLDER_GROUP_DEPTH) throw new RangeError(`${slotPath}: placeholder groups nest at most ${MAX_PLACEHOLDER_GROUP_DEPTH} levels inside a layout record.`);
|
|
1907
|
+
if (!Array.isArray(placeholder.placeholders) || !placeholder.placeholders.length) throw new RangeError(`${slotPath}: a placeholder group needs at least one placeholder.`);
|
|
1908
|
+
return { type, path: slotPath, depth, placeholder, children: walk2(placeholder.placeholders, `${slotPath}.placeholders`, depth + 1) };
|
|
1909
|
+
});
|
|
1910
|
+
return walk2(layout?.placeholders, base, 0);
|
|
1911
|
+
}
|
|
1912
|
+
function layoutLeaves(layout) {
|
|
1913
|
+
const leaves = [];
|
|
1914
|
+
const visit = (slots) => {
|
|
1915
|
+
for (const slot of slots) slot.children ? visit(slot.children) : leaves.push({ type: slot.type, path: slot.path, depth: slot.depth, placeholder: slot.placeholder });
|
|
1916
|
+
};
|
|
1917
|
+
visit(layoutSlots(layout));
|
|
1918
|
+
return leaves;
|
|
1919
|
+
}
|
|
1920
|
+
function layoutStructure(layout) {
|
|
1921
|
+
const describe = (slots) => slots.map((slot) => {
|
|
1922
|
+
if (!slot.children) return slot.type;
|
|
1923
|
+
const mode = record4(slot.placeholder.composition).mode;
|
|
1924
|
+
return `${typeof mode === "string" && mode !== "auto" ? mode : "group"} (${describe(slot.children)})`;
|
|
1925
|
+
}).join(", ");
|
|
1926
|
+
return describe(layoutSlots(layout));
|
|
1927
|
+
}
|
|
1928
|
+
function hasPlaceholderGroups(layout) {
|
|
1929
|
+
return Array.isArray(layout?.placeholders) && layout.placeholders.some(isPlaceholderGroup);
|
|
1930
|
+
}
|
|
1931
|
+
function layoutContent(layout) {
|
|
1932
|
+
const heading = { title: false, subtitle: false, tag: false };
|
|
1933
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1934
|
+
let count = 0;
|
|
1935
|
+
const visit = (entries, depth) => {
|
|
1936
|
+
for (const entry of Array.isArray(entries) ? entries : []) {
|
|
1937
|
+
const type = record4(entry).type;
|
|
1938
|
+
if (type === "group") {
|
|
1939
|
+
if (depth < MAX_PLACEHOLDER_GROUP_DEPTH) visit(record4(entry).placeholders, depth + 1);
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
if (type === "title" || type === "subtitle" || type === "tag") {
|
|
1943
|
+
if (depth === 0) heading[type] = true;
|
|
1944
|
+
} else if (typeof type === "string" && bodyKinds.has(type)) {
|
|
1945
|
+
counts.set(type, (counts.get(type) ?? 0) + 1);
|
|
1946
|
+
count += 1;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
};
|
|
1950
|
+
visit(layout?.placeholders, 0);
|
|
1951
|
+
let kind2 = "title", best = 0;
|
|
1952
|
+
for (const [candidate, total] of counts) if (total > best) {
|
|
1953
|
+
kind2 = candidate;
|
|
1954
|
+
best = total;
|
|
1955
|
+
}
|
|
1956
|
+
return { kind: kind2, count, heading };
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1774
1959
|
// src/direction.ts
|
|
1775
1960
|
var strongRtl = /[\u200F\u061C]|(?=\p{L})[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Adlam}\p{Script=Hanifi_Rohingya}\p{Script=Mandaic}\p{Script=Samaritan}\p{Script=Mende_Kikakui}\p{Script=Imperial_Aramaic}\p{Script=Phoenician}\p{Script=Kharoshthi}\p{Script=Old_South_Arabian}\p{Script=Old_North_Arabian}\p{Script=Avestan}\p{Script=Inscriptional_Parthian}\p{Script=Inscriptional_Pahlavi}\p{Script=Psalter_Pahlavi}\p{Script=Old_Turkic}\p{Script=Old_Hungarian}\p{Script=Nabataean}\p{Script=Palmyrene}\p{Script=Hatran}\p{Script=Manichaean}\p{Script=Sogdian}\p{Script=Old_Sogdian}\p{Script=Elymaic}\p{Script=Chorasmian}\p{Script=Yezidi}\p{Script=Cypriot}\p{Script=Lydian}\p{Script=Meroitic_Cursive}\p{Script=Meroitic_Hieroglyphs}\u{10F70}-\u{10FAF}\u{10D40}-\u{10D8F}]/u;
|
|
1776
1961
|
var strongLtr = /[\u200E\p{L}\p{Nl}]/u;
|
|
@@ -3283,8 +3468,8 @@ function codeSyntaxPalette(theme = {}, options = {}) {
|
|
|
3283
3468
|
return palette;
|
|
3284
3469
|
}
|
|
3285
3470
|
function codeSyntaxPaletteForScheme(scheme, options = {}) {
|
|
3286
|
-
const
|
|
3287
|
-
const pick = (role, slot, fallback) => normalize(
|
|
3471
|
+
const record7 = scheme && typeof scheme === "object" ? scheme : {};
|
|
3472
|
+
const pick = (role, slot, fallback) => normalize(record7[role]) ?? normalize(record7[slot]) ?? fallback;
|
|
3288
3473
|
return codeSyntaxPalette({ primary: pick("primary", "accent1", "#2563EB"), secondary: pick("secondary", "accent2", "#0F766E"), accent: pick("accent", "accent3", "#F59E0B") }, options);
|
|
3289
3474
|
}
|
|
3290
3475
|
|
|
@@ -3436,8 +3621,8 @@ var blend = (from, to, amount) => {
|
|
|
3436
3621
|
return toHex(a.map((value, index) => value + (b[index] - value) * amount));
|
|
3437
3622
|
};
|
|
3438
3623
|
function codeHighlightColors(scheme, palette = codeSyntaxPaletteForScheme(scheme)) {
|
|
3439
|
-
const
|
|
3440
|
-
const primary = normalize(
|
|
3624
|
+
const record7 = scheme && typeof scheme === "object" ? scheme : {};
|
|
3625
|
+
const primary = normalize(record7.primary) ?? normalize(record7.accent1) ?? "#2563EB";
|
|
3441
3626
|
const [hue, saturation] = toHsl(primary);
|
|
3442
3627
|
const tint = fromHsl(hue, Math.min(saturation, 0.7), 0.45);
|
|
3443
3628
|
const band = blend(CODE_PANEL_BACKGROUND, tint, CODE_HIGHLIGHT_BAND_TINT);
|
|
@@ -3634,7 +3819,7 @@ var CAPTION_FONT_RATIO = 0.6;
|
|
|
3634
3819
|
var CAPTION_MAX_RATIO = 0.35;
|
|
3635
3820
|
var FOOTNOTE_MAX_RATIO = 0.35;
|
|
3636
3821
|
var CAPTIONABLE_FIELDS = Object.freeze(["image", "chart", "table", "video"]);
|
|
3637
|
-
var
|
|
3822
|
+
var record5 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3638
3823
|
var isRecord3 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
3639
3824
|
var round = (value) => Math.round(value * 1e6) / 1e6 || value;
|
|
3640
3825
|
var regionKey = /^(top|middle|bottom|left|center|right)([+:]|$)/;
|
|
@@ -3642,7 +3827,7 @@ var TEXT_FIELDS = ["text", "items", "bullets"];
|
|
|
3642
3827
|
var HEADING_FIELDS = ["tag", "title", "subtitle"];
|
|
3643
3828
|
function annotationText(value) {
|
|
3644
3829
|
if (typeof value === "string") return value;
|
|
3645
|
-
if (Array.isArray(value)) return value.map((run) => typeof run === "string" ? run :
|
|
3830
|
+
if (Array.isArray(value)) return value.map((run) => typeof run === "string" ? run : record5(run).text ?? "").join("");
|
|
3646
3831
|
if (isRecord3(value) && value.text !== void 0) return annotationText(value.text);
|
|
3647
3832
|
return value === void 0 || value === null ? "" : String(value);
|
|
3648
3833
|
}
|
|
@@ -3674,7 +3859,7 @@ function walkCitationRuns(slide, basePath, visit) {
|
|
|
3674
3859
|
});
|
|
3675
3860
|
};
|
|
3676
3861
|
const host = (node, path, depth) => {
|
|
3677
|
-
const payload =
|
|
3862
|
+
const payload = record5(node);
|
|
3678
3863
|
if (Array.isArray(payload.blocks)) {
|
|
3679
3864
|
if (depth > 32) return;
|
|
3680
3865
|
payload.blocks.forEach((block, index) => {
|
|
@@ -3689,7 +3874,7 @@ function walkCitationRuns(slide, basePath, visit) {
|
|
|
3689
3874
|
}
|
|
3690
3875
|
if (isRecord3(payload.quote)) runs(payload.quote.text, `${path}.quote.text`);
|
|
3691
3876
|
};
|
|
3692
|
-
const value =
|
|
3877
|
+
const value = record5(slide);
|
|
3693
3878
|
for (const field of HEADING_FIELDS) runs(value[field], `${basePath}.${field}`);
|
|
3694
3879
|
const regions = Object.keys(value).filter((key) => regionKey.test(key)).sort();
|
|
3695
3880
|
if (regions.length) {
|
|
@@ -3706,7 +3891,7 @@ function walkCitationRuns(slide, basePath, visit) {
|
|
|
3706
3891
|
}
|
|
3707
3892
|
var citationMarkerText = (numbers) => numbers.join(",");
|
|
3708
3893
|
function referenceList(presentation) {
|
|
3709
|
-
const list =
|
|
3894
|
+
const list = record5(presentation).references;
|
|
3710
3895
|
return Array.isArray(list) ? list.filter((item) => isRecord3(item) && typeof item.id === "string") : [];
|
|
3711
3896
|
}
|
|
3712
3897
|
function numberSlide(slide, slideIndex, references, numbering) {
|
|
@@ -3739,7 +3924,7 @@ function numberSlide(slide, slideIndex, references, numbering) {
|
|
|
3739
3924
|
}
|
|
3740
3925
|
function collectCitations(presentation) {
|
|
3741
3926
|
const references = referenceList(presentation), numbering = { notes: [], byId: /* @__PURE__ */ new Map() }, slides = /* @__PURE__ */ new Map();
|
|
3742
|
-
const list =
|
|
3927
|
+
const list = record5(presentation).slides;
|
|
3743
3928
|
if (Array.isArray(list)) list.forEach((slide, index) => {
|
|
3744
3929
|
const result = numberSlide(slide, index, references, numbering);
|
|
3745
3930
|
if (result) slides.set(index, result);
|
|
@@ -3749,7 +3934,7 @@ function collectCitations(presentation) {
|
|
|
3749
3934
|
}
|
|
3750
3935
|
function slideCitations(slide, slideIndex, presentation) {
|
|
3751
3936
|
const references = referenceList(presentation), numbering = { notes: [], byId: /* @__PURE__ */ new Map() };
|
|
3752
|
-
const list =
|
|
3937
|
+
const list = record5(presentation).slides;
|
|
3753
3938
|
if (Array.isArray(list)) for (let index = 0; index < Math.min(slideIndex, list.length); index += 1) numberSlide(list[index], index, references, numbering);
|
|
3754
3939
|
return numberSlide(slide, slideIndex, references, numbering);
|
|
3755
3940
|
}
|
|
@@ -3812,35 +3997,12 @@ function referencesSlide(presentation, options = {}) {
|
|
|
3812
3997
|
return { title, items };
|
|
3813
3998
|
}
|
|
3814
3999
|
|
|
3815
|
-
// src/layout-content.ts
|
|
3816
|
-
var LAYOUT_BODY_KINDS = ["text", "list", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
|
|
3817
|
-
var bodyKinds = new Set(LAYOUT_BODY_KINDS);
|
|
3818
|
-
function layoutContent(record6) {
|
|
3819
|
-
const heading = { title: false, subtitle: false, tag: false };
|
|
3820
|
-
const counts = /* @__PURE__ */ new Map();
|
|
3821
|
-
let count = 0;
|
|
3822
|
-
for (const placeholder of Array.isArray(record6?.placeholders) ? record6.placeholders : []) {
|
|
3823
|
-
const type = placeholder?.type;
|
|
3824
|
-
if (type === "title" || type === "subtitle" || type === "tag") heading[type] = true;
|
|
3825
|
-
else if (typeof type === "string" && bodyKinds.has(type)) {
|
|
3826
|
-
counts.set(type, (counts.get(type) ?? 0) + 1);
|
|
3827
|
-
count += 1;
|
|
3828
|
-
}
|
|
3829
|
-
}
|
|
3830
|
-
let kind2 = "title", best = 0;
|
|
3831
|
-
for (const [candidate, total] of counts) if (total > best) {
|
|
3832
|
-
kind2 = candidate;
|
|
3833
|
-
best = total;
|
|
3834
|
-
}
|
|
3835
|
-
return { kind: kind2, count, heading };
|
|
3836
|
-
}
|
|
3837
|
-
|
|
3838
4000
|
// src/composition.ts
|
|
3839
4001
|
var MAX_COMPOSITION_DEPTH = 32;
|
|
3840
4002
|
var FALLBACK_CODE_FAMILY = "Roboto Mono";
|
|
3841
4003
|
var DEFAULT_FONT_FAMILIES = { heading: String(ENGINE_DEFAULT_FONT_SCHEME.major), body: String(ENGINE_DEFAULT_FONT_SCHEME.minor) };
|
|
3842
4004
|
function resolveFontFamilies(input) {
|
|
3843
|
-
const scheme =
|
|
4005
|
+
const scheme = record6(input);
|
|
3844
4006
|
const family = (value) => typeof value === "string" && value ? value : void 0;
|
|
3845
4007
|
const accent = family(scheme.accent);
|
|
3846
4008
|
return {
|
|
@@ -3911,6 +4073,12 @@ function translateTextFit(fit, dy) {
|
|
|
3911
4073
|
}
|
|
3912
4074
|
};
|
|
3913
4075
|
}
|
|
4076
|
+
var FIELD_KINDS = { text: "text", bullets: "text", items: "list", image: "image", video: "video", chart: "chart", table: "table", code: "code", metric: "metric", quote: "quote", timeline: "timeline" };
|
|
4077
|
+
function chartPrimaryLayout(side, kinds) {
|
|
4078
|
+
const first = side === "left" || side === "top";
|
|
4079
|
+
const group = { type: "group", composition: {}, placeholders: kinds.map((type) => ({ type })) };
|
|
4080
|
+
return { composition: { mode: side === "left" || side === "right" ? "row" : "column", weights: first ? [3, 2] : [2, 3] }, placeholders: first ? [{ type: "chart" }, group] : [group, { type: "chart" }] };
|
|
4081
|
+
}
|
|
3914
4082
|
var OPFCompositionError = class extends Error {
|
|
3915
4083
|
constructor(diagnostics, explanation) {
|
|
3916
4084
|
super("Slide content does not fit its composition.");
|
|
@@ -3926,7 +4094,7 @@ var fields = ["text", "items", "bullets", "image", "video", "chart", "table", "c
|
|
|
3926
4094
|
var headings = /* @__PURE__ */ new Set(["title", "subtitle", "tag"]);
|
|
3927
4095
|
var rows2 = ["top", "middle", "bottom"];
|
|
3928
4096
|
var columns = ["left", "center", "right"];
|
|
3929
|
-
var
|
|
4097
|
+
var record6 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3930
4098
|
var kind = (field) => field === "items" ? "list" : field === "bullets" ? "text" : field;
|
|
3931
4099
|
var round2 = (value) => Math.round(value * 1e6) / 1e6 || value;
|
|
3932
4100
|
var PLACEMENT_BAND = 0.5;
|
|
@@ -3940,13 +4108,13 @@ var imagePayload = (host) => {
|
|
|
3940
4108
|
for (const key of IMAGE_OPTION_KEYS) if (host[key] !== void 0) payload[key] = host[key];
|
|
3941
4109
|
return payload;
|
|
3942
4110
|
};
|
|
3943
|
-
var assetSource = (value) => typeof value === "string" ? value :
|
|
4111
|
+
var assetSource = (value) => typeof value === "string" ? value : record6(value).src;
|
|
3944
4112
|
var finite = (value, min, max) => typeof value === "number" && Number.isFinite(value) && value >= min && value <= max ? value : void 0;
|
|
3945
4113
|
var pathNumber = (value) => String(round2(value));
|
|
3946
4114
|
var IMAGE_SHAPES = { rectangle: "rect", rounded: "roundRect", circle: "ellipse", hexagon: "hexagon" };
|
|
3947
4115
|
var roundBox = (box) => ({ x: round2(box.x), y: round2(box.y), width: round2(box.width), height: round2(box.height) });
|
|
3948
4116
|
var imageFocus = (value) => {
|
|
3949
|
-
const focus =
|
|
4117
|
+
const focus = record6(value), x = finite(focus.x, 0, 1), y = finite(focus.y, 0, 1);
|
|
3950
4118
|
return x !== void 0 && y !== void 0 ? { x, y } : { x: 0.5, y: 0.5 };
|
|
3951
4119
|
};
|
|
3952
4120
|
function imageShape(kind2, box, cornerRadius = 1 / 6) {
|
|
@@ -3987,7 +4155,7 @@ function fitImage(frame, fit, aspect, focus = { x: 0.5, y: 0.5 }) {
|
|
|
3987
4155
|
}
|
|
3988
4156
|
function imageBackground(value) {
|
|
3989
4157
|
if (typeof value === "string") return IMAGE_SOURCE.test(value) ? { src: value, fit: "cover", focus: { x: 0.5, y: 0.5 } } : void 0;
|
|
3990
|
-
const background =
|
|
4158
|
+
const background = record6(value);
|
|
3991
4159
|
if (background.type !== "image" || typeof background.src !== "string" || !background.src) return void 0;
|
|
3992
4160
|
const opacity = finite(background.opacity, 0, 1);
|
|
3993
4161
|
return {
|
|
@@ -4002,11 +4170,11 @@ function imageBackground(value) {
|
|
|
4002
4170
|
}
|
|
4003
4171
|
function composeRecolor(value) {
|
|
4004
4172
|
if (value === "grayscale") return { type: "grayscale" };
|
|
4005
|
-
const duotone =
|
|
4173
|
+
const duotone = record6(value);
|
|
4006
4174
|
return duotone.dark !== void 0 && duotone.light !== void 0 ? { type: "duotone", dark: duotone.dark, light: duotone.light } : void 0;
|
|
4007
4175
|
}
|
|
4008
4176
|
function composeOverlay(value, frame, shape, path, mirrorSide, diagnostics) {
|
|
4009
|
-
const overlay =
|
|
4177
|
+
const overlay = record6(value), opacity = finite(overlay.opacity, 0, 1);
|
|
4010
4178
|
if (overlay.color === void 0 || opacity === void 0) return void 0;
|
|
4011
4179
|
const edge = IMAGE_EDGES.includes(overlay.edge) ? mirrorSide(overlay.edge) : void 0;
|
|
4012
4180
|
if (edge && shape.kind !== "rectangle") {
|
|
@@ -4031,7 +4199,7 @@ function composeImage(host, hostPath, region, frameArea, context) {
|
|
|
4031
4199
|
const focus = imageFocus(host.focus);
|
|
4032
4200
|
const shape = imageShape(kindName, box, finite(host.cornerRadius, 0, 0.5));
|
|
4033
4201
|
const result = { region: roundBox(region), box, fit, focus, shape };
|
|
4034
|
-
const border =
|
|
4202
|
+
const border = record6(host.border), borderWidth = finite(border.width, 0, 64);
|
|
4035
4203
|
if (border.color !== void 0 && borderWidth) result.border = { color: border.color, width: round2(borderWidth * scale) };
|
|
4036
4204
|
const opacity = finite(host.opacity, 0, 1);
|
|
4037
4205
|
if (opacity !== void 0 && opacity < 1) result.opacity = opacity;
|
|
@@ -4045,7 +4213,7 @@ function composeImage(host, hostPath, region, frameArea, context) {
|
|
|
4045
4213
|
return result;
|
|
4046
4214
|
}
|
|
4047
4215
|
function resolveBackgroundImage(slide, presentation, themeBackground, width, height, path, mirrorSide, diagnostics) {
|
|
4048
|
-
const own2 =
|
|
4216
|
+
const own2 = record6(slide.design), deck = record6(record6(presentation).design);
|
|
4049
4217
|
const [value, at3] = own2.background !== void 0 ? [own2.background, `${path}.design.background`] : deck.background !== void 0 ? [deck.background, "design.background"] : [themeBackground, "theme"];
|
|
4050
4218
|
const background = imageBackground(value);
|
|
4051
4219
|
if (!background) return void 0;
|
|
@@ -4056,7 +4224,7 @@ function resolveBackgroundImage(slide, presentation, themeBackground, width, hei
|
|
|
4056
4224
|
if (recolor) result.recolor = recolor;
|
|
4057
4225
|
const overlay = composeOverlay(background.overlay, box, imageShape("rectangle", box), `${at3}.overlay`, mirrorSide, diagnostics);
|
|
4058
4226
|
if (overlay) result.overlay = overlay;
|
|
4059
|
-
const aspect = background.fit === "tile" ? void 0 : intrinsicImageAspect(background.src,
|
|
4227
|
+
const aspect = background.fit === "tile" ? void 0 : intrinsicImageAspect(background.src, record6(presentation).assets);
|
|
4060
4228
|
if (aspect) result.picture = fitImage(box, background.fit, aspect, background.focus);
|
|
4061
4229
|
return result;
|
|
4062
4230
|
}
|
|
@@ -4077,10 +4245,10 @@ function resolveLogo(presentation, slide, options = {}) {
|
|
|
4077
4245
|
};
|
|
4078
4246
|
const pick = (value, path) => {
|
|
4079
4247
|
if (value === void 0 || value === null || value === false) return null;
|
|
4080
|
-
if (typeof value === "string" || typeof value === "object" && !Array.isArray(value) && "src" in
|
|
4248
|
+
if (typeof value === "string" || typeof value === "object" && !Array.isArray(value) && "src" in record6(value)) {
|
|
4081
4249
|
return usable(value) ? { source: value, path, variant: "default", slot } : null;
|
|
4082
4250
|
}
|
|
4083
|
-
const set2 =
|
|
4251
|
+
const set2 = record6(value);
|
|
4084
4252
|
if (!Object.keys(set2).some((key) => LOGO_SET_KEYS.has(key))) return null;
|
|
4085
4253
|
for (const key of chain) {
|
|
4086
4254
|
const variant = set2[key];
|
|
@@ -4088,16 +4256,16 @@ function resolveLogo(presentation, slide, options = {}) {
|
|
|
4088
4256
|
}
|
|
4089
4257
|
return null;
|
|
4090
4258
|
};
|
|
4091
|
-
const deck =
|
|
4092
|
-
const own2 = pick(
|
|
4259
|
+
const deck = record6(presentation), slideIndex = Number.isSafeInteger(options.slideIndex) && options.slideIndex >= 0 ? options.slideIndex : 0;
|
|
4260
|
+
const own2 = pick(record6(record6(slide).design).logo, `slides.${slideIndex}.design.logo`);
|
|
4093
4261
|
if (own2) return own2;
|
|
4094
|
-
const shared = pick(
|
|
4262
|
+
const shared = pick(record6(deck.design).logo, "design.logo");
|
|
4095
4263
|
if (shared) return shared;
|
|
4096
4264
|
const organizations = Array.isArray(deck.organization) ? deck.organization : [deck.organization];
|
|
4097
|
-
const primaryIndex = organizations.findIndex((item) =>
|
|
4265
|
+
const primaryIndex = organizations.findIndex((item) => record6(item).role === "primary");
|
|
4098
4266
|
const index = primaryIndex >= 0 ? primaryIndex : organizations.findIndex(Boolean);
|
|
4099
4267
|
if (index < 0) return null;
|
|
4100
|
-
return pick(
|
|
4268
|
+
return pick(record6(organizations[index]).logo, Array.isArray(deck.organization) ? `organization.${index}.logo` : "organization.logo");
|
|
4101
4269
|
}
|
|
4102
4270
|
var webUrl = /^https?:\/\/\S+$/i;
|
|
4103
4271
|
function resolveSocialProfile(platform, value, owner = "organization") {
|
|
@@ -4115,8 +4283,8 @@ function resolveSocialProfile(platform, value, owner = "organization") {
|
|
|
4115
4283
|
return { text: display(url), href: encodeURI(url), resolved: true };
|
|
4116
4284
|
}
|
|
4117
4285
|
function layoutFurniture(input, options = {}) {
|
|
4118
|
-
const slide =
|
|
4119
|
-
const settings = { ...
|
|
4286
|
+
const slide = record6(input), width = options.width ?? 1280, height = options.height ?? 720, scale = Math.min(width, height) / 720;
|
|
4287
|
+
const settings = { ...record6(record6(options.layout).composition), ...record6(slide.composition) };
|
|
4120
4288
|
assertComposition(settings);
|
|
4121
4289
|
const furnitureRtl = (options.direction ?? resolveSlideDirection(options.presentation, options.slideIndex)) === "rtl";
|
|
4122
4290
|
const minimum = snapFontSizeUp((settings.minFontSize ?? 16) * scale), size = gridFontSize(13 * scale, minimum), padding = (options.textRasterPadding ?? 2) * scale;
|
|
@@ -4128,14 +4296,13 @@ function layoutFurniture(input, options = {}) {
|
|
|
4128
4296
|
if (options.date !== void 0 && (typeof options.date !== "string" || !parseIsoDate(options.date))) throw new RangeError("The furniture date option must be an ISO YYYY-MM-DD calendar date.");
|
|
4129
4297
|
const outlines = options.textMeasurement?.outlineBounds !== void 0, parts = [], diagnostics = [];
|
|
4130
4298
|
const sourceRoot = `slides.${options.slideIndex ?? 0}`, organizations = Array.isArray(options.presentation?.organization) ? options.presentation.organization : [options.presentation?.organization];
|
|
4131
|
-
const primaryIndex = organizations.findIndex((item) =>
|
|
4132
|
-
const organization =
|
|
4133
|
-
const speakers = Array.isArray(options.presentation?.speaker) ? options.presentation.speaker : [options.presentation?.speaker], speaker = record5(speakers[0]), speakerRoot = Array.isArray(options.presentation?.speaker) ? "speaker.0" : "speaker";
|
|
4299
|
+
const primaryIndex = organizations.findIndex((item) => record6(item).role === "primary"), organizationIndex = primaryIndex >= 0 ? primaryIndex : organizations.findIndex(Boolean);
|
|
4300
|
+
const organization = record6(organizations[organizationIndex]), organizationRoot = Array.isArray(options.presentation?.organization) ? `organization.${organizationIndex}` : "organization";
|
|
4134
4301
|
const fontFamily = options.fontFamilies?.body ?? "sans-serif";
|
|
4135
4302
|
let headerBottom = 0, footerTop = height, configured = false;
|
|
4136
4303
|
const error = (path, message, code = "text-overflow") => diagnostics.push({ code, path, message });
|
|
4137
4304
|
for (const kind2 of ["header", "footer"]) {
|
|
4138
|
-
const local =
|
|
4305
|
+
const local = record6(slide.design)[kind2] !== void 0, value = local ? record6(slide.design)[kind2] : options.presentation?.design?.[kind2];
|
|
4139
4306
|
if (value === void 0 || value === false) continue;
|
|
4140
4307
|
const root = local ? `${sourceRoot}.design.${kind2}` : `design.${kind2}`;
|
|
4141
4308
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError("Header/footer content must be an object or false.");
|
|
@@ -4143,7 +4310,7 @@ function layoutFurniture(input, options = {}) {
|
|
|
4143
4310
|
const zones = [];
|
|
4144
4311
|
for (const [index, zone] of ["left", "center", "right"].entries()) {
|
|
4145
4312
|
const side = furnitureRtl && zone !== "center" ? zone === "left" ? "right" : "left" : zone;
|
|
4146
|
-
const content =
|
|
4313
|
+
const content = record6(record6(value)[zone]), path = `${root}.${zone}`, x = width * (0.07 + (furnitureRtl ? 2 - index : index) * 0.3), zoneWidth = width * 0.26, zoneParts = [];
|
|
4147
4314
|
let y = 0;
|
|
4148
4315
|
const add = (field, text2, generated = false, sourcePath, extras = {}) => {
|
|
4149
4316
|
if (text2 === void 0) return;
|
|
@@ -4180,7 +4347,7 @@ function layoutFurniture(input, options = {}) {
|
|
|
4180
4347
|
y += box.height;
|
|
4181
4348
|
};
|
|
4182
4349
|
const imageBox = (source) => {
|
|
4183
|
-
const imageHeight = Math.max(32 * scale, Math.min(height * 0.05, 72 * scale)), imageWidth = Math.min(zoneWidth, imageHeight * (intrinsicImageAspect(source,
|
|
4350
|
+
const imageHeight = Math.max(32 * scale, Math.min(height * 0.05, 72 * scale)), imageWidth = Math.min(zoneWidth, imageHeight * (intrinsicImageAspect(source, record6(options.presentation).assets) ?? 1));
|
|
4184
4351
|
return { x: side === "left" ? x : side === "center" ? x + (zoneWidth - imageWidth) / 2 : x + zoneWidth - imageWidth, y, width: imageWidth, height: imageHeight };
|
|
4185
4352
|
};
|
|
4186
4353
|
if (content.logo === true) {
|
|
@@ -4196,30 +4363,17 @@ function layoutFurniture(input, options = {}) {
|
|
|
4196
4363
|
zoneParts.push({ type: "image", kind: kind2, zone, field: "image", path: `${path}.image`, sourcePath: `${path}.image`, generated: false, image: content.image, box, alignment: side });
|
|
4197
4364
|
y += box.height;
|
|
4198
4365
|
}
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
if (
|
|
4202
|
-
|
|
4203
|
-
}
|
|
4204
|
-
if (content.speaker === true) {
|
|
4205
|
-
if (typeof speaker.name === "string" && speaker.name.trim()) add("speaker", typeof speaker.title === "string" && speaker.title.trim() ? `${speaker.name}, ${speaker.title}` : speaker.name, true, `${speakerRoot}.name`);
|
|
4206
|
-
else error(`${path}.speaker`, "Generated speaker needs a named speaker in the presentation.", "unresolved-content");
|
|
4207
|
-
}
|
|
4366
|
+
if (typeof content.text === "string") {
|
|
4367
|
+
const resolved = substituteSlideTokens(content.text, { slideNumber: number, ...slideCount !== void 0 ? { slideCount } : {}, section: slide.section });
|
|
4368
|
+
if (slideCount === void 0 && usesSlideBuiltin(content.text, "deck.slideCount")) error(`${path}.text`, "{{deck.slideCount}} needs the rendered slide count (the slideCount option or the presentation slides).", "unresolved-content");
|
|
4369
|
+
add("text", resolved.text, false, void 0, { fields: resolved.fields });
|
|
4370
|
+
} else add("text", content.text);
|
|
4208
4371
|
if (content.socials === true) {
|
|
4209
|
-
const links = Object.entries(
|
|
4372
|
+
const links = Object.entries(record6(organization.socials)).filter(([, value2]) => typeof value2 === "string" && value2.trim()).map(([platform, value2]) => ({ platform, sourcePath: `${organizationRoot}.socials.${platform}`, ...resolveSocialProfile(platform, value2, "organization") }));
|
|
4210
4373
|
if (links.length) add("socials", links.map((link) => link.text).join("\n"), true, `${organizationRoot}.socials`, { links });
|
|
4211
4374
|
else error(`${path}.socials`, "Generated social profiles need a primary organization with socials.", "unresolved-content");
|
|
4212
4375
|
}
|
|
4213
|
-
if (content.
|
|
4214
|
-
if (typeof slide.section === "string") add("section", slide.section, true, `${sourceRoot}.section`);
|
|
4215
|
-
else error(`${path}.section`, "Generated section needs a literal slide section.", "unresolved-content");
|
|
4216
|
-
}
|
|
4217
|
-
for (const setting of ["slideNumberFormat", "dateFormat"]) if (content[setting] !== void 0 && typeof content[setting] !== "string") throw new TypeError(`Furniture setting ${path}.${setting} requires a string.`);
|
|
4218
|
-
if (content.slideNumber === true) {
|
|
4219
|
-
const resolved = formatSlideNumber(content.slideNumberFormat ?? DEFAULT_SLIDE_NUMBER_FORMAT, number, slideCount);
|
|
4220
|
-
if ("error" in resolved) error(`${path}.slideNumberFormat`, resolved.error, "unresolved-content");
|
|
4221
|
-
else add("slideNumber", resolved.text, true, void 0, { fields: resolved.fields });
|
|
4222
|
-
}
|
|
4376
|
+
if (content.dateFormat !== void 0 && typeof content.dateFormat !== "string") throw new TypeError(`Furniture setting ${path}.dateFormat requires a string.`);
|
|
4223
4377
|
if (content.date === true) {
|
|
4224
4378
|
const format = content.dateFormat ?? DEFAULT_FURNITURE_DATE_FORMAT;
|
|
4225
4379
|
if (options.date === void 0) error(`${path}.date`, "A current date needs a host-supplied ISO date option. For fixed content use a literal date, or an ISO date with dateFormat.", "unresolved-content");
|
|
@@ -4755,19 +4909,19 @@ function fitSourceText(text2, box, size, minimum, step, measure, prose = false,
|
|
|
4755
4909
|
const layout = (fontSize) => {
|
|
4756
4910
|
const tabWidth = measure(" ", fontSize) * 4;
|
|
4757
4911
|
if (!Number.isFinite(tabWidth) || text2.includes(" ") && tabWidth <= 0) throw new RangeError("Text tabs require a positive finite measured space advance.");
|
|
4758
|
-
const measureLine = (start2, end2,
|
|
4912
|
+
const measureLine = (start2, end2, record7 = false) => {
|
|
4759
4913
|
let x = 0, offset = start2;
|
|
4760
4914
|
const segments = [];
|
|
4761
4915
|
for (const [index, segment2] of text2.slice(start2, end2).split(" ").entries()) {
|
|
4762
4916
|
if (index) {
|
|
4763
4917
|
const next = (Math.floor(x / tabWidth + 1e-9) + 1) * tabWidth;
|
|
4764
|
-
if (
|
|
4918
|
+
if (record7) segments.push({ kind: "tab", start: offset, end: offset + 1, x, width: next - x });
|
|
4765
4919
|
x = next;
|
|
4766
4920
|
offset++;
|
|
4767
4921
|
}
|
|
4768
4922
|
if (segment2) {
|
|
4769
4923
|
const advance = measure(segment2, fontSize);
|
|
4770
|
-
if (
|
|
4924
|
+
if (record7) segments.push({ kind: "text", start: offset, end: offset + segment2.length, x, width: advance });
|
|
4771
4925
|
x += advance;
|
|
4772
4926
|
offset += segment2.length;
|
|
4773
4927
|
}
|
|
@@ -5124,12 +5278,12 @@ function fitList(input, box, requestedSize = 25, minFontSize = 16, options = { s
|
|
|
5124
5278
|
function contentText(field, value) {
|
|
5125
5279
|
if (field === "text" || headings.has(field)) return flatten(value);
|
|
5126
5280
|
if (field === "items" || field === "bullets") return (Array.isArray(value) ? value : [value]).map((item) => {
|
|
5127
|
-
const entry =
|
|
5281
|
+
const entry = record6(item);
|
|
5128
5282
|
return `\u2022 ${flatten(item)}${entry.description ? `
|
|
5129
5283
|
${flatten(entry.description)}` : ""}`;
|
|
5130
5284
|
}).join("\n");
|
|
5131
|
-
if (field === "code") return flatten(
|
|
5132
|
-
if (field === "quote") return flatten(
|
|
5285
|
+
if (field === "code") return flatten(record6(value).source ?? value);
|
|
5286
|
+
if (field === "quote") return flatten(record6(value).text ?? value);
|
|
5133
5287
|
return void 0;
|
|
5134
5288
|
}
|
|
5135
5289
|
function layoutTable(value, box, options = {}) {
|
|
@@ -5200,7 +5354,7 @@ function flatten(value) {
|
|
|
5200
5354
|
if (value == null) return "";
|
|
5201
5355
|
if (typeof value !== "object") return String(value);
|
|
5202
5356
|
if (Array.isArray(value)) return value.map(flatten).join("");
|
|
5203
|
-
const item =
|
|
5357
|
+
const item = record6(value);
|
|
5204
5358
|
return flatten(item.text ?? item.value ?? item.source ?? JSON.stringify(value));
|
|
5205
5359
|
}
|
|
5206
5360
|
function regionParts(key) {
|
|
@@ -5256,7 +5410,7 @@ function assertComposition(value) {
|
|
|
5256
5410
|
if (value.overflow !== void 0 && !["warn", "error"].includes(value.overflow)) throw new RangeError("Invalid composition.overflow.");
|
|
5257
5411
|
}
|
|
5258
5412
|
function composeSlide(input, options = {}) {
|
|
5259
|
-
const slide =
|
|
5413
|
+
const slide = record6(input), layout = record6(options.layout);
|
|
5260
5414
|
const width = options.width ?? 1280, height = options.height ?? 720;
|
|
5261
5415
|
if (![width, height].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("Canvas dimensions must be finite and positive.");
|
|
5262
5416
|
const scale = Math.min(width, height) / 720;
|
|
@@ -5264,7 +5418,7 @@ function composeSlide(input, options = {}) {
|
|
|
5264
5418
|
const rtl = deckDirection === "rtl", textDirection = rtl ? "rtl" : void 0;
|
|
5265
5419
|
const hints = resolveDesignHints({ slide, layout, presentation: options.presentation, slideIndex: options.slideIndex, deck: { titleAlignment: options.titleAlignment, contentAlignment: options.contentAlignment, contentBox: options.contentBox } });
|
|
5266
5420
|
const hasCards = hints.contentBox ?? false;
|
|
5267
|
-
const composition = { ...
|
|
5421
|
+
const composition = { ...record6(layout.composition), ...record6(slide.composition) };
|
|
5268
5422
|
assertComposition(composition);
|
|
5269
5423
|
const padding = (composition.padding ?? 0.08) * Math.min(width, height);
|
|
5270
5424
|
const gap = (composition.gap ?? 1 / 30) * Math.min(width, height);
|
|
@@ -5345,16 +5499,16 @@ function composeSlide(input, options = {}) {
|
|
|
5345
5499
|
const mirrorSide = (side) => !rtl ? side : side === "left" ? "right" : side === "right" ? "left" : side;
|
|
5346
5500
|
const backgroundImage = resolveBackgroundImage(slide, options.presentation, options.themeBackground, width, height, path, mirrorSide, imageDiagnostics);
|
|
5347
5501
|
const regions = Object.keys(slide).filter((key) => regionParts(key)).sort();
|
|
5348
|
-
const assets =
|
|
5502
|
+
const assets = record6(options.presentation).assets;
|
|
5349
5503
|
const imageContext = (placement) => ({ fit: hints.imageFit, scale, mirrorSide, diagnostics: imageDiagnostics, assets, ...placement ? { placement } : {} });
|
|
5350
5504
|
const area = { left: 0, top: 0, right: width, bottom: height };
|
|
5351
|
-
const imagePlaceholders = (
|
|
5352
|
-
const topImages = regions.length ? [] : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index) => !Array.isArray(
|
|
5505
|
+
const imagePlaceholders = layoutLeaves(layout).flatMap((leaf) => leaf.type === "image" ? [{ placeholder: leaf.placeholder, path: leaf.path, depth: leaf.depth }] : []);
|
|
5506
|
+
const topImages = regions.length ? [] : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index) => !Array.isArray(record6(block).blocks) && record6(block).image !== void 0 ? [{ host: record6(block), hostPath: `${path}.blocks.${index}`, block: index }] : []) : slide.image !== void 0 ? [{ host: { type: "image", image: slide.image }, hostPath: path }] : [];
|
|
5353
5507
|
const placed = [], usedEdges = /* @__PURE__ */ new Set();
|
|
5354
5508
|
topImages.forEach((node, order) => {
|
|
5355
5509
|
const slot = imagePlaceholders[order];
|
|
5356
|
-
const own2 = node.block !== void 0 && node.host.placement !== void 0 ?
|
|
5357
|
-
const value = own2 ?? (slot?.placeholder.placement !== void 0 ?
|
|
5510
|
+
const own2 = node.block !== void 0 && node.host.placement !== void 0 ? record6(node.host.placement) : void 0;
|
|
5511
|
+
const value = own2 ?? (slot?.depth === 0 && slot.placeholder.placement !== void 0 ? record6(slot.placeholder.placement) : void 0);
|
|
5358
5512
|
if (!value || !IMAGE_EDGES.includes(value.edge)) return;
|
|
5359
5513
|
const edge = mirrorSide(value.edge);
|
|
5360
5514
|
if (usedEdges.has(edge)) return;
|
|
@@ -5367,7 +5521,7 @@ function composeSlide(input, options = {}) {
|
|
|
5367
5521
|
else if (edge === "right") area.right = region.x;
|
|
5368
5522
|
else if (edge === "top") area.top += band;
|
|
5369
5523
|
else area.bottom = region.y;
|
|
5370
|
-
const placement = { edge, size, inset: value.inset === true, path: own2 ? `${node.hostPath}.placement` :
|
|
5524
|
+
const placement = { edge, size, inset: value.inset === true, path: own2 ? `${node.hostPath}.placement` : `${slot.path}.placement` };
|
|
5371
5525
|
placed.push({ ...node, placement, region, slot: order });
|
|
5372
5526
|
});
|
|
5373
5527
|
const placedBlocks = new Set(placed.flatMap((entry) => entry.block !== void 0 ? [entry.block] : []));
|
|
@@ -5390,7 +5544,7 @@ function composeSlide(input, options = {}) {
|
|
|
5390
5544
|
const emptyPayload = (value) => value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
|
|
5391
5545
|
const emptyHost = (host) => emptyPayload(host.blocks) && fields.every((field) => emptyPayload(host[field]));
|
|
5392
5546
|
const flowBlocks = Array.isArray(slide.blocks) ? slide.blocks.filter((_, index) => !placedBlocks.has(index)) : slide.blocks;
|
|
5393
|
-
const hasBodyPayload = regions.some((key) => !emptyHost(
|
|
5547
|
+
const hasBodyPayload = regions.some((key) => !emptyHost(record6(slide[key]))) || !emptyPayload(flowBlocks) || fields.some((field) => !(placedRoot && field === "image") && !emptyPayload(slide[field]));
|
|
5394
5548
|
const isCover = !hasBodyPayload && (headingOnlyLayout || !hasLayoutRecord);
|
|
5395
5549
|
coverGroup = isCover;
|
|
5396
5550
|
let logo;
|
|
@@ -5457,7 +5611,7 @@ function composeSlide(input, options = {}) {
|
|
|
5457
5611
|
const collect = (host, basePath, depth = 0, ancestors = []) => {
|
|
5458
5612
|
if (Array.isArray(host.blocks)) {
|
|
5459
5613
|
if (depth >= MAX_COMPOSITION_DEPTH || ancestors.includes(host)) throw new RangeError(`Content groups must be acyclic and nest at most ${MAX_COMPOSITION_DEPTH} levels.`);
|
|
5460
|
-
const settings =
|
|
5614
|
+
const settings = record6(host.composition);
|
|
5461
5615
|
assertComposition(settings);
|
|
5462
5616
|
return [{
|
|
5463
5617
|
field: "blocks",
|
|
@@ -5466,7 +5620,7 @@ function composeSlide(input, options = {}) {
|
|
|
5466
5620
|
path: basePath,
|
|
5467
5621
|
payload: host,
|
|
5468
5622
|
composition: settings,
|
|
5469
|
-
children: host.blocks.flatMap((block, index) => collect(
|
|
5623
|
+
children: host.blocks.flatMap((block, index) => collect(record6(block), `${basePath}.blocks.${index}`, depth + 1, [...ancestors, host]))
|
|
5470
5624
|
}];
|
|
5471
5625
|
}
|
|
5472
5626
|
const captioned = host.caption !== void 0 ? fields.filter((field) => host[field] !== void 0 && CAPTIONABLE_FIELDS.includes(field)) : [];
|
|
@@ -5482,7 +5636,7 @@ function composeSlide(input, options = {}) {
|
|
|
5482
5636
|
}));
|
|
5483
5637
|
};
|
|
5484
5638
|
const regionsInReadingOrder = visualReadingOrder(regions.map((key) => ({ key, box: regionBox(regionParts(key), contentBox, gap) }))).map((entry) => entry.key);
|
|
5485
|
-
const pending = regions.length ? regionsInReadingOrder.flatMap((key) => collect(
|
|
5639
|
+
const pending = regions.length ? regionsInReadingOrder.flatMap((key) => collect(record6(slide[key]), `${path}.${key}`).map((item) => ({ ...item, region: regionParts(key) }))) : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index) => placedBlocks.has(index) ? [] : collect(record6(block), `${path}.blocks.${index}`)) : collect(placedRoot ? { ...slide, image: void 0 } : slide, path);
|
|
5486
5640
|
const groups = [], flows = [];
|
|
5487
5641
|
const decisions = options.explain ? [] : void 0;
|
|
5488
5642
|
const inheritedSettings = (parent, own2 = {}) => ({
|
|
@@ -5580,12 +5734,23 @@ function composeSlide(input, options = {}) {
|
|
|
5580
5734
|
};
|
|
5581
5735
|
const scoreNode = (node, box, settings, penalties) => {
|
|
5582
5736
|
if (!node.children) return leafScore(node, box, settings, penalties);
|
|
5583
|
-
const own2 = inheritedSettings(settings, node.composition), area2 = inset(box, own2);
|
|
5584
|
-
const cols = defaultColumns(
|
|
5585
|
-
const boxes = gridBoxes(
|
|
5737
|
+
const own2 = inheritedSettings(settings, node.composition), area2 = inset(box, own2), slotCount = Math.max(node.children.length, node.reserved ?? 0);
|
|
5738
|
+
const cols = defaultColumns(slotCount, area2, own2);
|
|
5739
|
+
const boxes = gridBoxes(slotCount, area2, cols, (own2.gap ?? 1 / 30) * Math.min(box.width, box.height), own2.weights ?? [], modeFor(own2) === "column");
|
|
5586
5740
|
return node.children.reduce((score, child, index) => score + scoreNode(child, boxes[index], own2, penalties), 0);
|
|
5587
5741
|
};
|
|
5588
|
-
const
|
|
5742
|
+
const slots = [];
|
|
5743
|
+
const emptySlots = (entries, boxes, settings) => entries.forEach((entry, index) => {
|
|
5744
|
+
const box = boxes[index];
|
|
5745
|
+
if (!box) return;
|
|
5746
|
+
slots.push({ path: entry.path, type: entry.type, depth: entry.depth, box: acceptedBox(box) });
|
|
5747
|
+
if (!entry.children) return;
|
|
5748
|
+
const own2 = inheritedSettings(settings, record6(entry.placeholder.composition)), inner = inset(box, own2);
|
|
5749
|
+
const cols = defaultColumns(entry.children.length, inner, own2);
|
|
5750
|
+
const mirror = (cell) => rtl ? { ...cell, x: inner.x + inner.width - (cell.x - inner.x) - cell.width } : cell;
|
|
5751
|
+
emptySlots(entry.children, gridBoxes(entry.children.length, inner, cols, (own2.gap ?? 1 / 30) * Math.min(box.width, box.height), own2.weights ?? [], modeFor(own2) === "column").map(mirror), own2);
|
|
5752
|
+
});
|
|
5753
|
+
const arrange = (nodes, area2, settings, reserved = 0, gapOverride, containerPath = path, recorded = true, template) => {
|
|
5589
5754
|
const count = Math.max(nodes.length, reserved);
|
|
5590
5755
|
if (!count) return;
|
|
5591
5756
|
const mode = modeFor(settings), localGap = (settings.gap ?? 1 / 30) * Math.min(area2.width, area2.height);
|
|
@@ -5597,9 +5762,9 @@ function composeSlide(input, options = {}) {
|
|
|
5597
5762
|
let best = Infinity;
|
|
5598
5763
|
for (let candidate = 1; candidate <= Math.min(count, settings.columns ?? 6); candidate++) {
|
|
5599
5764
|
const boxes2 = gridBoxes(count, area2, candidate, actualGap, settings.weights ?? [], false);
|
|
5600
|
-
const
|
|
5601
|
-
const penalties = candidates ? { cellProportions: 0, fontReduction: 0, textOverflow: 0, tableOverflow: 0, smallCells: 0, emptySlots } : void 0;
|
|
5602
|
-
const score = nodes.reduce((sum, node, i) => sum + scoreNode(node, boxes2[i], settings, penalties), 0) +
|
|
5765
|
+
const emptySlots2 = (Math.ceil(count / candidate) * candidate - count) * 2;
|
|
5766
|
+
const penalties = candidates ? { cellProportions: 0, fontReduction: 0, textOverflow: 0, tableOverflow: 0, smallCells: 0, emptySlots: emptySlots2 } : void 0;
|
|
5767
|
+
const score = nodes.reduce((sum, node, i) => sum + scoreNode(node, boxes2[i], settings, penalties), 0) + emptySlots2;
|
|
5603
5768
|
if (penalties && candidates) candidates.push({ columns: candidate, rows: Math.ceil(count / candidate), score, penalties });
|
|
5604
5769
|
if (score < best) {
|
|
5605
5770
|
best = score;
|
|
@@ -5617,13 +5782,15 @@ function composeSlide(input, options = {}) {
|
|
|
5617
5782
|
const grid = gridGeometry(count, area2, cols, actualGap, settings.weights ?? [], mode === "column");
|
|
5618
5783
|
const mirrored = (box) => rtl ? { ...box, x: area2.x + area2.width - (box.x - area2.x) - box.width } : box;
|
|
5619
5784
|
const boxes = grid.boxes.map(mirrored);
|
|
5785
|
+
if (template) emptySlots(template.slice(nodes.length), boxes.slice(nodes.length), settings);
|
|
5620
5786
|
if (recorded && !hasRegions) flows.push({ path: containerPath, box: { ...area2 }, composition: { ...settings }, columns: rtl ? grid.columns.map((track) => ({ offset: area2.width - track.offset - track.size, size: track.size })) : grid.columns, rows: grid.rows, gap: grid.gap, itemCount: nodes.length, slotCount: count });
|
|
5621
5787
|
nodes.forEach((node, index) => {
|
|
5622
5788
|
let box = node.region ? mirrored(regionBox(node.region, area2, actualGap)) : boxes[index];
|
|
5789
|
+
if (node.slot) slots.push({ path: node.slot.path, type: node.slot.type, depth: node.slot.depth, box: acceptedBox(box), ...node.slot.children ? {} : { content: node.path } });
|
|
5623
5790
|
if (node.children) {
|
|
5624
5791
|
const own2 = inheritedSettings(settings, node.composition), inner = inset(box, own2);
|
|
5625
5792
|
if (!node.synthetic) groups.push({ path: node.path, box, contentBox: inner, composition: own2 });
|
|
5626
|
-
arrange(node.children, inner, own2, 0, (own2.gap ?? 1 / 30) * Math.min(box.width, box.height), node.path, !node.synthetic);
|
|
5793
|
+
arrange(node.children, inner, own2, node.reserved ?? 0, (own2.gap ?? 1 / 30) * Math.min(box.width, box.height), node.path, !node.synthetic, node.slots);
|
|
5627
5794
|
} else {
|
|
5628
5795
|
const frameBox = hasCards ? acceptedBox(box) : void 0;
|
|
5629
5796
|
box = payloadBox(box);
|
|
@@ -5669,18 +5836,59 @@ function composeSlide(input, options = {}) {
|
|
|
5669
5836
|
if (placedSlots.size) {
|
|
5670
5837
|
for (let index = placeholders.length - 1; index >= 0; index--) if (placedSlots.has(placeholders[index])) placeholders.splice(index, 1);
|
|
5671
5838
|
}
|
|
5672
|
-
const ownMode =
|
|
5839
|
+
const ownMode = record6(slide.composition).mode;
|
|
5673
5840
|
const direction = hints.contentDirection;
|
|
5674
5841
|
const directionMode = direction === "vertical" ? "column" : direction === "horizontal" ? "row" : "auto";
|
|
5675
5842
|
const chartHint = hints.chartPrimary;
|
|
5676
5843
|
const chartSide = chartHint === "left" || chartHint === "right" || chartHint === "top" || chartHint === "bottom" ? chartHint : void 0;
|
|
5677
5844
|
const chartIndex = pending.findIndex((node) => !node.children && node.field === "chart");
|
|
5678
5845
|
const chartPrimary = chartSide !== void 0 && !ownMode && !regions.length && chartIndex >= 0 && pending.some((node) => node.children || node.field !== "chart") ? chartSide : void 0;
|
|
5679
|
-
const
|
|
5680
|
-
|
|
5846
|
+
const kindOf = (node) => node.children ? node.children[0] ? kindOf(node.children[0]) : "text" : FIELD_KINDS[node.field] ?? "text";
|
|
5847
|
+
const sugar = chartPrimary ? chartPrimaryLayout(chartPrimary, pending.filter((_, index) => index !== chartIndex).map(kindOf)) : void 0;
|
|
5848
|
+
const rootSettings = sugar ? { ...composition, ...sugar.composition, columns: void 0 } : { ...composition, mode: composition.mode ?? directionMode };
|
|
5849
|
+
const recordSlots = sugar ? [] : layoutSlots(layout).filter((slot) => !headings.has(slot.type) && !placedSlots.has(slot.placeholder));
|
|
5850
|
+
const templated = !sugar && !regions.length && recordSlots.some((slot) => slot.children) && pending.every((node) => !node.children);
|
|
5851
|
+
const fillSlots = (entries, queue, cursor, recordSlot) => {
|
|
5852
|
+
const nodes = [];
|
|
5853
|
+
for (const entry of entries) {
|
|
5854
|
+
if (cursor.next >= queue.length) break;
|
|
5855
|
+
if (!entry.children) {
|
|
5856
|
+
nodes.push({ ...queue[cursor.next++], ...recordSlot ? { slot: entry } : {} });
|
|
5857
|
+
continue;
|
|
5858
|
+
}
|
|
5859
|
+
const own2 = record6(entry.placeholder.composition);
|
|
5860
|
+
assertComposition(own2);
|
|
5861
|
+
const children = fillSlots(entry.children, queue, cursor, recordSlot);
|
|
5862
|
+
nodes.push({
|
|
5863
|
+
field: "blocks",
|
|
5864
|
+
type: "group",
|
|
5865
|
+
value: children.map((child) => child.payload),
|
|
5866
|
+
path,
|
|
5867
|
+
payload: {},
|
|
5868
|
+
children,
|
|
5869
|
+
composition: own2,
|
|
5870
|
+
synthetic: true,
|
|
5871
|
+
reserved: own2.mode ? 0 : entry.children.length,
|
|
5872
|
+
...recordSlot ? { slot: entry, slots: entry.children } : {}
|
|
5873
|
+
});
|
|
5874
|
+
}
|
|
5875
|
+
return nodes;
|
|
5876
|
+
};
|
|
5877
|
+
if (sugar) {
|
|
5681
5878
|
const primary = pending[chartIndex], rest = pending.filter((_, index) => index !== chartIndex);
|
|
5682
|
-
const
|
|
5683
|
-
arrange(
|
|
5879
|
+
const queue = chartPrimary === "left" || chartPrimary === "top" ? [primary, ...rest] : [...rest, primary];
|
|
5880
|
+
arrange(fillSlots(layoutSlots(sugar, "design.chartPrimary"), queue, { next: 0 }, false), contentBox, rootSettings, 0);
|
|
5881
|
+
} else if (templated) {
|
|
5882
|
+
const cursor = { next: 0 };
|
|
5883
|
+
const nodes = fillSlots(recordSlots, pending, cursor, true);
|
|
5884
|
+
arrange([...nodes, ...pending.slice(cursor.next)], contentBox, rootSettings, composition.mode ? 0 : placeholders.length, void 0, path, true, recordSlots);
|
|
5885
|
+
const order = /* @__PURE__ */ new Map();
|
|
5886
|
+
const number = (entries) => entries.forEach((entry) => {
|
|
5887
|
+
order.set(entry.path, order.size);
|
|
5888
|
+
if (entry.children) number(entry.children);
|
|
5889
|
+
});
|
|
5890
|
+
number(recordSlots);
|
|
5891
|
+
slots.sort((a, b) => order.get(a.path) - order.get(b.path));
|
|
5684
5892
|
} else arrange(pending, contentBox, rootSettings, composition.mode ? 0 : placeholders.length);
|
|
5685
5893
|
if (listBullet?.value === "image" && !bulletImage && items.some((item) => (item.field === "items" || item.field === "bullets") && item.payload.numbering === void 0)) {
|
|
5686
5894
|
diagnostics.push({ code: "unresolved-content", path: listBullet.path, message: "Picture bullets (listBullet: image) need design.logo or a primary organization logo; the marker glyph is drawn instead." });
|
|
@@ -5721,7 +5929,8 @@ function composeSlide(input, options = {}) {
|
|
|
5721
5929
|
} : void 0;
|
|
5722
5930
|
if (failures.length) throw new OPFCompositionError(failures, explanation);
|
|
5723
5931
|
diagnostics.push(...imageDiagnostics, ...numberingDiagnostics);
|
|
5724
|
-
|
|
5932
|
+
for (const slot of slots) for (const key of ["x", "y", "width", "height"]) slot.box[key] = round2(slot.box[key]);
|
|
5933
|
+
return { width, height, contentBox, items, groups, flows, ...slots.length ? { slots } : {}, diagnostics, composition, design: hints, ...furniture ? { furniture } : {}, ...backgroundImage ? { backgroundImage } : {}, ...logo ? { logo } : {}, ...rtl ? { direction: "rtl" } : {}, ...footnotes ? { footnotes } : {}, ...explanation ? { explanation } : {} };
|
|
5725
5934
|
}
|
|
5726
5935
|
function resolveCanvasDimensions(input) {
|
|
5727
5936
|
const presets = {
|
|
@@ -5736,7 +5945,7 @@ function resolveCanvasDimensions(input) {
|
|
|
5736
5945
|
letter: [11, 8.5],
|
|
5737
5946
|
a4: [11.69, 8.27]
|
|
5738
5947
|
};
|
|
5739
|
-
const value =
|
|
5948
|
+
const value = record6(input);
|
|
5740
5949
|
const preset = presets[typeof input === "string" ? input : value.preset] ?? presets.widescreen;
|
|
5741
5950
|
const width = (value.widthInches ?? preset[0]) * 96;
|
|
5742
5951
|
const height = (value.heightInches ?? preset[1]) * 96;
|
|
@@ -5744,4 +5953,4 @@ function resolveCanvasDimensions(input) {
|
|
|
5744
5953
|
return { width, height };
|
|
5745
5954
|
}
|
|
5746
5955
|
|
|
5747
|
-
export { CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CHART_HIGHLIGHT_MUTED_MIN_CONTRAST, CHART_HIGHLIGHT_MUTED_MIX, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CHART_TYPES, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, CODE_HIGHLIGHT_LANGUAGES, CODE_HIGHLIGHT_MAX_LENGTH, CODE_PANEL_BACKGROUND, CODE_PANEL_FOREGROUND, CODE_SYNTAX_MIN_CONTRAST, DARK_BACKGROUND_LUMINANCE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FURNITURE_DATE_FORMAT,
|
|
5956
|
+
export { CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CHART_HIGHLIGHT_MUTED_MIN_CONTRAST, CHART_HIGHLIGHT_MUTED_MIX, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CHART_TYPES, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, CODE_HIGHLIGHT_LANGUAGES, CODE_HIGHLIGHT_MAX_LENGTH, CODE_PANEL_BACKGROUND, CODE_PANEL_FOREGROUND, CODE_SYNTAX_MIN_CONTRAST, DARK_BACKGROUND_LUMINANCE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, DESIGN_HINT_KEYS, ENGINE_DEFAULT_CHART_TYPES, ENGINE_DEFAULT_COLOR_SCHEME, ENGINE_DEFAULT_FONT_SCHEME, ENGINE_DEFAULT_THEME, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, LANGUAGES, LAYOUT_BODY_KINDS, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_PLACEHOLDER_GROUP_DEPTH, MAX_ROMAN_VALUE, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCompositionError, OPFVariableError, PATTERN_PRESETS, PATTERN_PRESET_ALIASES, PATTERN_TILE_SIZE, PICTURE_BULLET_SCALE, SLIDE_SCOPED_BUILTINS, SOCIAL_PLATFORMS, SURFACE_ALT_MIN_CONTRAST, SURFACE_ALT_MIX, TIMELINE_OUTLINE_MIN_CONTRAST, TIMELINE_STATUSES, TIMELINE_TEXT_MIN_CONTRAST, VARIABLE_KINDS, annotationText, captionSettings, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, chartPrimaryLayout, citationMarkerText, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, composeSlide, datasetDiagnostics, defaultSlideBackground, fitImage, fitList, fitRichText, fitText, formatChartLabelNumber, formatChartLabelPercent, formatDataNumber, formatFurnitureDate, formatListNumber, formatVariableNumber, fromExcelNumberFormat, hasContentVariables, hasPlaceholderGroups, imageBackground, imageShape, inlineChartData, inlineDatasets, inlineTableData, instantiateForValidation, intrinsicImageAspect, intrinsicImageSize, isDarkColor, isDatasetRef, isPlaceholderGroup, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutFootnotes, layoutFurniture, layoutLeaves, layoutMetric, layoutQuote, layoutSlots, layoutStructure, layoutTable, layoutTimeline, layoutWatermark, listBuiltinVariables, listNumbers, listVariables, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, promotedRegionKeys, readingRows, referencesSlide, resolveCanvasDimensions, resolveChartData, resolveChartOptions, resolveCodeLanguage, resolveColorRef, resolveColorRoles, resolveDesignHints, resolveDesignRecords, resolveFontFamilies, resolveFontScheme, resolveLogo, resolveNumbering, resolvePatternPreset, resolveScriptFonts, resolveSlideDirection, resolveSlideVariables, resolveSocialProfile, resolveTableData, resolveTextStyle, resolveVariables, scriptFontRole, sliceNumberedItems, slideCitations, slideTokenSpans, snapFontSizeDown, snapFontSizeUp, suggestChartNumberFix, surfaceAltColor, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, timelineMarkerShapes, timelineTextColor, toExcelNumberFormat, tokenizeCode, unusedDatasets, usesSlideBuiltin, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };
|