@openpresentation/opf 0.17.0 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +4 -4
  2. package/dist/browser.js +38 -0
  3. package/dist/{catalog-refs-C4K4y-vh.d.ts → catalog-refs-BSfGELpt.d.ts} +1 -1
  4. package/dist/{catalog-schemas-g7RFQBdc.d.ts → catalog-schemas-CinPh5WA.d.ts} +1 -1
  5. package/dist/catalog.d.ts +2 -2
  6. package/dist/{chart-data-DTxdRRT1.d.ts → chart-data-BnNqgnC-.d.ts} +1 -1
  7. package/dist/{chunk-RA64UQKI.js → chunk-2PEWUUBR.js} +97 -73
  8. package/dist/{chunk-TCD2FB2K.js → chunk-ECP7QPGK.js} +5 -5
  9. package/dist/{chunk-O2CX5NEH.js → chunk-FO3WGS4R.js} +6 -5
  10. package/dist/{chunk-N4EVOFEA.js → chunk-GVOLSWAJ.js} +4 -4
  11. package/dist/{chunk-WWYWFVOI.js → chunk-IM337HP5.js} +151 -25
  12. package/dist/{chunk-YT7FMQER.js → chunk-JCOSZTOI.js} +1 -1
  13. package/dist/{chunk-IPW5BS3X.js → chunk-K5EG3UMS.js} +190 -172
  14. package/dist/{chunk-NLNYNBTS.js → chunk-KA3ZPFVT.js} +84 -26
  15. package/dist/{chunk-M4UR3NPN.js → chunk-L5YACLWK.js} +2 -2
  16. package/dist/{chunk-CW7GEAV3.js → chunk-MBU42S5Y.js} +291 -133
  17. package/dist/{chunk-BIC3SWPK.js → chunk-MSFE2HUK.js} +30 -5
  18. package/dist/{chunk-ESRYBYLY.js → chunk-PNINP5IF.js} +1 -1
  19. package/dist/{chunk-IS5H5JKH.js → chunk-R7KIASS4.js} +1 -1
  20. package/dist/{chunk-PPROJP2E.js → chunk-TRELE6I6.js} +1 -1
  21. package/dist/{chunk-O3CVNJTL.js → chunk-WHHLGDCQ.js} +1 -1
  22. package/dist/{chunk-O263APNI.js → chunk-ZCFSDSUX.js} +3 -3
  23. package/dist/{composition-BbZ_9C-c.d.ts → composition-C-OoqvAr.d.ts} +80 -40
  24. package/dist/composition.d.ts +3 -3
  25. package/dist/composition.js +1 -1
  26. package/dist/conversion-4CLOEG6O.js +21 -0
  27. package/dist/{conversion-SBpTOwdg.d.ts → conversion-BxZbBd_0.d.ts} +96 -38
  28. package/dist/convert.d.ts +4 -4
  29. package/dist/convert.js +7 -7
  30. package/dist/data.d.ts +7 -7
  31. package/dist/data.js +2 -2
  32. package/dist/{deck-report-Bx3naFlF.d.ts → deck-report-DiDf_Vew.d.ts} +5 -5
  33. package/dist/deck.d.ts +8 -8
  34. package/dist/deck.js +10 -10
  35. package/dist/diff.d.ts +1 -1
  36. package/dist/diff.js +5 -5
  37. package/dist/docs.js +35 -29
  38. package/dist/examples.d.ts +1 -1
  39. package/dist/examples.js +181 -214
  40. package/dist/{finding-CDQ_wH8j.d.ts → finding-CT_f_vbD.d.ts} +1 -1
  41. package/dist/format.js +2 -2
  42. package/dist/index.d.ts +153 -20
  43. package/dist/index.js +62 -15
  44. package/dist/markdown.d.ts +12 -8
  45. package/dist/markdown.js +7 -7
  46. package/dist/node-engine.d.ts +37 -17
  47. package/dist/node-engine.js +39 -16
  48. package/dist/{pagination-BhX4M48Y.d.ts → pagination-BaUjDrTz.d.ts} +7 -4
  49. package/dist/pagination.d.ts +4 -4
  50. package/dist/pagination.js +4 -4
  51. package/dist/patch.d.ts +1 -1
  52. package/dist/patch.js +4 -4
  53. package/dist/{presentation-fb8CZmRq.d.ts → presentation-81rNihF0.d.ts} +271 -384
  54. package/dist/repo-readme.js +1 -1
  55. package/dist/schemas.d.ts +4 -2
  56. package/dist/schemas.js +1 -1
  57. package/dist/spec/README.md +1 -1
  58. package/dist/spec/schemas/opf.schema.json +67 -72
  59. package/dist/types.d.ts +3 -3
  60. package/dist/{validation-types-iZbXfES6.d.ts → validation-types-PbGDrNUr.d.ts} +12 -7
  61. package/dist/validator.d.ts +8 -8
  62. package/dist/validator.js +3 -3
  63. package/dist/yaml.d.ts +6 -6
  64. package/dist/yaml.js +7 -7
  65. package/package.json +14 -12
  66. package/dist/node.d.ts +0 -60
  67. package/dist/node.js +0 -54
package/README.md CHANGED
@@ -49,10 +49,10 @@ console.log(Object.keys(saved.catalogs.default.themes)); // ["classic"]
49
49
  console.log(Object.keys(defaultCatalog.tones));
50
50
  ```
51
51
 
52
- In Node, `@openpresentation/opf/node` adds files: `convert` turns one file into another (a deck to PDF, PNG, SVG or PPTX, a PowerPoint file to a deck, one deck form to another, or bytes with no output path), `open` reads a deck file or imports a `.pptx`, and `save` writes one. It re-exports the rest of core, so one namespace import covers an application:
52
+ In Node (and Bun and Deno), the root adds files: `convert` turns one file into another (a deck to PDF, PNG, SVG or PPTX, a PowerPoint file to a deck, one deck form to another, or bytes with no output path), `open` reads a deck file or imports a `.pptx`, and `save` writes one. The same import works in every runtime, so one namespace import covers an application:
53
53
 
54
54
  ```ts
55
- import * as opf from "@openpresentation/opf/node";
55
+ import * as opf from "@openpresentation/opf";
56
56
 
57
57
  await opf.convert("deck.opf.md", "deck.pdf");
58
58
  const deck = await opf.open("deck.opf.md");
@@ -61,7 +61,7 @@ await opf.save(deck, "deck.opf.md");
61
61
  const { files } = await opf.convert(deck, { format: "pptx" }); // bytes, nothing written
62
62
  ```
63
63
 
64
- Drawing and PowerPoint go through the optional peers `@openpresentation/opf-render` and `@openpresentation/opf-pptx`, which `/node` loads the first time a call needs them; npm does not install them for you. `/node` is the only Node-only entry: the root and every other subpath run in a browser. See [OPF files in Node](../../docs/node.md).
64
+ Drawing and PowerPoint go through the optional peers `@openpresentation/opf-render` and `@openpresentation/opf-pptx`, which core loads the first time a call needs them; npm does not install them for you. The root has conditional exports (OPF 0.18 removed `/node`): `node`, `bun` and `deno` get this full build, and `browser`, `worker`, `workerd` and `default` get a browser-safe build with the same names and the same types, where `open`, `save` and `convert` reject with `OPFApiError` code `node-only`. Every other subpath runs in a browser. `parseSlideSelection(3 | "1-3" | [1, 3], total)` reads slide selections in both. See [OPF files in Node](../../docs/node.md).
65
65
 
66
66
  Use focused imports when you only need one surface:
67
67
 
@@ -91,7 +91,7 @@ The layout engine's names are not on the root. `composeSlide`, `fitText`, `layou
91
91
 
92
92
  ### Reading and writing a deck in any form
93
93
 
94
- `parse(text, { format, filename, catalogs })` and `stringify(presentation, { format | filename })` (the root and `@openpresentation/opf/deck`) read and write a deck as JSON (canonical), YAML or Markdown. The format is the `format` option, else the file name (`.opf.md` is Markdown, `.yaml` and `.yml` are YAML, anything else JSON; a plain `.md` is not a deck), and never the content. `parse` returns the presentation and throws `OPFValidationError` for a syntax, schema or reference error; the error's `report.findings` are located by line and column in the text (`opf/json-syntax`, `yaml/<rule>` or `markdown/<rule>` for syntax errors). Warnings do not throw: `validate(text)` returns the full report. Both run in a browser; files are `/node`'s job (below).
94
+ `parse(text, { format, filename, catalogs })` and `stringify(presentation, { format | filename })` (the root and `@openpresentation/opf/deck`) read and write a deck as JSON (canonical), YAML or Markdown. The format is the `format` option, else the file name (`.opf.md` is Markdown, `.yaml` and `.yml` are YAML, anything else JSON; a plain `.md` is not a deck), and never the content. `parse` returns the presentation and throws `OPFValidationError` for a syntax, schema or reference error; the error's `report.findings` are located by line and column in the text (`opf/json-syntax`, `yaml/<rule>` or `markdown/<rule>` for syntax errors). Warnings do not throw: `validate(text)` returns the full report. Both run in a browser; files are the Node build's job (above).
95
95
 
96
96
  ### OPF as YAML
97
97
 
@@ -0,0 +1,38 @@
1
+ import { OPFApiError } from './chunk-IM337HP5.js';
2
+ export { OPFApiError, OPFExportError, OPFImportError, OPFMoveToCustomError, copySlides, edit, embed, fill, fillRecords, moveToCustom, parseSlideSelection, sameRecord, stats, updateFromCatalog } from './chunk-IM337HP5.js';
3
+ export { specFileEntries, specFileKinds, specFilePaths } from './chunk-HXHOZ7AH.js';
4
+ export { OPFDataImportError, ingest, parseTabularData } from './chunk-ZCFSDSUX.js';
5
+ export { DECK_FORMATS, deckFormatOf, parse, stringify } from './chunk-GVOLSWAJ.js';
6
+ export { fromMarkdown, toMarkdown } from './chunk-MSFE2HUK.js';
7
+ import './chunk-ECP7QPGK.js';
8
+ export { OPFMarkdownError } from './chunk-R7KIASS4.js';
9
+ export { diff, merge } from './chunk-L5YACLWK.js';
10
+ export { OPFPatchError, OPFPatchValidationError, applyPatch } from './chunk-WHHLGDCQ.js';
11
+ export { OPFFormatError, format } from './chunk-JCOSZTOI.js';
12
+ export { OPFPaginationError, paginate, paginateSlide } from './chunk-FO3WGS4R.js';
13
+ import './chunk-PNINP5IF.js';
14
+ import './chunk-TRELE6I6.js';
15
+ export { DEFAULT_CHART_PALETTE, DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, findValidationRule, resolveSlideContext, validate, validateCatalogRecord, validationCategories, validationRules } from './chunk-KA3ZPFVT.js';
16
+ export { CHART_TYPES, DEFAULT_VARIABLE_DATE_FORMAT, ENGINE_DEFAULT_CHART_TYPES, ENGINE_DEFAULT_COLOR_SCHEME, ENGINE_DEFAULT_FONT_SCHEME, ENGINE_DEFAULT_THEME, LANGUAGES, LOGO_SHAPES, OPFVariableError, SLIDE_SCOPED_BUILTINS, SOCIAL_PLATFORMS, VARIABLE_KINDS, chartNumber, coerceVariableValue, datasetDiagnostics, formatDataNumber, formatVariableNumber, fromExcelNumberFormat, hasContentVariables, inlineChartData, inlineDatasets, inlineTableData, isDatasetRef, isTemplate, isXYChartType, listBuiltinVariables, listVariables, normalizeLanguageFamily, numberFormatError, resolveChartData, resolveDesignRecords, resolveFontScheme, resolveSlideVariables, resolveTableData, resolveVariables, suggestChartNumberFix, tableCellDisplayValue, toExcelNumberFormat, unusedDatasets, variableDeclarations } from './chunk-MBU42S5Y.js';
17
+ export { catalogDisplayKinds, catalogSchemaNames } from './chunk-TRDXRRQK.js';
18
+ export { CATALOG_GROUP_PATTERN, CATALOG_REFERENCE_PATTERN, OPFCatalogsOptionError, OPFUnresolvedReferenceError, catalogGroupSource, catalogKinds, catalogRecords, catalogReferenceSites, parseReference, resolveReference, unresolvedReference } from './chunk-SPFV27O5.js';
19
+ export { audience, chartType, colorScheme, fontScheme, language, layout, narrative, presentation, purpose, schemaEntries, schemaNames, schemas, socialPlatform, theme, tone } from './chunk-2PEWUUBR.js';
20
+ export { FONT_POLICY, applyFontPolicyDecisions, fontAvailabilityDiagnostics, fontPolicyFor } from './chunk-WXSPETQ6.js';
21
+
22
+ // src/browser.ts
23
+ var nodeOnly = (name, message) => new OPFApiError(`\`${name}\` ${message}`, "node-only", { details: { function: name, build: "browser" } });
24
+ var PARSE = "In a browser or a worker, read the text yourself and call parse(text, { filename }).";
25
+ var STRINGIFY = "In a browser or a worker, call stringify(deck, { filename }) and store or download the text.";
26
+ var CONVERT = "In a browser or a worker, change deck forms with parse and stringify (YAML, Markdown, JSON), and draw slides with @openpresentation/opf-render's /export-browser entry.";
27
+ var open = async () => {
28
+ throw nodeOnly("open", `reads files and needs Node. ${PARSE}`);
29
+ };
30
+ var save = async () => {
31
+ throw nodeOnly("save", `writes files and needs Node. ${STRINGIFY}`);
32
+ };
33
+ var convert = (async (_input, output) => {
34
+ const inMemory = output !== null && typeof output === "object";
35
+ throw nodeOnly("convert", inMemory ? `needs Node in OPF 0.18, also for the in-memory convert(deck, { format }). ${CONVERT}` : `reads and writes files and needs Node. ${CONVERT}`);
36
+ });
37
+
38
+ export { convert, open, save };
@@ -125,4 +125,4 @@ declare function catalogReferenceSites(document: unknown, options?: {
125
125
  /** Records a picker can offer for `kind`: the document's embedded records, then those of the registered catalogs its groups name, with the reference to write for each. */
126
126
  declare function catalogRecords(document: unknown, kind: CatalogKind, options?: CatalogOptions): ResolvedReference[];
127
127
 
128
- export { CATALOG_GROUP_PATTERN as C, OPFCatalogsOptionError as O, type RecordProvenance as R, type UnresolvedReferenceDiagnostic as U, CATALOG_REFERENCE_PATTERN as a, type Catalog as b, type CatalogKind as c, type CatalogOptions as d, type CatalogRecordMap as e, type CatalogRecords as f, type CatalogReferenceSite as g, OPFUnresolvedReferenceError as h, type ResolvedReference as i, catalogGroupSource as j, catalogKinds as k, catalogRecords as l, catalogReferenceSites as m, parseReference as p, resolveReference as r, unresolvedReference as u };
128
+ export { type CatalogKind as C, OPFCatalogsOptionError as O, type RecordProvenance as R, type UnresolvedReferenceDiagnostic as U, type Catalog as a, type CatalogOptions as b, CATALOG_GROUP_PATTERN as c, CATALOG_REFERENCE_PATTERN as d, type CatalogRecordMap as e, type CatalogRecords as f, type CatalogReferenceSite as g, OPFUnresolvedReferenceError as h, type ResolvedReference as i, catalogGroupSource as j, catalogKinds as k, catalogRecords as l, catalogReferenceSites as m, parseReference as p, resolveReference as r, unresolvedReference as u };
@@ -1,4 +1,4 @@
1
- import { c as CatalogKind } from './catalog-refs-C4K4y-vh.js';
1
+ import { C as CatalogKind } from './catalog-refs-BSfGELpt.js';
2
2
  import { SchemaName } from './schemas.js';
3
3
 
4
4
  /** Kinds of catalog display metadata: published by catalogs for pickers, never referenced by documents. */
package/dist/catalog.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { b as Catalog } from './catalog-refs-C4K4y-vh.js';
2
- import { C as CatalogDisplayKind } from './catalog-schemas-g7RFQBdc.js';
1
+ import { a as Catalog } from './catalog-refs-BSfGELpt.js';
2
+ import { C as CatalogDisplayKind } from './catalog-schemas-CinPh5WA.js';
3
3
  import './schemas.js';
4
4
  import './json-BFSdESOE.js';
5
5
 
@@ -185,4 +185,4 @@ declare function resolveTableData(table: unknown, document?: unknown, options?:
185
185
  /** Display value of a table cell: a number with a format (cell, else column) becomes formatted text; anything else is returned unchanged. */
186
186
  declare function tableCellDisplayValue(cell: DataTableCell, columnFormat?: string): DataTableCell;
187
187
 
188
- export { numberFormatError as A, resolveChartData as B, type ChartComboSeries as C, type DataCellValue as D, resolveTableData as E, suggestChartNumberFix as F, tableCellDisplayValue as G, toExcelNumberFormat as H, unusedDatasets as I, type ResolvedChartData as R, type ChartMapping as a, type ChartNumberFix as b, type ChartNumberFixOperation as c, type ChartNumberFixOptions as d, type DataColumn as e, type DataDiagnostic as f, type DataDiagnosticCode as g, type DataResolveOptions as h, type DataSourceRef as i, type DataStyledCell as j, type DataTableCell as k, type DataTableHeader as l, type DataTableValue as m, type DataTextRun as n, type Dataset as o, type DatasetRef as p, type ResolvedTableData as q, chartNumber as r, datasetDiagnostics as s, formatDataNumber as t, fromExcelNumberFormat as u, inlineChartData as v, inlineDatasets as w, inlineTableData as x, isDatasetRef as y, isXYChartType as z };
188
+ export { resolveChartData as A, resolveTableData as B, type ChartMapping as C, type DataCellValue as D, suggestChartNumberFix as E, tableCellDisplayValue as F, toExcelNumberFormat as G, unusedDatasets as H, type ChartComboSeries as I, type ResolvedChartData as R, type ChartNumberFix as a, type ChartNumberFixOperation as b, type ChartNumberFixOptions as c, type DataColumn as d, type DataDiagnostic as e, type DataDiagnosticCode as f, type DataResolveOptions as g, type DataSourceRef as h, type DataStyledCell as i, type DataTableCell as j, type DataTableHeader as k, type DataTableValue as l, type DataTextRun as m, type Dataset as n, type DatasetRef as o, type ResolvedTableData as p, chartNumber as q, datasetDiagnostics as r, formatDataNumber as s, fromExcelNumberFormat as t, inlineChartData as u, inlineDatasets as v, inlineTableData as w, isDatasetRef as x, isXYChartType as y, numberFormatError as z };
@@ -52,7 +52,7 @@ var presentation = {
52
52
  "minItems": 1
53
53
  }
54
54
  ],
55
- "description": "Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (Organization.role 'primary', else the first item) supplies the default deck logo, the 'socials' header/footer field and the 'organization.<field>' built-in variables; the others are available by id as 'organization.<id>.<field>' and are not drawn automatically."
55
+ "description": "Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (Organization.role 'primary', else the first item) supplies the cover and section logo, the 'socials' header/footer field and the 'organization.<field>' built-in variables; the others are available by id as 'organization.<id>.<field>' and are not drawn automatically."
56
56
  },
57
57
  "speaker": {
58
58
  "oneOf": [
@@ -775,7 +775,7 @@ var presentation = {
775
775
  },
776
776
  "Organization": {
777
777
  "type": "object",
778
- "description": "An organization associated with the presentation, typically the presenting company, but also hosts, partners, clients, or sponsors. The primary organization (role 'primary', else the first one) supplies the default deck logo (unless design.logo overrides it) and the 'socials' header/footer field (its socials). Every field is also a built-in variable ('{{organization.name}}', 'var:organization.logo', 'organization.<id>.<field>'). Nothing else about an organization is drawn automatically. See docs/templates-and-variables.md.",
778
+ "description": "An organization associated with the presentation, typically the presenting company, but also hosts, partners, clients, or sponsors. The primary organization (role 'primary', else the first one) supplies the cover and section logo (unless design.logo overrides it) and the 'socials' header/footer field (its socials). Every field is also a built-in variable ('{{organization.name}}', 'organization.<id>.<field>'), and every logo a slide-scoped image ('var:organization.logo.icon', 'var:organization.<id>.logo'). Nothing else about an organization is drawn automatically. See docs/templates-and-variables.md.",
779
779
  "required": [
780
780
  "id",
781
781
  "name"
@@ -809,12 +809,29 @@ var presentation = {
809
809
  ]
810
810
  },
811
811
  "logo": {
812
- "$ref": "#/$defs/Asset",
813
- "description": "Source for the organization's logo image. Accepts an HTTPS URL, data URI, relative path (resolved against the OPF file location), local path, or 'asset:<id>' reference. Common formats are SVG (preferred for vector logos), PNG (with transparency), or JPG. The primary organization's logo (role 'primary', else the first organization) is the fallback source wherever the deck logo is drawn: a slide's design.logo, then design.logo, then this value. It is therefore drawn on cover and section slides and by header/footer zones with logo: true, exactly as design.logo would be (see design.logo and docs/design-resolution.md). It is also the built-in image variable 'organization.logo' (or 'organization.<id>.logo'), placed with 'var:organization.logo' in an image field.",
812
+ "oneOf": [
813
+ {
814
+ "$ref": "#/$defs/Asset"
815
+ },
816
+ {
817
+ "$ref": "#/$defs/OrganizationLogo"
818
+ }
819
+ ],
820
+ "description": "The organization's logo. A path, URL or Asset is one logo for every shape; an object gives up to four shapes (full, stacked, icon, wordmark), each a path or Asset, or { onLight, onDark } for the two backgrounds. A path is resolved against the OPF file location; an HTTPS URL, data URI or 'asset:<id>' reference works too. SVG (preferred for vector logos) or PNG with transparency are typical. The primary organization's full logo (role 'primary', else the first organization) is drawn on cover and section slides unless design.logo names another or is false. Every logo is also a slide-scoped built-in image, placed with a whole-field reference in any image field: 'var:organization.logo' (the full logo), 'var:organization.logo.icon' (likewise stacked, wordmark, full), and 'var:organization.<id>.logo' or 'var:organization.<id>.logo.<shape>' for another organization. A missing shape falls back to full, and full to the first defined of wordmark, stacked and icon. The onLight or onDark value is chosen for each slide's background; a missing one uses the other. See docs/templates-and-variables.md and docs/design-resolution.md.",
814
821
  "examples": [
822
+ "./assets/acme-logo.svg",
823
+ {
824
+ "full": "./assets/acme-logo.svg",
825
+ "icon": "./assets/acme-mark.svg"
826
+ },
827
+ {
828
+ "full": {
829
+ "onLight": "./assets/acme-logo.svg",
830
+ "onDark": "./assets/acme-logo-white.svg"
831
+ },
832
+ "icon": "./assets/acme-mark.svg"
833
+ },
815
834
  "https://cdn.acme.com/logo.svg",
816
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9V3iWggAAAAASUVORK5CYII=",
817
- "./assets/logo.jpg",
818
835
  "asset:acme-logo"
819
836
  ]
820
837
  },
@@ -863,7 +880,7 @@ var presentation = {
863
880
  "sponsor",
864
881
  "host"
865
882
  ],
866
- "description": "Role of the organization relative to the presentation. Only 'primary' has behavior: it selects the primary organization (deck logo, the 'socials' header/footer field, and the 'organization.<field>' built-ins). When no organization has role 'primary', the first one is primary. 'partner', 'client', 'sponsor' and 'host' are descriptive labels that change nothing."
883
+ "description": "Role of the organization relative to the presentation. Only 'primary' has behavior: it selects the primary organization (cover and section logo, the 'socials' header/footer field, and the 'organization.<field>' built-ins). When no organization has role 'primary', the first one is primary. 'partner', 'client', 'sponsor' and 'host' are descriptive labels that change nothing."
867
884
  },
868
885
  "socials": {
869
886
  "$ref": "#/$defs/Socials",
@@ -1086,20 +1103,19 @@ var presentation = {
1086
1103
  "logo": {
1087
1104
  "oneOf": [
1088
1105
  {
1089
- "$ref": "#/$defs/Asset"
1106
+ "type": "string",
1107
+ "pattern": "^var:organization(\\.[A-Za-z0-9_-]+)?\\.logo(\\.(full|stacked|icon|wordmark))?$"
1090
1108
  },
1091
1109
  {
1092
- "$ref": "#/$defs/LogoSet"
1110
+ "type": "boolean",
1111
+ "const": false
1093
1112
  }
1094
1113
  ],
1095
- "description": "Deck logo assets used by covers, section dividers, headers, footers and picture bullets. A string or Asset object is the default logo source; the LogoSet object form provides light/dark, stacked, icon, and wordmark variants (see LogoSet for the selection order). Source precedence: a slide's design.logo, then this value, then the primary organization's logo; absence inherits. Placement (reference engines, vetoable): on a cover or section slide (no body payload on a heading-only layout such as title, title-subtitle or section-divider, or no layout) the lockup variant is drawn at the top-left of the free area, inside the slide padding and below any header furniture, in a box 56 reference pixels tall and at most four times as wide; the tag/title/subtitle group then centers in the remaining span. Content slides never get an automatic logo. Header and footer zones draw the icon variant when they set logo: true, and design.listBullet 'image' draws it as the picture bullet. composeSlide returns the cover box as geometry.logo.",
1114
+ "description": "Which logo covers, section dividers and picture bullets draw. Logos live on the organization (Organization.logo); without this field covers and sections draw the primary organization's full logo and picture bullets its icon. A logo reference overrides that: 'var:organization.beta.logo' draws organization beta's logo, and a reference that names a shape ('var:organization.logo.wordmark') draws that shape everywhere this field applies. false draws no logo. A slide's design.logo overrides the deck's; absence inherits. An override naming an organization without a logo draws nothing (validation warns). Placement (reference engines, vetoable): on a cover or section slide (no body payload on a heading-only layout such as title, title-subtitle or section-divider, or no layout) the logo is drawn at the top-left of the free area, inside the slide padding and below any header furniture, in a box 56 reference pixels tall and at most four times as wide; the tag/title/subtitle group then centers in the remaining span. Content slides never get an automatic logo; a header or footer zone places one with image: 'var:organization.logo.icon'. composeSlide returns the cover box as geometry.logo.",
1096
1115
  "examples": [
1097
- "asset:acme-logo",
1098
- {
1099
- "default": "asset:acme-logo",
1100
- "light": "asset:acme-logo-white",
1101
- "icon": "asset:acme-icon"
1102
- }
1116
+ "var:organization.logo.wordmark",
1117
+ "var:organization.beta.logo",
1118
+ false
1103
1119
  ]
1104
1120
  },
1105
1121
  "watermark": {
@@ -1147,7 +1163,7 @@ var presentation = {
1147
1163
  "text": "{{slide.section}}"
1148
1164
  },
1149
1165
  "right": {
1150
- "image": "asset:acme-logo"
1166
+ "image": "var:organization.logo.icon"
1151
1167
  }
1152
1168
  }
1153
1169
  ]
@@ -1167,7 +1183,7 @@ var presentation = {
1167
1183
  false,
1168
1184
  {
1169
1185
  "left": {
1170
- "image": "asset:acme-logo"
1186
+ "image": "var:organization.logo.icon"
1171
1187
  },
1172
1188
  "center": {
1173
1189
  "text": "Confidential"
@@ -1234,7 +1250,7 @@ var presentation = {
1234
1250
  "character",
1235
1251
  "image"
1236
1252
  ],
1237
- "description": "Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the deck's icon logo (a slide's design.logo, then design.logo, then the primary organization's logo; light variants on dark backgrounds) as a picture bullet: a square of the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field."
1253
+ "description": "Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square of the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field."
1238
1254
  }
1239
1255
  }
1240
1256
  },
@@ -1574,11 +1590,11 @@ var presentation = {
1574
1590
  "widescreen",
1575
1591
  "standard"
1576
1592
  ],
1577
- "description": "Named dimension preset; chooses both aspect ratio and physical size. 'widescreen' is an alias for 16:9 in PowerPoint widescreen size; 'standard' is an alias for 4:3 in PowerPoint standard size. The social-feed ratios keep the widescreen short edge of 7.5 in: 1:1 is 7.5 x 7.5 in, 4:5 is 7.5 x 9.375 in and 9:16 is 7.5 x 13.333 in (portrait)."
1593
+ "description": "Named preset; sets aspect ratio and physical size. 16:9 ('widescreen'): 13.333 x 7.5 in, PowerPoint's Widescreen. 4:3 ('standard'): 10 x 7.5 in. 16:10: 10 x 6.25 in. letter (11 x 8.5 in) and a4 (11.69 x 8.27 in) are paper sizes, not PowerPoint's Letter Paper or A4 Paper. 1:1, 4:5 and 9:16 are 7.5 in on the short edge."
1578
1594
  },
1579
1595
  "Dimensions": {
1580
1596
  "type": "object",
1581
- "description": "Slide dimensions; either pick a preset or specify custom inches.",
1597
+ "description": "Slide dimensions: a preset, or custom inches that override it. PowerPoint's Letter Paper (10 x 7.5 in), A4 Paper (10.8333 x 7.5 in) and On-screen Show (16:9) (10 x 5.625 in) are not OPF presets; use widthInches and heightInches. docs/slide-sizes.md compares every preset.",
1582
1598
  "properties": {
1583
1599
  "preset": {
1584
1600
  "$ref": "#/$defs/DimensionPreset"
@@ -1666,7 +1682,7 @@ var presentation = {
1666
1682
  "additionalProperties": {
1667
1683
  "$ref": "#/$defs/Variable"
1668
1684
  },
1669
- "description": "Named variables, keyed by stable kebab-case id. A variable is a typed, named value the deck declares once and uses in many places: a color ('var:<id>' in color fields, the original use), or content that fills a template (text, number, date, image, url, list). Content is referenced inline as '{{<id>}}' inside any string, or whole as 'var:<id>' in a field of the matching type; '\\{{' writes a literal '{{'. A hex string is shorthand for a color variable. A variable with no 'value' is unfilled: expected in a template (root 'template': true), an error in a normal deck. Engines resolve variables with resolveVariables() before composing, rendering or exporting, so a template plus its values previews and exports exactly like the equivalent hand-written deck. Read-only built-in variables come from the deck's own metadata and use dotted names that a user id can never take: 'deck.name', 'deck.description', 'deck.author', 'speaker.name|title|email|phone|bio|photo' (first speaker), 'speakers' (every speaker's name, a list), 'organization.name|legalName|tagline|domain|email|phone|logo' (primary organization), and 'speaker.<id>.<field>' / 'organization.<id>.<field>' by id. They are written the same two ways ('{{speaker.name}}', 'var:speaker.photo'), are never declared, and an unknown built-in path is a validation error; a known one with no source value resolves to nothing with a warning. The id 'speakers' is reserved. Three built-ins are slide-scoped and written only as inline tokens: '{{slide.number}}' (the displayed slide number after pagination), '{{slide.section}}' (the slide's section) and '{{deck.slideCount}}' (the number of slides after pagination). resolveVariables() leaves them as written; they resolve per slide as it is composed (resolveSlideVariables(), and header/footer text in layoutFurniture()), so every 'slide.' name is reserved and 'var:slide.*' or 'var:deck.slideCount' is a validation error. See docs/templates-and-variables.md.",
1685
+ "description": "Named variables, keyed by stable kebab-case id. A variable is a typed, named value the deck declares once and uses in many places: a color ('var:<id>' in color fields, the original use), or content that fills a template (text, number, date, image, url, list). Content is referenced inline as '{{<id>}}' inside any string, or whole as 'var:<id>' in a field of the matching type; '\\{{' writes a literal '{{'. A hex string is shorthand for a color variable. A variable with no 'value' is unfilled: expected in a template (root 'template': true), an error in a normal deck. Engines resolve variables with resolveVariables() before composing, rendering or exporting, so a template plus its values previews and exports exactly like the equivalent hand-written deck. Read-only built-in variables come from the deck's own metadata and use dotted names that a user id can never take: 'deck.name', 'deck.description', 'deck.author', 'speaker.name|title|email|phone|bio|photo' (first speaker), 'speakers' (every speaker's name, a list), 'organization.name|legalName|tagline|domain|email|phone' (primary organization), and 'speaker.<id>.<field>' / 'organization.<id>.<field>' by id. They are written the same two ways ('{{speaker.name}}', 'var:speaker.photo'), are never declared, and an unknown built-in path is a validation error; a known one with no source value resolves to nothing with a warning. The id 'speakers' is reserved. Three built-ins are slide-scoped and written only as inline tokens: '{{slide.number}}' (the displayed slide number after pagination), '{{slide.section}}' (the slide's section) and '{{deck.slideCount}}' (the number of slides after pagination). resolveVariables() leaves them as written; they resolve per slide as it is composed (resolveSlideVariables(), and header/footer text in layoutFurniture()), so every 'slide.' name is reserved and 'var:slide.*' or 'var:deck.slideCount' is a validation error. Organization logos are slide-scoped whole-field images: 'var:organization.logo', 'var:organization.logo.<shape>' (full, stacked, icon, wordmark), 'var:organization.<id>.logo' and 'var:organization.<id>.logo.<shape>' resolve per slide to the onLight or onDark asset for its background. See docs/templates-and-variables.md.",
1670
1686
  "examples": [
1671
1687
  {
1672
1688
  "risk": "#B42318",
@@ -2509,60 +2525,71 @@ var presentation = {
2509
2525
  }
2510
2526
  }
2511
2527
  },
2512
- "LogoSet": {
2528
+ "OrganizationLogo": {
2513
2529
  "type": "object",
2514
- "description": "Deck logo variants surfaced by covers, section dividers, headers, footers and picture bullets. Organization identity lives in organization; this object only controls visual rendering assets. Engines select one variant per slot and background tone (resolveLogo in @openpresentation/opf): same-tone variants first, neutral ones next, the opposite tone last. Lockup on a dark background: light, default, stackedLight, stacked, wordmarkLight, wordmark, iconLight, icon, then dark, stackedDark, wordmarkDark, iconDark; on a light background: dark, default, stackedDark, stacked, wordmarkDark, wordmark, iconDark, icon, then light, stackedLight, wordmarkLight, iconLight. The icon slot (headers, footers, picture bullets) tries iconLight or iconDark for the tone, then icon, then the lockup chain; the stacked slot tries stackedLight or stackedDark, then stacked, then the lockup chain.",
2530
+ "description": "An organization's logo in up to four shapes. Each shape is a path or Asset, or { onLight, onDark } for the two backgrounds. A missing shape falls back to full, and full to the first defined of wordmark, stacked and icon; within a shape a missing onLight or onDark uses the other. Shapes are placed with slide-scoped references such as 'var:organization.logo.icon'.",
2515
2531
  "additionalProperties": false,
2532
+ "minProperties": 1,
2516
2533
  "properties": {
2517
- "default": {
2518
- "$ref": "#/$defs/Asset",
2519
- "description": "Default full-lockup logo. Used as fallback when no more specific variant is set."
2520
- },
2521
- "light": {
2522
- "$ref": "#/$defs/Asset",
2523
- "description": "Light-colored full-lockup logo intended for rendering on dark backgrounds."
2524
- },
2525
- "dark": {
2526
- "$ref": "#/$defs/Asset",
2527
- "description": "Dark-colored full-lockup logo intended for rendering on light backgrounds."
2534
+ "full": {
2535
+ "$ref": "#/$defs/LogoSource",
2536
+ "description": "The full logo (lockup): mark and name side by side. Drawn on cover and section slides, and placed by 'var:organization.logo'."
2528
2537
  },
2529
2538
  "stacked": {
2530
- "$ref": "#/$defs/Asset",
2531
- "description": "Stacked vertical logo lockup, suited to portrait or square brand-mark slots."
2532
- },
2533
- "stackedLight": {
2534
- "$ref": "#/$defs/Asset",
2535
- "description": "Light-colored stacked logo variant intended for rendering on dark backgrounds."
2536
- },
2537
- "stackedDark": {
2538
- "$ref": "#/$defs/Asset",
2539
- "description": "Dark-colored stacked logo variant intended for rendering on light backgrounds."
2539
+ "$ref": "#/$defs/LogoSource",
2540
+ "description": "The stacked lockup: mark above the name, for portrait or square slots. Placed by 'var:organization.logo.stacked'."
2540
2541
  },
2541
2542
  "icon": {
2542
- "$ref": "#/$defs/Asset",
2543
- "description": "Default icon, mark, or symbol without wordmark. Useful for tight spaces such as footers, badges, and slide-corner marks."
2544
- },
2545
- "iconLight": {
2546
- "$ref": "#/$defs/Asset",
2547
- "description": "Light-colored icon variant intended for rendering on dark backgrounds."
2548
- },
2549
- "iconDark": {
2550
- "$ref": "#/$defs/Asset",
2551
- "description": "Dark-colored icon variant intended for rendering on light backgrounds."
2543
+ "$ref": "#/$defs/LogoSource",
2544
+ "description": "The mark or symbol without the name, for tight spaces such as header and footer zones and picture bullets. Placed by 'var:organization.logo.icon'."
2552
2545
  },
2553
2546
  "wordmark": {
2554
- "$ref": "#/$defs/Asset",
2555
- "description": "Default wordmark: the organization name set in branded typography, without icon."
2547
+ "$ref": "#/$defs/LogoSource",
2548
+ "description": "The name set in the brand's lettering, without the mark. Placed by 'var:organization.logo.wordmark'."
2549
+ }
2550
+ },
2551
+ "examples": [
2552
+ {
2553
+ "full": "./assets/acme-logo.svg",
2554
+ "icon": "./assets/acme-mark.svg"
2556
2555
  },
2557
- "wordmarkLight": {
2558
- "$ref": "#/$defs/Asset",
2559
- "description": "Light-colored wordmark variant intended for rendering on dark backgrounds."
2556
+ {
2557
+ "full": {
2558
+ "onLight": "./assets/acme-logo.svg",
2559
+ "onDark": "./assets/acme-logo-white.svg"
2560
+ }
2561
+ }
2562
+ ]
2563
+ },
2564
+ "LogoSource": {
2565
+ "description": "One logo shape: a path or Asset for every background, or { onLight, onDark }. onLight is drawn on light backgrounds (usually dark artwork) and onDark on dark backgrounds (usually light artwork), by each slide's background; a missing one uses the other.",
2566
+ "oneOf": [
2567
+ {
2568
+ "$ref": "#/$defs/Asset"
2560
2569
  },
2561
- "wordmarkDark": {
2562
- "$ref": "#/$defs/Asset",
2563
- "description": "Dark-colored wordmark variant intended for rendering on light backgrounds."
2570
+ {
2571
+ "type": "object",
2572
+ "additionalProperties": false,
2573
+ "minProperties": 1,
2574
+ "properties": {
2575
+ "onLight": {
2576
+ "$ref": "#/$defs/Asset",
2577
+ "description": "The logo for light backgrounds, usually dark artwork."
2578
+ },
2579
+ "onDark": {
2580
+ "$ref": "#/$defs/Asset",
2581
+ "description": "The logo for dark backgrounds, usually light or white artwork."
2582
+ }
2583
+ }
2564
2584
  }
2565
- }
2585
+ ],
2586
+ "examples": [
2587
+ "./assets/acme-mark.svg",
2588
+ {
2589
+ "onLight": "./assets/acme-logo.svg",
2590
+ "onDark": "./assets/acme-logo-white.svg"
2591
+ }
2592
+ ]
2566
2593
  },
2567
2594
  "Watermark": {
2568
2595
  "type": "object",
@@ -2625,13 +2652,9 @@ var presentation = {
2625
2652
  },
2626
2653
  "HeaderFooterItem": {
2627
2654
  "type": "object",
2628
- "description": "One header/footer zone. Every configured field renders; fields in one zone stack top to bottom in the order logo, image, text, socials, date. Generated values such as the slide number, the slide count, the section, the organization or the speaker are variables inside text ('{{slide.number}} / {{deck.slideCount}}', '{{organization.name}}'), so one text writes several values in the author's order; a line break is '\\n'. Put a date and a slide number in different zones to keep each on the zone's single line. See docs/templates-and-variables.md.",
2655
+ "description": "One header/footer zone. Every configured field renders, side by side in one row in the order image, text, socials, date (mirrored in a right-to-left deck), aligned to the zone's edge (left, center or right) and vertically centered on each other; a line break inside text or socials ('\\n') stacks lines within that part. When the parts are wider than the zone their text wraps, and a row that cannot fit even so is reported as overflow. Generated values such as the slide number, the slide count, the section, the organization or the speaker are variables inside text ('{{slide.number}} / {{deck.slideCount}}', '{{organization.name}}'), so one text writes several values in the author's order. An organization logo is image: 'var:organization.logo.icon'. See docs/templates-and-variables.md.",
2629
2656
  "additionalProperties": false,
2630
2657
  "properties": {
2631
- "logo": {
2632
- "type": "boolean",
2633
- "description": "Whether to render the deck's icon logo in this zone: a slide's design.logo, then design.logo, then the primary organization's logo (LogoSet icon variants first, light ones on dark backgrounds). It is a generated image part in the same box as image; without a logo the engine reports unresolved-content at this field. Use image for a literal picture that is not the deck logo."
2634
- },
2635
2658
  "text": {
2636
2659
  "type": "string",
2637
2660
  "description": "Text rendered in this zone. Variables resolve inside it like any string: deck-wide ones ('{{organization.name}}', '{{speaker.name}}, {{speaker.title}}', '{{customer}}') before composition, and the slide-scoped built-ins '{{slide.number}}', '{{slide.section}}' and '{{deck.slideCount}}' for each slide as it is laid out. Each '{{slide.number}}' is a live slide-number field: PPTX export writes it as a native field when its value fits within one accepted text line, and as static text with a diagnostic otherwise. '{{deck.slideCount}}' is fixed text, because PowerPoint has no slide-count field. Write '\\{{' for literal braces.",
@@ -2644,10 +2667,11 @@ var presentation = {
2644
2667
  },
2645
2668
  "image": {
2646
2669
  "$ref": "#/$defs/Asset",
2647
- "description": "Generic image rendered in this zone, such as a logo, partner mark, certification badge, or icon.",
2670
+ "description": "Image rendered first in this zone's row, such as a logo, partner mark, certification badge, or icon: a path, URL or Asset, or an organization logo reference ('var:organization.logo.icon', 'var:organization.<id>.logo.wordmark'), which resolves for each slide's background (onLight or onDark).",
2648
2671
  "examples": [
2649
- "asset:acme-logo",
2650
- "./assets/footer-badge.svg"
2672
+ "var:organization.logo.icon",
2673
+ "./assets/footer-badge.svg",
2674
+ "var:organization.beta.logo"
2651
2675
  ]
2652
2676
  },
2653
2677
  "date": {
@@ -3087,7 +3111,7 @@ var presentation = {
3087
3111
  },
3088
3112
  "hidden": {
3089
3113
  "type": "boolean",
3090
- "description": "Whether the slide is hidden from the presented sequence. The player skips it, the PPTX export writes it as a hidden slide, and per-slide image and PDF output skips it unless the caller asks to include hidden slides (opf CLI: --include-hidden; the deck-level renderSvg: the opt-in skipHidden). A slide named explicitly (opf render --slides, renderSvg slideIndex) is still rendered."
3114
+ "description": "Whether the slide is hidden from the presented sequence. The player skips it, the PPTX export writes it as a hidden slide, and per-slide image and PDF output skips it unless the caller asks to include hidden slides (opf CLI: --include-hidden; the deck-level toSvg: the opt-in skipHidden). A slide named explicitly (opf convert --slides, toSvg with a slide number) is still rendered."
3091
3115
  },
3092
3116
  "composition": {
3093
3117
  "$ref": "#/$defs/Composition"
@@ -1,9 +1,9 @@
1
- import { NOT_CHECKED, Ctx } from './chunk-IS5H5JKH.js';
2
- import { sortPresentationKeys } from './chunk-YT7FMQER.js';
3
- import { same } from './chunk-PPROJP2E.js';
4
- import { validate } from './chunk-NLNYNBTS.js';
1
+ import { NOT_CHECKED, Ctx } from './chunk-R7KIASS4.js';
2
+ import { sortPresentationKeys } from './chunk-JCOSZTOI.js';
3
+ import { same } from './chunk-TRELE6I6.js';
4
+ import { validate } from './chunk-KA3ZPFVT.js';
5
5
  import { checkCatalogsOption } from './chunk-SPFV27O5.js';
6
- import { presentation } from './chunk-RA64UQKI.js';
6
+ import { presentation } from './chunk-2PEWUUBR.js';
7
7
  import { Parser, parseDocument, isMap, Document, visit, isScalar, isAlias, isSeq } from 'yaml';
8
8
 
9
9
  var MAX_ALIAS_COUNT = 100;
@@ -1,5 +1,5 @@
1
- import { assertValid, resolveSlideScriptMeasurement, resolveSlideContext } from './chunk-NLNYNBTS.js';
2
- import { resolveSlideVariables, usesSlideBuiltin, composeSlide, codeHighlightSlice, tableRowBoundaries, visitContentPayloads, slideTokenSpans, sliceNumberedItems } from './chunk-CW7GEAV3.js';
1
+ import { assertValid, resolveSlideScriptMeasurement, resolveSlideContext } from './chunk-KA3ZPFVT.js';
2
+ import { resolveSlideVariables, usesSlideBuiltin, composeSlide, codeHighlightSlice, tableRowBoundaries, visitContentPayloads, slideTokenSpans, sliceNumberedItems } from './chunk-MBU42S5Y.js';
3
3
  import { checkCatalogsOption } from './chunk-SPFV27O5.js';
4
4
 
5
5
  // src/pagination.ts
@@ -122,10 +122,11 @@ function paginateSlide(input, options = {}) {
122
122
  if (options.layout !== void 0) composeOptions.layout = readableLayout(options.layout);
123
123
  const presentationSlides = options.presentation?.slides;
124
124
  const slideCount = options.slideCount ?? (Array.isArray(presentationSlides) && presentationSlides.length ? presentationSlides.length : void 0);
125
+ const logoContext = options.presentation !== void 0 ? { presentation: options.presentation, darkBackground: options.darkBackground === true } : {};
125
126
  const geometry = (slide, pageIndex = 0) => {
126
127
  if (++evaluations > 2e4) throw new OPFPaginationError("Pagination exceeded its layout evaluation limit. Split the input into smaller sections.");
127
128
  const slideNumber = (options.slideNumber ?? sourceIndex + 1) + pageIndex;
128
- return composeSlide(resolveSlideVariables(withReadability(slide, true), { slideNumber, ...slideCount !== void 0 ? { slideCount } : {} }), { ...composeOptions, slideNumber });
129
+ return composeSlide(resolveSlideVariables(withReadability(slide, true), { slideNumber, ...slideCount !== void 0 ? { slideCount } : {}, ...logoContext }), { ...composeOptions, slideNumber });
129
130
  };
130
131
  const initial = geometry(source);
131
132
  const fit = (diagnostics) => diagnostics.filter((issue) => issue.code === "text-overflow" || issue.code === "small-cell" || !!initial.furniture?.diagnostics.includes(issue));
@@ -141,7 +142,7 @@ function paginateSlide(input, options = {}) {
141
142
  if (!fit(initial.diagnostics).length) return { slides: [source], pages: [{ slideIndex: sourceIndex, mappings: initial.items.map((item) => ({ sourcePath: item.path, outputPath: item.path })), ...initial.furniture ? { repeatedMappings: repeatedMappings(0) } : {} }] };
142
143
  const headerIssues = initial.diagnostics.filter((issue) => headingFields.has(issue.path.slice(sourceBase.length + 1)) || initial.furniture?.diagnostics.includes(issue));
143
144
  if (headerIssues.length) throw new OPFPaginationError("Repeated headings or header/footer content cannot fit or resolve. Change the repeated content or slide design before pagination.", headerIssues);
144
- const tokens = resolveSlideVariables(source, { slideNumber: 1, slideCount: 1 }) !== source;
145
+ const tokens = resolveSlideVariables(source, { slideNumber: 1, slideCount: 1, ...logoContext }) !== source;
145
146
  const sourceValue = (path, fallback) => {
146
147
  if (!tokens || !path.startsWith(`${sourceBase}.`)) return fallback;
147
148
  let node = source;
@@ -312,7 +313,7 @@ function paginate(input, options = {}) {
312
313
  const { output, pages } = result;
313
314
  presentation.slides = output;
314
315
  assertValid(presentation, { only: ["format"] });
315
- return { presentation, pages };
316
+ return { presentation, pages, layout: options.fonts ? "measured" : "estimated" };
316
317
  }
317
318
 
318
319
  export { OPFPaginationError, paginate, paginateSlide };
@@ -1,7 +1,7 @@
1
- import { fromMarkdown, toMarkdown } from './chunk-BIC3SWPK.js';
2
- import { fromYaml, toYaml } from './chunk-TCD2FB2K.js';
3
- import { NOT_CHECKED } from './chunk-IS5H5JKH.js';
4
- import { parseSource, validate, OPFValidationError } from './chunk-NLNYNBTS.js';
1
+ import { fromMarkdown, toMarkdown } from './chunk-MSFE2HUK.js';
2
+ import { fromYaml, toYaml } from './chunk-ECP7QPGK.js';
3
+ import { NOT_CHECKED } from './chunk-R7KIASS4.js';
4
+ import { parseSource, validate, OPFValidationError } from './chunk-KA3ZPFVT.js';
5
5
  import { checkCatalogsOption } from './chunk-SPFV27O5.js';
6
6
 
7
7
  // src/deck-report.ts