@bendyline/squisq 1.4.1 → 1.5.1
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 +14 -1
- package/dist/{ContentContainer-DNx460y8.d.ts → ContentContainer-BXUlIf18.d.ts} +6 -2
- package/dist/{Doc-BeSeH2iX.d.ts → Doc-BBVGq1_9.d.ts} +922 -273
- package/dist/{ImageEditDoc-BTIvw0oq.d.ts → ImageEditDoc-FuyGtt6o.d.ts} +11 -4
- package/dist/{chunk-ZTX4PFFT.js → chunk-2OIBZYKP.js} +75 -2
- package/dist/chunk-2OIBZYKP.js.map +1 -0
- package/dist/chunk-2UQOHYE2.js +45 -0
- package/dist/chunk-2UQOHYE2.js.map +1 -0
- package/dist/chunk-6ATE2PSM.js +344 -0
- package/dist/chunk-6ATE2PSM.js.map +1 -0
- package/dist/{chunk-57CVQCFX.js → chunk-A4O7GIWE.js} +74 -23
- package/dist/chunk-A4O7GIWE.js.map +1 -0
- package/dist/{chunk-5WFRKURX.js → chunk-DLXZMS5K.js} +4 -2
- package/dist/chunk-DLXZMS5K.js.map +1 -0
- package/dist/chunk-ET53IIEP.js +1 -0
- package/dist/chunk-ET53IIEP.js.map +1 -0
- package/dist/chunk-HWVFJAAH.js +362 -0
- package/dist/chunk-HWVFJAAH.js.map +1 -0
- package/dist/{chunk-2TMAWB4Y.js → chunk-IMSCRLLV.js} +1 -1
- package/dist/chunk-IMSCRLLV.js.map +1 -0
- package/dist/{chunk-B4EEON3N.js → chunk-KKNUBQ6Y.js} +536 -103
- package/dist/chunk-KKNUBQ6Y.js.map +1 -0
- package/dist/chunk-LDQ2HJIX.js +596 -0
- package/dist/chunk-LDQ2HJIX.js.map +1 -0
- package/dist/chunk-LH7I6SH7.js +7208 -0
- package/dist/chunk-LH7I6SH7.js.map +1 -0
- package/dist/chunk-PGGGKYWG.js +1 -0
- package/dist/chunk-PGGGKYWG.js.map +1 -0
- package/dist/{chunk-7UDSRZKG.js → chunk-Q3ROPT5H.js} +35 -14
- package/dist/chunk-Q3ROPT5H.js.map +1 -0
- package/dist/chunk-QE7TWGVT.js +178 -0
- package/dist/chunk-QE7TWGVT.js.map +1 -0
- package/dist/chunk-RUDYOTA6.js +345 -0
- package/dist/chunk-RUDYOTA6.js.map +1 -0
- package/dist/{chunk-K32VJONL.js → chunk-T5UK6YOB.js} +41 -2
- package/dist/chunk-T5UK6YOB.js.map +1 -0
- package/dist/{chunk-3K5OG6KI.js → chunk-TEEEILMP.js} +412 -186
- package/dist/chunk-TEEEILMP.js.map +1 -0
- package/dist/{chunk-FR2RBTKO.js → chunk-TQWLI6S2.js} +93 -27
- package/dist/chunk-TQWLI6S2.js.map +1 -0
- package/dist/{chunk-WMOI7FN3.js → chunk-UY7KGQ5R.js} +12 -2
- package/dist/{chunk-WMOI7FN3.js.map → chunk-UY7KGQ5R.js.map} +1 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-VWUFZ6ZG.js} +29 -2
- package/dist/chunk-VWUFZ6ZG.js.map +1 -0
- package/dist/chunk-ZLQKNOZQ.js +1 -0
- package/dist/chunk-ZLQKNOZQ.js.map +1 -0
- package/dist/doc/index.d.ts +5 -5
- package/dist/doc/index.js +135 -8
- package/dist/generate/index.d.ts +3 -74
- package/dist/generate/index.js +2 -7
- package/dist/icons/index.d.ts +3 -26
- package/dist/icons/index.js +13 -0
- package/dist/icons/inlineIconMarker.d.ts +1 -0
- package/dist/icons/inlineIconMarker.js +15 -0
- package/dist/icons/inlineIconMarker.js.map +1 -0
- package/dist/imageEdit/index.d.ts +12 -6
- package/dist/imageEdit/index.js +4 -1
- package/dist/index.d.ts +14 -11
- package/dist/index.js +265 -37
- package/dist/inlineIconMarker-CiE8Hlvz.d.ts +59 -0
- package/dist/jsonForm/index.d.ts +42 -1
- package/dist/jsonForm/index.js +9 -1
- package/dist/markdown/index.d.ts +228 -3
- package/dist/markdown/index.js +42 -7
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +3 -2
- package/dist/schemas/index.d.ts +28 -8
- package/dist/schemas/index.js +36 -8
- package/dist/spatial/index.d.ts +9 -4
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +1 -1
- package/dist/story/index.d.ts +1021 -41
- package/dist/story/index.js +135 -8
- package/dist/{themeLibrary-BHjJ0Qx6.d.ts → themeLibrary-CehcJhzz.d.ts} +1 -1
- package/dist/timing/index.js +3 -5
- package/dist/transform/index.d.ts +48 -10
- package/dist/transform/index.js +17 -481
- package/dist/transform/index.js.map +1 -1
- package/dist/{types-BdZkdJ3z.d.ts → types-DlAZ7MW4.d.ts} +115 -1
- package/dist/versions/index.d.ts +1 -1
- package/package.json +6 -1
- package/src/__tests__/animationUtils.test.ts +40 -0
- package/src/__tests__/annotationCoercion.test.ts +243 -0
- package/src/__tests__/applyRenderStyle.test.ts +146 -0
- package/src/__tests__/atmosphereLayers.test.ts +108 -0
- package/src/__tests__/attrTokens.test.ts +162 -0
- package/src/__tests__/contentExtractor.test.ts +60 -0
- package/src/__tests__/coverBlock.test.ts +46 -1
- package/src/__tests__/customTemplateSample.test.ts +144 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +236 -0
- package/src/__tests__/customThemesFrontmatter.test.ts +145 -0
- package/src/__tests__/diagramBlock.test.ts +122 -0
- package/src/__tests__/diagramLayout.test.ts +134 -0
- package/src/__tests__/drawing.test.ts +109 -0
- package/src/__tests__/drawingBlock.test.ts +124 -0
- package/src/__tests__/drawingLayout.test.ts +171 -0
- package/src/__tests__/geohash.test.ts +6 -5
- package/src/__tests__/getLayers.test.ts +6 -2
- package/src/__tests__/getLayersFallback.test.ts +103 -0
- package/src/__tests__/imageEditExportSvg.test.ts +70 -0
- package/src/__tests__/imageEditVersions.test.ts +72 -0
- package/src/__tests__/inlineIconMarker.test.ts +36 -0
- package/src/__tests__/inputDescriptors.test.ts +162 -0
- package/src/__tests__/jsonForm.tokens.test.ts +84 -0
- package/src/__tests__/layoutBlock.test.ts +83 -0
- package/src/__tests__/layoutLayout.test.ts +169 -0
- package/src/__tests__/markdown.test.ts +87 -0
- package/src/__tests__/markdownSanitize.test.ts +79 -0
- package/src/__tests__/markdownToDoc.test.ts +391 -2
- package/src/__tests__/mediaAnnotations.test.ts +91 -0
- package/src/__tests__/mediaSchedule.test.ts +118 -0
- package/src/__tests__/pandocAttrParse.test.ts +187 -0
- package/src/__tests__/resolveDocTheme.test.ts +55 -0
- package/src/__tests__/rootExports.test.ts +43 -0
- package/src/__tests__/shapeGeometry.test.ts +89 -0
- package/src/__tests__/shapeVocabulary.test.ts +133 -0
- package/src/__tests__/structuredData.test.ts +249 -0
- package/src/__tests__/templateAnnotationParse.test.ts +108 -0
- package/src/__tests__/templateMetadata.test.ts +31 -0
- package/src/__tests__/templates.test.ts +257 -4
- package/src/__tests__/themeCompile.test.ts +42 -0
- package/src/__tests__/themeValidator.test.ts +6 -0
- package/src/__tests__/transformV2.test.ts +137 -0
- package/src/__tests__/transitionNormalize.test.ts +61 -0
- package/src/__tests__/validateDoc.test.ts +260 -0
- package/src/doc/annotationBlocks.ts +117 -0
- package/src/doc/customTemplatesFrontmatter.ts +314 -0
- package/src/doc/customThemesFrontmatter.ts +95 -0
- package/src/doc/docToMarkdown.ts +104 -5
- package/src/doc/getLayers.ts +49 -17
- package/src/doc/index.ts +47 -1
- package/src/doc/markdownToDoc.ts +411 -13
- package/src/doc/mediaAnnotations.ts +100 -0
- package/src/doc/resolveDocTheme.ts +55 -0
- package/src/doc/standaloneAnnotation.ts +58 -0
- package/src/doc/structuredData.ts +301 -0
- package/src/doc/templateInputs.ts +240 -0
- package/src/doc/templates/__tests__/customTemplate.test.ts +170 -0
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +110 -0
- package/src/doc/templates/accentImage.ts +30 -6
- package/src/doc/templates/captionUtils.ts +23 -0
- package/src/doc/templates/comparisonBar.ts +33 -18
- package/src/doc/templates/coverBlock.ts +35 -5
- package/src/doc/templates/customTemplate.ts +51 -0
- package/src/doc/templates/dataTable.ts +37 -19
- package/src/doc/templates/dateEvent.ts +41 -20
- package/src/doc/templates/definitionCard.ts +26 -18
- package/src/doc/templates/diagramBlock.ts +204 -0
- package/src/doc/templates/diagramLayout.ts +159 -0
- package/src/doc/templates/drawingBlock.ts +325 -0
- package/src/doc/templates/drawingLayout.ts +539 -0
- package/src/doc/templates/factCard.ts +54 -26
- package/src/doc/templates/fallbackBlock.ts +123 -0
- package/src/doc/templates/featureBlock.ts +20 -13
- package/src/doc/templates/fullBleedQuote.ts +18 -8
- package/src/doc/templates/imageWithCaption.ts +30 -15
- package/src/doc/templates/index.ts +225 -46
- package/src/doc/templates/inputDescriptors.ts +432 -0
- package/src/doc/templates/layoutBlock.ts +43 -0
- package/src/doc/templates/layoutLayout.ts +243 -0
- package/src/doc/templates/listBlock.ts +56 -30
- package/src/doc/templates/mapBlock.ts +15 -12
- package/src/doc/templates/metadata.ts +120 -0
- package/src/doc/templates/persistentLayers.ts +129 -11
- package/src/doc/templates/photoGrid.ts +22 -34
- package/src/doc/templates/pullQuote.ts +30 -12
- package/src/doc/templates/quoteBlock.ts +54 -29
- package/src/doc/templates/sectionHeader.ts +25 -11
- package/src/doc/templates/statHighlight.ts +39 -22
- package/src/doc/templates/titleBlock.ts +59 -21
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +487 -0
- package/src/doc/templates/tokens/resolveTokens.ts +453 -0
- package/src/doc/templates/twoColumn.ts +48 -30
- package/src/doc/templates/videoPullQuote.ts +22 -12
- package/src/doc/templates/videoWithCaption.ts +21 -15
- package/src/doc/utils/animationUtils.ts +267 -3
- package/src/doc/utils/applyRenderStyle.ts +113 -0
- package/src/doc/utils/imageTreatment.ts +70 -0
- package/src/doc/utils/nearest.ts +59 -0
- package/src/doc/utils/shapeGeometry.ts +464 -0
- package/src/doc/utils/themeUtils.ts +75 -1
- package/src/doc/validate.ts +575 -0
- package/src/generate/contentExtractor.ts +148 -35
- package/src/generate/index.ts +0 -3
- package/src/icons/index.ts +8 -0
- package/src/icons/inlineIconMarker.ts +73 -0
- package/src/imageEdit/export.ts +85 -2
- package/src/imageEdit/index.ts +1 -0
- package/src/imageEdit/persistence.ts +51 -0
- package/src/index.ts +2 -0
- package/src/jsonForm/index.ts +2 -0
- package/src/jsonForm/tokens.ts +78 -0
- package/src/markdown/annotationCoercion.ts +295 -0
- package/src/markdown/attrTokens.ts +241 -0
- package/src/markdown/convert.ts +229 -26
- package/src/markdown/index.ts +37 -0
- package/src/markdown/sanitize.ts +318 -0
- package/src/markdown/stringify.ts +96 -6
- package/src/markdown/types.ts +66 -0
- package/src/markdown/utils.ts +111 -2
- package/src/recommend/templates.ts +24 -0
- package/src/schemas/BlockTemplates.ts +133 -4
- package/src/schemas/CustomTemplates.ts +126 -0
- package/src/schemas/Doc.ts +387 -65
- package/src/schemas/ImageEditDoc.ts +11 -4
- package/src/schemas/Media.ts +169 -0
- package/src/schemas/Theme.ts +23 -1
- package/src/schemas/Transitions.ts +224 -0
- package/src/schemas/colorUtils.ts +33 -0
- package/src/schemas/fontStacks.ts +5 -2
- package/src/schemas/index.ts +3 -0
- package/src/schemas/themeCompile.ts +24 -5
- package/src/schemas/themeValidator.ts +49 -11
- package/src/schemas/themes/cinematic.json +69 -12
- package/src/schemas/themes/documentary.json +58 -11
- package/src/schemas/themes/gezellig.json +60 -11
- package/src/schemas/themes/magazine.json +54 -9
- package/src/schemas/themes/morning-light.json +52 -9
- package/src/schemas/themes/standard-dark.json +48 -13
- package/src/schemas/themes/standard.json +44 -12
- package/src/schemas/themes/tech-dark.json +65 -12
- package/src/spatial/Geohash.ts +52 -21
- package/src/storage/ContentContainer.ts +6 -2
- package/src/transform/applyTransform.ts +43 -4
- package/src/transform/index.ts +1 -0
- package/src/transform/registry.ts +44 -13
- package/src/transform/styles/dataDriven.ts +2 -1
- package/src/transform/styles/documentary.ts +2 -1
- package/src/transform/styles/magazine.ts +3 -1
- package/src/transform/styles/minimal.ts +2 -1
- package/src/transform/styles/narrative.ts +3 -1
- package/src/transform/templateSelector.ts +87 -11
- package/src/transform/types.ts +35 -2
- package/dist/chunk-2TMAWB4Y.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-3K5OG6KI.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js +0 -35
- package/dist/chunk-4X3JQXNM.js.map +0 -1
- package/dist/chunk-57CVQCFX.js.map +0 -1
- package/dist/chunk-5WFRKURX.js.map +0 -1
- package/dist/chunk-7UDSRZKG.js.map +0 -1
- package/dist/chunk-B4EEON3N.js.map +0 -1
- package/dist/chunk-FR2RBTKO.js.map +0 -1
- package/dist/chunk-H3AXU4MJ.js +0 -179
- package/dist/chunk-H3AXU4MJ.js.map +0 -1
- package/dist/chunk-K32VJONL.js.map +0 -1
- package/dist/chunk-KSWJR66U.js +0 -3706
- package/dist/chunk-KSWJR66U.js.map +0 -1
- package/dist/chunk-MYIH7FWD.js +0 -145
- package/dist/chunk-MYIH7FWD.js.map +0 -1
- package/dist/chunk-ZTX4PFFT.js.map +0 -1
- package/src/__tests__/slideshowGenerator.test.ts +0 -128
- package/src/generate/slideshowGenerator.ts +0 -273
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frontmatter serialization for user-defined custom themes.
|
|
3
|
+
*
|
|
4
|
+
* The theme analog of {@link ./customTemplatesFrontmatter.ts}. Custom Theme
|
|
5
|
+
* definitions live in the document's YAML frontmatter under the key
|
|
6
|
+
* `squisq-custom-themes`, stored as a single **compact JSON** object keyed
|
|
7
|
+
* by theme id:
|
|
8
|
+
*
|
|
9
|
+
* ```yaml
|
|
10
|
+
* squisq-custom-themes: {"my-brand":{"schemaVersion":"1","id":"my-brand",…}}
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Squisq's frontmatter parser is line-based; a JSON object literal
|
|
14
|
+
* round-trips through it verbatim (single line, no leading quote to strip),
|
|
15
|
+
* so the value is written **unquoted** and stays human-readable and diffable
|
|
16
|
+
* — the same mechanism the custom-templates codec relies on.
|
|
17
|
+
*
|
|
18
|
+
* Only one theme is *active* per doc (selected by id via the `squisq-theme`
|
|
19
|
+
* frontmatter key / `Doc.themeId`), but the payload is a keyed map — parallel
|
|
20
|
+
* to custom templates — so a doc can carry a small catalog and switch between
|
|
21
|
+
* them, and `resolveThemeForDoc` can resolve any of them doc-scoped.
|
|
22
|
+
*
|
|
23
|
+
* Malformed entries are dropped (via `validateTheme`) rather than failing the
|
|
24
|
+
* whole doc load, matching the tolerant behavior of the templates reader.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { Theme } from '../schemas/Theme.js';
|
|
28
|
+
import { FRONTMATTER_CUSTOM_THEMES_KEY } from '../schemas/Theme.js';
|
|
29
|
+
import { validateTheme } from '../schemas/themeValidator.js';
|
|
30
|
+
|
|
31
|
+
/** Re-export for callers that need the canonical key spelling. */
|
|
32
|
+
export { FRONTMATTER_CUSTOM_THEMES_KEY };
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Normalize the raw frontmatter value into an array of candidate objects.
|
|
36
|
+
* Accepts, in order: a JSON string (current, from the line-based parser),
|
|
37
|
+
* an already-parsed object map (keyed by id), and an array (in case a richer
|
|
38
|
+
* YAML parser delivers one). Returns undefined when absent/unparseable.
|
|
39
|
+
*/
|
|
40
|
+
function normalizeCandidates(raw: unknown): unknown[] | undefined {
|
|
41
|
+
if (raw === undefined || raw === null) return undefined;
|
|
42
|
+
let value: unknown = raw;
|
|
43
|
+
if (typeof value === 'string') {
|
|
44
|
+
const trimmed = value.trim();
|
|
45
|
+
if (!trimmed) return undefined;
|
|
46
|
+
try {
|
|
47
|
+
value = JSON.parse(trimmed);
|
|
48
|
+
} catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(value)) return value;
|
|
53
|
+
if (value && typeof value === 'object') {
|
|
54
|
+
return Object.values(value as Record<string, unknown>);
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Read the custom themes inlined into a document's frontmatter. Returns
|
|
61
|
+
* undefined when the key is absent or holds no valid theme, so callers can
|
|
62
|
+
* omit the field from the Doc.
|
|
63
|
+
*/
|
|
64
|
+
export function readCustomThemesFromFrontmatter(
|
|
65
|
+
frontmatter: Record<string, unknown> | undefined,
|
|
66
|
+
): Theme[] | undefined {
|
|
67
|
+
if (!frontmatter) return undefined;
|
|
68
|
+
const candidates = normalizeCandidates(frontmatter[FRONTMATTER_CUSTOM_THEMES_KEY]);
|
|
69
|
+
if (!candidates) return undefined;
|
|
70
|
+
const out: Theme[] = [];
|
|
71
|
+
for (const entry of candidates) {
|
|
72
|
+
const result = validateTheme(entry);
|
|
73
|
+
if (result.valid && result.theme) out.push(result.theme);
|
|
74
|
+
}
|
|
75
|
+
return out.length > 0 ? out : undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Encode a list of custom themes into the compact JSON object described in
|
|
80
|
+
* the module header (keyed by theme id). Returns undefined when the input is
|
|
81
|
+
* empty so callers can leave the key off the output.
|
|
82
|
+
*/
|
|
83
|
+
export function writeCustomThemesToFrontmatter(
|
|
84
|
+
themes: readonly Theme[] | undefined,
|
|
85
|
+
options?: { pretty?: boolean },
|
|
86
|
+
): string | undefined {
|
|
87
|
+
if (!themes || themes.length === 0) return undefined;
|
|
88
|
+
const map: Record<string, Theme> = {};
|
|
89
|
+
for (const theme of themes) map[theme.id] = theme;
|
|
90
|
+
// Pretty output is multi-line, so it serializes as a YAML literal block
|
|
91
|
+
// scalar (see the markdown stringify frontmatter path) and reads back via
|
|
92
|
+
// `JSON.parse`. Default stays compact (single line) so existing docs and
|
|
93
|
+
// snapshots are byte-unchanged.
|
|
94
|
+
return JSON.stringify(map, null, options?.pretty ? 2 : undefined);
|
|
95
|
+
}
|
package/src/doc/docToMarkdown.ts
CHANGED
|
@@ -23,7 +23,21 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import type { Doc, Block } from '../schemas/Doc.js';
|
|
26
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
MarkdownDocument,
|
|
28
|
+
MarkdownBlockNode,
|
|
29
|
+
MarkdownHeading,
|
|
30
|
+
MarkdownParagraph,
|
|
31
|
+
} from '../markdown/types.js';
|
|
32
|
+
import { serializeAnnotation } from '../markdown/attrTokens.js';
|
|
33
|
+
import {
|
|
34
|
+
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
35
|
+
writeCustomTemplatesToFrontmatter,
|
|
36
|
+
} from './customTemplatesFrontmatter.js';
|
|
37
|
+
import {
|
|
38
|
+
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
39
|
+
writeCustomThemesToFrontmatter,
|
|
40
|
+
} from './customThemesFrontmatter.js';
|
|
27
41
|
|
|
28
42
|
/**
|
|
29
43
|
* Convert a Doc with heading-driven blocks back to a MarkdownDocument.
|
|
@@ -47,6 +61,12 @@ export function docToMarkdown(doc: Doc): MarkdownDocument {
|
|
|
47
61
|
if (block.sourceHeading) {
|
|
48
62
|
const heading = ensureAnnotation(block, block.sourceHeading);
|
|
49
63
|
children.push(heading);
|
|
64
|
+
} else if (block.standaloneAnnotation) {
|
|
65
|
+
// Heading-less standalone block: re-emit its `{[…]}` annotation as a
|
|
66
|
+
// paragraph before its contents. The serializer's quoting is paired
|
|
67
|
+
// with the tokenizer, and stringifyMarkdown un-escapes `{[…]}` spans,
|
|
68
|
+
// so the annotation round-trips.
|
|
69
|
+
children.push(synthesizeAnnotationParagraph(block));
|
|
50
70
|
}
|
|
51
71
|
|
|
52
72
|
// Emit body content
|
|
@@ -66,33 +86,112 @@ export function docToMarkdown(doc: Doc): MarkdownDocument {
|
|
|
66
86
|
emitBlock(block);
|
|
67
87
|
}
|
|
68
88
|
|
|
89
|
+
// Merge `Doc.customTemplates` into the outgoing frontmatter so the
|
|
90
|
+
// markdown remains the source-of-truth: edits made via the editor's
|
|
91
|
+
// TemplateDesigner round-trip through `docToMarkdown` →
|
|
92
|
+
// `stringifyMarkdown` and are visible to anyone reading the file.
|
|
93
|
+
const customPayload = writeCustomTemplatesToFrontmatter(doc.customTemplates);
|
|
94
|
+
let frontmatter = doc.frontmatter;
|
|
95
|
+
if (customPayload) {
|
|
96
|
+
frontmatter = { ...(frontmatter ?? {}), [FRONTMATTER_CUSTOM_TEMPLATES_KEY]: customPayload };
|
|
97
|
+
} else if (frontmatter && FRONTMATTER_CUSTOM_TEMPLATES_KEY in frontmatter) {
|
|
98
|
+
// The doc has no custom templates anymore — drop the stale
|
|
99
|
+
// frontmatter key so the markdown reflects the current state.
|
|
100
|
+
const { [FRONTMATTER_CUSTOM_TEMPLATES_KEY]: _drop, ...rest } = frontmatter;
|
|
101
|
+
void _drop;
|
|
102
|
+
frontmatter = rest;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Mirror the same round-trip for `Doc.customThemes` (the theme analog).
|
|
106
|
+
const customThemesPayload = writeCustomThemesToFrontmatter(doc.customThemes);
|
|
107
|
+
if (customThemesPayload) {
|
|
108
|
+
frontmatter = { ...(frontmatter ?? {}), [FRONTMATTER_CUSTOM_THEMES_KEY]: customThemesPayload };
|
|
109
|
+
} else if (frontmatter && FRONTMATTER_CUSTOM_THEMES_KEY in frontmatter) {
|
|
110
|
+
const { [FRONTMATTER_CUSTOM_THEMES_KEY]: _dropTheme, ...rest } = frontmatter;
|
|
111
|
+
void _dropTheme;
|
|
112
|
+
frontmatter = rest;
|
|
113
|
+
}
|
|
114
|
+
|
|
69
115
|
return {
|
|
70
116
|
type: 'document',
|
|
71
117
|
children,
|
|
118
|
+
...(frontmatter && Object.keys(frontmatter).length > 0 ? { frontmatter } : {}),
|
|
72
119
|
};
|
|
73
120
|
}
|
|
74
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Build the synthesized annotation paragraph for a heading-less standalone
|
|
124
|
+
* block: `{[templateName key=value …]}` from its `sourceAnnotation.template`
|
|
125
|
+
* and current `templateOverrides` (edits round-trip through the latter).
|
|
126
|
+
*/
|
|
127
|
+
function synthesizeAnnotationParagraph(block: Block): MarkdownParagraph {
|
|
128
|
+
const text = serializeAnnotation(block.sourceAnnotation?.template, block.templateOverrides);
|
|
129
|
+
return { type: 'paragraph', children: [{ type: 'text', value: text }] };
|
|
130
|
+
}
|
|
131
|
+
|
|
75
132
|
/**
|
|
76
133
|
* Ensure the heading's `templateAnnotation` reflects the block's
|
|
77
134
|
* template and templateOverrides. Returns a (possibly cloned) heading.
|
|
78
135
|
*/
|
|
79
136
|
function ensureAnnotation(block: Block, heading: MarkdownHeading): MarkdownHeading {
|
|
80
|
-
|
|
81
|
-
if (heading.templateAnnotation) return heading;
|
|
137
|
+
const attrs = ensureTransitionAttributes(block, heading);
|
|
82
138
|
|
|
83
139
|
// If the block has a non-default template or overrides, inject an annotation
|
|
84
|
-
const hasExplicitTemplate =
|
|
140
|
+
const hasExplicitTemplate =
|
|
141
|
+
block.template && block.template !== 'sectionHeader' && block.autoTemplate !== true;
|
|
85
142
|
const hasOverrides = block.templateOverrides && Object.keys(block.templateOverrides).length > 0;
|
|
86
143
|
|
|
87
|
-
|
|
144
|
+
// If the heading already has an annotation, trust it (it came from parsing).
|
|
145
|
+
// Transition attrs may still have been injected above if the block changed.
|
|
146
|
+
if (heading.templateAnnotation) {
|
|
147
|
+
return attrs === heading.attributes ? heading : { ...heading, attributes: attrs };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!hasExplicitTemplate && !hasOverrides) {
|
|
151
|
+
return attrs === heading.attributes ? heading : { ...heading, attributes: attrs };
|
|
152
|
+
}
|
|
88
153
|
|
|
89
154
|
// Clone to avoid mutating the original
|
|
90
155
|
return {
|
|
91
156
|
...heading,
|
|
92
157
|
children: [...heading.children],
|
|
158
|
+
attributes: attrs,
|
|
93
159
|
templateAnnotation: {
|
|
94
160
|
template: block.template ?? 'sectionHeader',
|
|
95
161
|
...(hasOverrides ? { params: block.templateOverrides } : {}),
|
|
96
162
|
},
|
|
97
163
|
};
|
|
98
164
|
}
|
|
165
|
+
|
|
166
|
+
function ensureTransitionAttributes(
|
|
167
|
+
block: Block,
|
|
168
|
+
heading: MarkdownHeading,
|
|
169
|
+
): MarkdownHeading['attributes'] {
|
|
170
|
+
const transition = block.transition;
|
|
171
|
+
if (!transition) return heading.attributes;
|
|
172
|
+
|
|
173
|
+
// The transition is deliberately written to BOTH channels, which serve
|
|
174
|
+
// different consumers:
|
|
175
|
+
// - `params` is what `stringifyMarkdown` serializes into the Pandoc `{…}`
|
|
176
|
+
// attribute text (serializePandocAttributes reads only id/classes/params).
|
|
177
|
+
// - `blockMeta` is what `markdownToDoc` reads back directly (makeBlock,
|
|
178
|
+
// pinnedHeadingMeta) — an in-memory Doc → MarkdownDocument → Doc round
|
|
179
|
+
// trip never re-parses params, so a stale/missing `blockMeta.transition`
|
|
180
|
+
// would lose or resurrect the wrong transition.
|
|
181
|
+
const attrs = heading.attributes ?? {};
|
|
182
|
+
return {
|
|
183
|
+
...attrs,
|
|
184
|
+
params: {
|
|
185
|
+
...(attrs.params ?? {}),
|
|
186
|
+
transition: transition.type,
|
|
187
|
+
...(transition.duration !== undefined
|
|
188
|
+
? { transitionDuration: String(transition.duration) }
|
|
189
|
+
: {}),
|
|
190
|
+
...(transition.direction ? { transitionDirection: transition.direction } : {}),
|
|
191
|
+
},
|
|
192
|
+
blockMeta: {
|
|
193
|
+
...(attrs.blockMeta ?? {}),
|
|
194
|
+
transition,
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
package/src/doc/getLayers.ts
CHANGED
|
@@ -35,7 +35,10 @@ import { VIEWPORT_PRESETS } from '../schemas/Viewport.js';
|
|
|
35
35
|
import { createTemplateContext, isTemplateBlock } from '../schemas/BlockTemplates.js';
|
|
36
36
|
import { DEFAULT_THEME } from '../schemas/themeLibrary.js';
|
|
37
37
|
import { templateRegistry, resolveTemplateName } from './templates/index.js';
|
|
38
|
-
import {
|
|
38
|
+
import { coerceTemplateParams } from './templates/inputDescriptors.js';
|
|
39
|
+
import { expandPersistentLayers, wrapWithPersistentLayers } from './templates/persistentLayers.js';
|
|
40
|
+
import { applyRenderStyleToLayers } from './utils/applyRenderStyle.js';
|
|
41
|
+
import { fallbackBlockLayers } from './templates/fallbackBlock.js';
|
|
39
42
|
|
|
40
43
|
// ============================================
|
|
41
44
|
// RenderContext
|
|
@@ -109,9 +112,30 @@ export function getLayers(block: DocBlock, context: RenderContext = {}): Layer[]
|
|
|
109
112
|
// and the layer list comes back empty.
|
|
110
113
|
if (isTemplateBlock(block)) {
|
|
111
114
|
const resolved = resolveTemplateName(block.template);
|
|
115
|
+
const templateCtx = createTemplateContext(theme, blockIndex, totalBlocks, viewport);
|
|
112
116
|
if (resolved in templateRegistry) {
|
|
113
117
|
const templateName = resolved as keyof typeof templateRegistry;
|
|
114
|
-
|
|
118
|
+
// Aggregate templates (e.g. `diagram`) consume the block's children.
|
|
119
|
+
const maybeChildren = (block as Block).children;
|
|
120
|
+
if (maybeChildren && maybeChildren.length > 0) {
|
|
121
|
+
templateCtx.children = maybeChildren;
|
|
122
|
+
}
|
|
123
|
+
// Effective template input: the block's own fields, then structured
|
|
124
|
+
// body data (```json data fences, GFM tables), then `{[…]}` string
|
|
125
|
+
// overrides — the same merge order buildPreviewDoc uses. Inline overrides
|
|
126
|
+
// are coerced to their typed shape (`center="47.6,-122.3"` → `{lat,lng}`,
|
|
127
|
+
// `zoom=9` → `9`) so pure-inline annotations render without any change to
|
|
128
|
+
// the template functions. `block.templateOverrides` itself stays raw
|
|
129
|
+
// strings for lossless round-tripping — only this ephemeral input is coerced.
|
|
130
|
+
const { templateData, templateOverrides } = block as Block;
|
|
131
|
+
const input =
|
|
132
|
+
templateData || templateOverrides
|
|
133
|
+
? ({
|
|
134
|
+
...block,
|
|
135
|
+
...templateData,
|
|
136
|
+
...coerceTemplateParams(block.template, templateOverrides ?? {}).input,
|
|
137
|
+
} as TemplateBlock)
|
|
138
|
+
: block;
|
|
115
139
|
let layers: Layer[];
|
|
116
140
|
try {
|
|
117
141
|
// Each registry entry accepts its specific TemplateBlock variant; the
|
|
@@ -120,21 +144,34 @@ export function getLayers(block: DocBlock, context: RenderContext = {}): Layer[]
|
|
|
120
144
|
input: TemplateBlock,
|
|
121
145
|
ctx: TemplateContext,
|
|
122
146
|
) => Layer[];
|
|
123
|
-
layers = templateFn(
|
|
147
|
+
layers = templateFn(input, templateCtx);
|
|
124
148
|
if (!Array.isArray(layers)) {
|
|
125
|
-
console.
|
|
126
|
-
layers =
|
|
149
|
+
console.warn(`Template ${templateName} did not return an array, got:`, typeof layers);
|
|
150
|
+
layers = fallbackBlockLayers(block, templateCtx, `Template "${block.template}" failed`);
|
|
127
151
|
}
|
|
128
152
|
} catch (err: unknown) {
|
|
129
|
-
console.
|
|
130
|
-
layers =
|
|
153
|
+
console.warn(`Error expanding template ${templateName}:`, err);
|
|
154
|
+
layers = fallbackBlockLayers(block, templateCtx, `Template "${block.template}" failed`);
|
|
131
155
|
}
|
|
132
156
|
|
|
157
|
+
// Theme motion defaults apply to template-generated layers only
|
|
158
|
+
// (mirrors expandDocBlocks — the two paths must agree).
|
|
159
|
+
layers = applyRenderStyleToLayers(layers, block as Block, theme);
|
|
160
|
+
|
|
133
161
|
return injectPersistentLayers(layers, block, context);
|
|
134
162
|
}
|
|
163
|
+
|
|
164
|
+
// Unknown template — graceful-degradation guarantee: render the
|
|
165
|
+
// block's heading + body text as a plain card with a visible notice
|
|
166
|
+
// instead of a blank slide.
|
|
167
|
+
return injectPersistentLayers(
|
|
168
|
+
fallbackBlockLayers(block, templateCtx, `Unknown template "${block.template}"`),
|
|
169
|
+
block,
|
|
170
|
+
context,
|
|
171
|
+
);
|
|
135
172
|
}
|
|
136
173
|
|
|
137
|
-
// 3. Fallback: no layers and no
|
|
174
|
+
// 3. Fallback: no layers and no template requested
|
|
138
175
|
return injectPersistentLayers([], block, context);
|
|
139
176
|
}
|
|
140
177
|
|
|
@@ -150,14 +187,9 @@ function injectPersistentLayers(layers: Layer[], block: DocBlock, context: Rende
|
|
|
150
187
|
const { persistentLayers } = context;
|
|
151
188
|
if (!persistentLayers) return layers;
|
|
152
189
|
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
if (bottomLayers.length === 0 && topLayers.length === 0) return layers;
|
|
157
|
-
|
|
158
|
-
const templateBlock = block as TemplateBlock;
|
|
159
|
-
const useBottom = templateBlock.useBottomLayer !== false;
|
|
160
|
-
const useTop = templateBlock.useTopLayer !== false;
|
|
190
|
+
const theme = context.theme ?? DEFAULT_THEME;
|
|
191
|
+
const bottomLayers = expandPersistentLayers(persistentLayers.bottomLayers, theme);
|
|
192
|
+
const topLayers = expandPersistentLayers(persistentLayers.topLayers, theme);
|
|
161
193
|
|
|
162
|
-
return
|
|
194
|
+
return wrapWithPersistentLayers(layers, block as TemplateBlock, bottomLayers, topLayers);
|
|
163
195
|
}
|
package/src/doc/index.ts
CHANGED
|
@@ -1,9 +1,55 @@
|
|
|
1
1
|
export * from './templates/index.js';
|
|
2
2
|
export * from './utils/animationUtils.js';
|
|
3
3
|
export * from './utils/themeUtils.js';
|
|
4
|
-
export
|
|
4
|
+
export * from './utils/applyRenderStyle.js';
|
|
5
|
+
export * from './utils/imageTreatment.js';
|
|
6
|
+
export * from './templateInputs.js';
|
|
7
|
+
export * from './utils/shapeGeometry.js';
|
|
8
|
+
export {
|
|
9
|
+
markdownToDoc,
|
|
10
|
+
flattenBlocks,
|
|
11
|
+
flattenRenderableBlocks,
|
|
12
|
+
countBlocks,
|
|
13
|
+
getBlockDepth,
|
|
14
|
+
} from './markdownToDoc.js';
|
|
5
15
|
export type { MarkdownToDocOptions } from './markdownToDoc.js';
|
|
6
16
|
export { docToMarkdown } from './docToMarkdown.js';
|
|
17
|
+
export {
|
|
18
|
+
encodeLayersForFrontmatter,
|
|
19
|
+
decodeLayersFromFrontmatter,
|
|
20
|
+
readCustomTemplatesFromFrontmatter,
|
|
21
|
+
writeCustomTemplatesToFrontmatter,
|
|
22
|
+
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
23
|
+
} from './customTemplatesFrontmatter.js';
|
|
24
|
+
export {
|
|
25
|
+
readCustomThemesFromFrontmatter,
|
|
26
|
+
writeCustomThemesToFrontmatter,
|
|
27
|
+
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
28
|
+
} from './customThemesFrontmatter.js';
|
|
29
|
+
export { resolveThemeForDoc } from './resolveDocTheme.js';
|
|
7
30
|
export { getLayers } from './getLayers.js';
|
|
8
31
|
export type { RenderContext } from './getLayers.js';
|
|
9
32
|
export { resolveAudioMapping, scoreTextSimilarity } from './audioMapping.js';
|
|
33
|
+
export {
|
|
34
|
+
isDataFence,
|
|
35
|
+
parseDataFence,
|
|
36
|
+
replaceDataFence,
|
|
37
|
+
parseYamlSubset,
|
|
38
|
+
findFirstTable,
|
|
39
|
+
extractTableData,
|
|
40
|
+
} from './structuredData.js';
|
|
41
|
+
export type { DataFenceParseResult, ExtractedTableData } from './structuredData.js';
|
|
42
|
+
export { validateMarkdownSource, validateMarkdownDoc } from './validate.js';
|
|
43
|
+
export type { ValidateOptions, MarkdownValidationResult } from './validate.js';
|
|
44
|
+
export { fallbackBlockLayers } from './templates/fallbackBlock.js';
|
|
45
|
+
export {
|
|
46
|
+
BASE_INPUT_DESCRIPTORS,
|
|
47
|
+
TEMPLATE_INPUT_DESCRIPTORS,
|
|
48
|
+
coerceTemplateParams,
|
|
49
|
+
lintTemplateParams,
|
|
50
|
+
} from './templates/inputDescriptors.js';
|
|
51
|
+
export type {
|
|
52
|
+
InputCoercion,
|
|
53
|
+
TemplateInputDescriptor,
|
|
54
|
+
TemplateParamFinding,
|
|
55
|
+
} from './templates/inputDescriptors.js';
|