@bendyline/squisq 1.5.1 → 2.0.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 +63 -10
- package/dist/{Doc-BBVGq1_9.d.ts → Doc-ylqWKDc_.d.ts} +248 -37
- package/dist/{ImageEditDoc-FuyGtt6o.d.ts → ImageEditDoc-D828IXJ1.d.ts} +1 -1
- package/dist/annotationCoercion-Dr_DY9Hx.d.ts +86 -0
- package/dist/{chunk-VWUFZ6ZG.js → chunk-3E5F2XMR.js} +2 -29
- package/dist/chunk-3E5F2XMR.js.map +1 -0
- package/dist/chunk-4X3JQXNM.js +35 -0
- package/dist/chunk-4X3JQXNM.js.map +1 -0
- package/dist/{chunk-2OIBZYKP.js → chunk-5DKBFXPY.js} +31 -121
- package/dist/chunk-5DKBFXPY.js.map +1 -0
- package/dist/{chunk-DLXZMS5K.js → chunk-5J4HKRJF.js} +51 -3
- package/dist/chunk-5J4HKRJF.js.map +1 -0
- package/dist/chunk-5UYI3RJB.js +2503 -0
- package/dist/chunk-5UYI3RJB.js.map +1 -0
- package/dist/{chunk-TEEEILMP.js → chunk-66QO7XFB.js} +19 -292
- package/dist/chunk-66QO7XFB.js.map +1 -0
- package/dist/{chunk-KKNUBQ6Y.js → chunk-6PJRB2CF.js} +156 -91
- package/dist/chunk-6PJRB2CF.js.map +1 -0
- package/dist/{chunk-HWVFJAAH.js → chunk-AMIR72JP.js} +28 -10
- package/dist/chunk-AMIR72JP.js.map +1 -0
- package/dist/chunk-FVJUUTEM.js +74 -0
- package/dist/chunk-FVJUUTEM.js.map +1 -0
- package/dist/{chunk-LH7I6SH7.js → chunk-GF3BVNLU.js} +6360 -5723
- package/dist/chunk-GF3BVNLU.js.map +1 -0
- package/dist/{chunk-Q3ROPT5H.js → chunk-GZY66SDN.js} +1 -1
- package/dist/{chunk-Q3ROPT5H.js.map → chunk-GZY66SDN.js.map} +1 -1
- package/dist/chunk-JOQYPRDZ.js +127 -0
- package/dist/chunk-JOQYPRDZ.js.map +1 -0
- package/dist/{chunk-A4O7GIWE.js → chunk-LYNJEOAC.js} +10 -73
- package/dist/chunk-LYNJEOAC.js.map +1 -0
- package/dist/{chunk-LDQ2HJIX.js → chunk-PXLVXTLW.js} +252 -54
- package/dist/chunk-PXLVXTLW.js.map +1 -0
- package/dist/{chunk-TQWLI6S2.js → chunk-Q7LROV2H.js} +4 -2
- package/dist/{chunk-TQWLI6S2.js.map → chunk-Q7LROV2H.js.map} +1 -1
- package/dist/{chunk-T5UK6YOB.js → chunk-QTSJOY54.js} +60 -17
- package/dist/chunk-QTSJOY54.js.map +1 -0
- package/dist/chunk-QVANWDPH.js +2358 -0
- package/dist/chunk-QVANWDPH.js.map +1 -0
- package/dist/{chunk-6ATE2PSM.js → chunk-R2GC6RLD.js} +7 -7
- package/dist/chunk-R2GC6RLD.js.map +1 -0
- package/dist/chunk-R2YZTCLO.js +292 -0
- package/dist/chunk-R2YZTCLO.js.map +1 -0
- package/dist/chunk-S7A5D7ZJ.js +174 -0
- package/dist/chunk-S7A5D7ZJ.js.map +1 -0
- package/dist/chunk-T3TI7GSZ.js +884 -0
- package/dist/chunk-T3TI7GSZ.js.map +1 -0
- package/dist/{chunk-RUDYOTA6.js → chunk-TUWMK62B.js} +110 -4
- package/dist/chunk-TUWMK62B.js.map +1 -0
- package/dist/{chunk-IMSCRLLV.js → chunk-VR7UPJ7C.js} +35 -25
- package/dist/chunk-VR7UPJ7C.js.map +1 -0
- package/dist/doc/index.d.ts +2334 -5
- package/dist/doc/index.js +134 -34
- package/dist/generate/index.d.ts +7 -2
- package/dist/generate/index.js +1 -1
- package/dist/imageEdit/index.d.ts +9 -6
- package/dist/imageEdit/index.js +3 -3
- package/dist/index.d.ts +12 -10
- package/dist/index.js +253 -81
- package/dist/jsonForm/index.d.ts +7 -3
- package/dist/jsonForm/index.js +9 -4
- package/dist/markdown/index.d.ts +6 -70
- package/dist/markdown/index.js +13 -9
- package/dist/narration/index.d.ts +618 -0
- package/dist/narration/index.js +82 -0
- package/dist/recommend/index.d.ts +15 -1
- package/dist/recommend/index.js +2 -2
- package/dist/schemas/index.d.ts +28 -6
- package/dist/schemas/index.js +15 -13
- package/dist/spatial/index.d.ts +0 -1
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/{themeLibrary-CehcJhzz.d.ts → themeLibrary-RjVgLpUi.d.ts} +10 -11
- package/dist/timing/index.js +5 -3
- package/dist/transform/index.d.ts +35 -24
- package/dist/transform/index.js +9 -10
- package/dist/{types-DlAZ7MW4.d.ts → types-BwMPl2CB.d.ts} +1 -1
- package/dist/{types-D98li1gV.d.ts → types-C4kiRn_k.d.ts} +3 -1
- package/dist/versions/index.d.ts +2 -1
- package/dist/versions/index.js +2 -2
- package/package.json +6 -6
- package/src/__tests__/applyNarrationTiming.test.ts +190 -0
- package/src/__tests__/applyRenderStyle.test.ts +3 -3
- package/src/__tests__/asciiDiagramBattle.test.ts +246 -0
- package/src/__tests__/asciiDiagramDetect.test.ts +162 -0
- package/src/__tests__/asciiDiagramMapping.test.ts +38 -0
- package/src/__tests__/asciiDiagramParse.test.ts +233 -0
- package/src/__tests__/asciiDiagramPipeline.test.ts +273 -0
- package/src/__tests__/asciiDiagramRender.test.ts +162 -0
- package/src/__tests__/asciiDiagramRepair.test.ts +84 -0
- package/src/__tests__/asciiTimelineDetect.test.ts +157 -0
- package/src/__tests__/asciiTimelineParse.test.ts +205 -0
- package/src/__tests__/asciiTimelinePipeline.test.ts +349 -0
- package/src/__tests__/asciiTimelineRender.test.ts +376 -0
- package/src/__tests__/attrTokens.test.ts +5 -0
- package/src/__tests__/contentContainer.test.ts +43 -0
- package/src/__tests__/coverBlock.test.ts +33 -2
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -15
- package/src/__tests__/dataTable.test.ts +25 -15
- package/src/__tests__/diagramBlock.test.ts +3 -3
- package/src/__tests__/diagramText.test.ts +26 -0
- package/src/__tests__/docToMarkdownMedia.test.ts +83 -0
- package/src/__tests__/drawingBlock.test.ts +3 -3
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +512 -0
- package/src/__tests__/fixtures/asciiDiagrams.ts +287 -0
- package/src/__tests__/fixtures/asciiTimelines.ts +35 -0
- package/src/__tests__/fixtures/treeviewFixtures.ts +243 -0
- package/src/__tests__/getLayers.test.ts +32 -18
- package/src/__tests__/getLayersFallback.test.ts +8 -8
- package/src/__tests__/imageEditVersions.test.ts +2 -0
- package/src/__tests__/jsonForm.pointer.test.ts +47 -1
- package/src/__tests__/layoutBlock.test.ts +3 -3
- package/src/__tests__/majorApiTypes.test.ts +18 -0
- package/src/__tests__/markdown.test.ts +41 -0
- package/src/__tests__/markdownToDoc.test.ts +5 -2
- package/src/__tests__/matchFontFamily.test.ts +114 -0
- package/src/__tests__/materializeBlockLayers.test.ts +135 -0
- package/src/__tests__/materializeTestUtils.ts +17 -0
- package/src/__tests__/narrationAlign.test.ts +150 -0
- package/src/__tests__/narrationFeatures.test.ts +71 -0
- package/src/__tests__/narrationNuclei.test.ts +45 -0
- package/src/__tests__/narrationPacing.test.ts +189 -0
- package/src/__tests__/narrationScript.test.ts +149 -0
- package/src/__tests__/narrationSessionRepro.test.ts +62 -0
- package/src/__tests__/narrationSidecar.test.ts +88 -0
- package/src/__tests__/narrationSyllables.test.ts +65 -0
- package/src/__tests__/narrationTestSignals.ts +167 -0
- package/src/__tests__/narrationVad.test.ts +66 -0
- package/src/__tests__/resolveDocTheme.test.ts +16 -2
- package/src/__tests__/rootExports.test.ts +18 -0
- package/src/__tests__/scopedContentContainer.test.ts +20 -0
- package/src/__tests__/shapeGeometry.test.ts +49 -0
- package/src/__tests__/templateAnnotationParse.test.ts +10 -0
- package/src/__tests__/templateInputs.test.ts +69 -0
- package/src/__tests__/templateMetadata.test.ts +2 -1
- package/src/__tests__/templates.test.ts +143 -17
- package/src/__tests__/themeCompile.test.ts +49 -22
- package/src/__tests__/transformProvenance.test.ts +160 -0
- package/src/__tests__/transformV2.test.ts +40 -14
- package/src/__tests__/treeviewBattle.test.ts +76 -0
- package/src/__tests__/treeviewDetect.test.ts +168 -0
- package/src/__tests__/treeviewParse.test.ts +118 -0
- package/src/__tests__/treeviewPipeline.test.ts +183 -0
- package/src/__tests__/treeviewRender.test.ts +91 -0
- package/src/__tests__/versions.test.ts +44 -0
- package/src/doc/applyNarrationTiming.ts +244 -0
- package/src/doc/asciiDiagram/chars.ts +210 -0
- package/src/doc/asciiDiagram/detect.ts +175 -0
- package/src/doc/asciiDiagram/index.ts +38 -0
- package/src/doc/asciiDiagram/mapping.ts +225 -0
- package/src/doc/asciiDiagram/parse.ts +1095 -0
- package/src/doc/asciiDiagram/render.ts +963 -0
- package/src/doc/asciiDiagram/repair.ts +400 -0
- package/src/doc/asciiDiagram/types.ts +65 -0
- package/src/doc/asciiTimeline/detect.ts +138 -0
- package/src/doc/asciiTimeline/index.ts +26 -0
- package/src/doc/asciiTimeline/mapping.ts +43 -0
- package/src/doc/asciiTimeline/parse.ts +870 -0
- package/src/doc/asciiTimeline/render.ts +427 -0
- package/src/doc/asciiTimeline/types.ts +73 -0
- package/src/doc/asciiTimeline/wrappedFlow.ts +427 -0
- package/src/doc/audioMapping.ts +60 -46
- package/src/doc/customTemplatesFrontmatter.ts +0 -41
- package/src/doc/docToMarkdown.ts +126 -39
- package/src/doc/index.ts +76 -4
- package/src/doc/markdownToDoc.ts +135 -1
- package/src/doc/materializeBlockLayers.ts +304 -0
- package/src/doc/mediaAnnotations.ts +20 -0
- package/src/doc/resolveDocTheme.ts +8 -7
- package/src/doc/templateInputs.ts +185 -2
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +22 -8
- package/src/doc/templates/coverBlock.ts +49 -13
- package/src/doc/templates/diagramBlock.ts +237 -38
- package/src/doc/templates/drawingBlock.ts +2 -2
- package/src/doc/templates/fallbackBlock.ts +1 -1
- package/src/doc/templates/index.ts +134 -279
- package/src/doc/templates/inputDescriptors.ts +20 -1
- package/src/doc/templates/metadata.ts +10 -0
- package/src/doc/templates/persistentLayers.ts +12 -126
- package/src/doc/templates/registry.ts +88 -0
- package/src/doc/templates/templateNames.ts +22 -0
- package/src/doc/templates/timelineBlock.ts +613 -0
- package/src/doc/templates/treeBlock.ts +131 -0
- package/src/doc/treeview/chars.ts +72 -0
- package/src/doc/treeview/detect.ts +145 -0
- package/src/doc/treeview/index.ts +30 -0
- package/src/doc/treeview/mapping.ts +95 -0
- package/src/doc/treeview/parse.ts +201 -0
- package/src/doc/treeview/render.ts +41 -0
- package/src/doc/treeview/types.ts +43 -0
- package/src/doc/utils/applyRenderStyle.ts +2 -9
- package/src/doc/utils/diagramText.ts +78 -0
- package/src/doc/utils/shapeGeometry.ts +157 -7
- package/src/doc/validate.ts +1 -1
- package/src/generate/templateMapper.ts +7 -0
- package/src/imageEdit/export.ts +6 -5
- package/src/imageEdit/versionPaths.ts +13 -26
- package/src/imageEdit/versions.ts +21 -100
- package/src/index.ts +1 -0
- package/src/internal/immutable.ts +58 -0
- package/src/jsonForm/index.ts +9 -1
- package/src/jsonForm/pointer.ts +68 -23
- package/src/markdown/attrTokens.ts +7 -5
- package/src/markdown/convert.ts +11 -1
- package/src/markdown/index.ts +1 -0
- package/src/markdown/stringify.ts +4 -9
- package/src/markdown/utils.ts +36 -14
- package/src/narration/align.ts +514 -0
- package/src/narration/features.ts +231 -0
- package/src/narration/index.ts +86 -0
- package/src/narration/nuclei.ts +118 -0
- package/src/narration/pacing.ts +211 -0
- package/src/narration/script.ts +239 -0
- package/src/narration/session.ts +100 -0
- package/src/narration/sidecar.ts +187 -0
- package/src/narration/syllables.ts +85 -0
- package/src/narration/trace.ts +50 -0
- package/src/narration/types.ts +299 -0
- package/src/narration/vad.ts +131 -0
- package/src/recommend/numberHighlight.ts +25 -0
- package/src/recommend/templates.ts +108 -12
- package/src/schemas/BlockTemplates.ts +156 -7
- package/src/schemas/Doc.ts +72 -9
- package/src/schemas/Media.ts +12 -2
- package/src/schemas/Theme.ts +45 -25
- package/src/schemas/Viewport.ts +2 -2
- package/src/schemas/fontStacks.ts +79 -0
- package/src/schemas/themeCompile.ts +15 -0
- package/src/schemas/themeConstants.ts +2 -0
- package/src/schemas/themeLibrary.ts +25 -19
- package/src/schemas/themeValidator.ts +1 -1
- package/src/spatial/Geohash.ts +0 -3
- package/src/storage/ContentContainer.ts +17 -9
- package/src/storage/ScopedContentContainer.ts +45 -15
- package/src/transform/applyTransform.ts +5 -5
- package/src/transform/index.ts +3 -1
- package/src/transform/registry.ts +169 -49
- package/src/transform/templateSelector.ts +21 -2
- package/src/transform/timingAllocator.ts +152 -21
- package/src/transform/types.ts +14 -1
- package/src/versions/gitignore.ts +34 -0
- package/src/versions/index.ts +2 -0
- package/src/versions/operations.ts +18 -104
- package/src/versions/paths.ts +13 -28
- package/src/versions/snapshotStore.ts +202 -0
- package/src/versions/types.ts +3 -1
- package/dist/chunk-2OIBZYKP.js.map +0 -1
- package/dist/chunk-6ATE2PSM.js.map +0 -1
- package/dist/chunk-A4O7GIWE.js.map +0 -1
- package/dist/chunk-DLXZMS5K.js.map +0 -1
- package/dist/chunk-HWVFJAAH.js.map +0 -1
- package/dist/chunk-IMSCRLLV.js.map +0 -1
- package/dist/chunk-JELIRVDP.js +0 -24
- package/dist/chunk-JELIRVDP.js.map +0 -1
- package/dist/chunk-KKNUBQ6Y.js.map +0 -1
- package/dist/chunk-LDQ2HJIX.js.map +0 -1
- package/dist/chunk-LH7I6SH7.js.map +0 -1
- package/dist/chunk-RUDYOTA6.js.map +0 -1
- package/dist/chunk-T5UK6YOB.js.map +0 -1
- package/dist/chunk-TEEEILMP.js.map +0 -1
- package/dist/chunk-UY7KGQ5R.js +0 -192
- package/dist/chunk-UY7KGQ5R.js.map +0 -1
- package/dist/chunk-VLJJHDAC.js +0 -218
- package/dist/chunk-VLJJHDAC.js.map +0 -1
- package/dist/chunk-VWUFZ6ZG.js.map +0 -1
- package/dist/story/index.d.ts +0 -1777
- package/dist/story/index.js +0 -273
- package/src/doc/getLayers.ts +0 -195
- /package/dist/{story → narration}/index.js.map +0 -0
|
@@ -110,6 +110,19 @@ interface BaseTemplateBlock {
|
|
|
110
110
|
* Used with sourceStartTime to precisely position the block.
|
|
111
111
|
*/
|
|
112
112
|
sourceDuration?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Transform provenance: the id of the source Block this template block
|
|
115
|
+
* was derived from. Lets narration timing (and any per-source styling)
|
|
116
|
+
* be remapped onto transformed/summarized docs.
|
|
117
|
+
*/
|
|
118
|
+
sourceBlockId?: string;
|
|
119
|
+
/** All source block ids when the block summarizes more than one. */
|
|
120
|
+
sourceBlockIds?: string[];
|
|
121
|
+
/**
|
|
122
|
+
* Char offset of the extraction inside the source block's plain text.
|
|
123
|
+
* Provenance only — NOT a time (see sourceStartTime for seconds).
|
|
124
|
+
*/
|
|
125
|
+
sourceCharOffset?: number;
|
|
113
126
|
/**
|
|
114
127
|
* Per-block override for the theme's photographic image grade
|
|
115
128
|
* (`theme.style.imageTreatment`). `'none'` opts this block's imagery out;
|
|
@@ -357,6 +370,92 @@ export interface ListBlockInput extends BaseTemplateBlock {
|
|
|
357
370
|
accentImage?: AccentImage;
|
|
358
371
|
}
|
|
359
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Tree block — renders a hierarchical filesystem-style treeview from an
|
|
375
|
+
* ASCII tree fence (file trees, dependency trees, outlines). The nested
|
|
376
|
+
* `items` arrive via `templateData`, derived from the fence by the pipeline
|
|
377
|
+
* (peer to how `diagram` receives `nodes`/`edges`).
|
|
378
|
+
*/
|
|
379
|
+
export interface TreeBlockInput extends BaseTemplateBlock {
|
|
380
|
+
template: 'tree';
|
|
381
|
+
/** Nested tree items (usually via `templateData.items`). */
|
|
382
|
+
items?: TreeTemplateItem[];
|
|
383
|
+
/** Optional title above the tree. */
|
|
384
|
+
title?: string;
|
|
385
|
+
/** Color scheme for folder rows / icons. */
|
|
386
|
+
colorScheme?: ColorScheme;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** One node supplied via `templateData.items` (mirrors `TreeLayerItem`). */
|
|
390
|
+
export interface TreeTemplateItem {
|
|
391
|
+
id: string;
|
|
392
|
+
label: string;
|
|
393
|
+
isDir?: boolean;
|
|
394
|
+
comment?: string;
|
|
395
|
+
children: TreeTemplateItem[];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* One point on a timeline track. Event positions are normalized across the
|
|
400
|
+
* whole timeline (0 = left edge, 1 = right edge) so events on separate tracks
|
|
401
|
+
* remain horizontally comparable.
|
|
402
|
+
*/
|
|
403
|
+
export interface TimelineTemplateEvent {
|
|
404
|
+
/** Stable id used by cross-track branch links. */
|
|
405
|
+
id: string;
|
|
406
|
+
/** Short label displayed next to the event dot. */
|
|
407
|
+
label: string;
|
|
408
|
+
/** Optional longer callout text. */
|
|
409
|
+
description?: string;
|
|
410
|
+
/** Normalized horizontal position; renderers clamp values to 0..1. */
|
|
411
|
+
position: number;
|
|
412
|
+
/** Preferred callout placement. Defaults to alternating above/below. */
|
|
413
|
+
side?: 'above' | 'below';
|
|
414
|
+
/** Description placement when it should sit opposite the event label. */
|
|
415
|
+
descriptionSide?: 'above' | 'below';
|
|
416
|
+
/** False renders the point only (useful for dense cadence tracks). */
|
|
417
|
+
callout?: boolean;
|
|
418
|
+
/** Dot treatment. Defaults to `filled`. */
|
|
419
|
+
marker?: 'filled' | 'hollow' | 'diamond';
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** A horizontal timeline lane with zero or more positioned events. */
|
|
423
|
+
export interface TimelineTemplateTrack {
|
|
424
|
+
id: string;
|
|
425
|
+
/** Optional label displayed to the left of the track. */
|
|
426
|
+
label?: string;
|
|
427
|
+
/** Optional label displayed after the track's terminal arrow. */
|
|
428
|
+
endLabel?: string;
|
|
429
|
+
events: TimelineTemplateEvent[];
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* A branch or relationship between two events. Source and target resolve
|
|
434
|
+
* against event ids globally, so links may cross tracks.
|
|
435
|
+
*/
|
|
436
|
+
export interface TimelineTemplateLink {
|
|
437
|
+
source: string;
|
|
438
|
+
target: string;
|
|
439
|
+
/** Optional text displayed near the branch path. */
|
|
440
|
+
label?: string;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Timeline block - renders one or more horizontal tracks with event dots,
|
|
445
|
+
* text callouts, and optional branches between events.
|
|
446
|
+
*/
|
|
447
|
+
export interface TimelineBlockInput extends BaseTemplateBlock {
|
|
448
|
+
template: 'timeline';
|
|
449
|
+
/** Tracks and their events (usually supplied through `templateData`). */
|
|
450
|
+
tracks?: TimelineTemplateTrack[];
|
|
451
|
+
/** Optional branch/cross-track links between event ids. */
|
|
452
|
+
links?: TimelineTemplateLink[];
|
|
453
|
+
/** Optional title above the timeline. */
|
|
454
|
+
title?: string;
|
|
455
|
+
/** Color scheme for tracks, markers, and branch links. */
|
|
456
|
+
colorScheme?: ColorScheme;
|
|
457
|
+
}
|
|
458
|
+
|
|
360
459
|
/**
|
|
361
460
|
* Photo grid - 2-4 images in a tiled layout.
|
|
362
461
|
* Used when multiple images are available for visual variety.
|
|
@@ -477,13 +576,57 @@ export interface VideoPullQuoteInput extends BaseTemplateBlock {
|
|
|
477
576
|
}
|
|
478
577
|
|
|
479
578
|
/**
|
|
480
|
-
*
|
|
579
|
+
* One diagram node supplied via `templateData.nodes` (canvas units, the
|
|
580
|
+
* same coordinate space as `Block.x`/`Block.y`). This is the data-driven
|
|
581
|
+
* alternative to child headings — used when a diagram is derived from an
|
|
582
|
+
* ASCII-art fence.
|
|
583
|
+
*/
|
|
584
|
+
export interface DiagramTemplateNode {
|
|
585
|
+
id: string;
|
|
586
|
+
/** Display label; may contain `\n` for multi-line labels. */
|
|
587
|
+
label: string;
|
|
588
|
+
x: number;
|
|
589
|
+
y: number;
|
|
590
|
+
/** Per-node width override in canvas units (defaults to the standard card width). */
|
|
591
|
+
w?: number;
|
|
592
|
+
/** Per-node height override in canvas units. */
|
|
593
|
+
h?: number;
|
|
594
|
+
/** Id of the node visually containing this one; containers draw behind their children. */
|
|
595
|
+
container?: string;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** A position along one side of a diagram node, normalized from 0 to 1. */
|
|
599
|
+
export interface DiagramEdgeAnchor {
|
|
600
|
+
side: 'top' | 'right' | 'bottom' | 'left';
|
|
601
|
+
/** Left→right on horizontal sides; top→bottom on vertical sides. */
|
|
602
|
+
offset: number;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/** An edge for `DiagramTemplateNode` lists. `directed` defaults to true. */
|
|
606
|
+
export interface DiagramTemplateEdge {
|
|
607
|
+
source: string;
|
|
608
|
+
target: string;
|
|
609
|
+
/** Edge label rendered at the midpoint. */
|
|
610
|
+
label?: string;
|
|
611
|
+
/** False suppresses the end arrowhead (a plain connecting line). */
|
|
612
|
+
directed?: boolean;
|
|
613
|
+
/** Optional authored attachment on the source node. */
|
|
614
|
+
sourceAnchor?: DiagramEdgeAnchor;
|
|
615
|
+
/** Optional authored attachment on the target node. */
|
|
616
|
+
targetAnchor?: DiagramEdgeAnchor;
|
|
617
|
+
/** Per-edge path routing; ASCII-derived edges use orthogonal routing. */
|
|
618
|
+
routing?: 'straight' | 'orthogonal' | 'curved';
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Diagram block - renders a node-and-edge diagram.
|
|
481
623
|
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
624
|
+
* Two data sources, in precedence order:
|
|
625
|
+
* 1. Child headings (`context.children`) — each child is a node positioned
|
|
626
|
+
* by its `x`/`y` and connected by its `connectsTo` (legacy authored form).
|
|
627
|
+
* 2. `nodes`/`edges` on this input (usually via `templateData`, derived
|
|
628
|
+
* from an ASCII-art diagram fence in the block body).
|
|
629
|
+
* Per-diagram options on this input control overall appearance.
|
|
487
630
|
*/
|
|
488
631
|
export interface DiagramBlockInput extends BaseTemplateBlock {
|
|
489
632
|
template: 'diagram';
|
|
@@ -501,6 +644,10 @@ export interface DiagramBlockInput extends BaseTemplateBlock {
|
|
|
501
644
|
endStyle?: MarkerStyle;
|
|
502
645
|
/** Edge line style (default: 'solid'). */
|
|
503
646
|
lineStyle?: 'solid' | 'dashed' | 'dotted';
|
|
647
|
+
/** Data-driven node list; used only when the block has no children. */
|
|
648
|
+
nodes?: DiagramTemplateNode[];
|
|
649
|
+
/** Edges for `nodes`. */
|
|
650
|
+
edges?: DiagramTemplateEdge[];
|
|
504
651
|
}
|
|
505
652
|
|
|
506
653
|
/**
|
|
@@ -591,6 +738,8 @@ export type TemplateBlock =
|
|
|
591
738
|
| VideoPullQuoteInput
|
|
592
739
|
| DataTableInput
|
|
593
740
|
| DiagramBlockInput
|
|
741
|
+
| TreeBlockInput
|
|
742
|
+
| TimelineBlockInput
|
|
594
743
|
| DrawingBlockInput
|
|
595
744
|
| RawLayersInput;
|
|
596
745
|
|
|
@@ -630,7 +779,7 @@ export interface TemplateContext {
|
|
|
630
779
|
/** Layout hints for this orientation */
|
|
631
780
|
layout: LayoutHints;
|
|
632
781
|
/**
|
|
633
|
-
* The block's direct children (set by `
|
|
782
|
+
* The block's direct children (set by `materializeBlockLayers` when the block has
|
|
634
783
|
* `children`). Most templates ignore this; aggregate templates like
|
|
635
784
|
* `diagram` consume it to render each child as part of their output.
|
|
636
785
|
*/
|
package/src/schemas/Doc.ts
CHANGED
|
@@ -215,11 +215,23 @@ export interface Block {
|
|
|
215
215
|
/** Which audio segment this block belongs to (0-indexed) */
|
|
216
216
|
audioSegment: number;
|
|
217
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Transform provenance: the source block id this block was derived
|
|
220
|
+
* from (see `BaseTemplateBlock.sourceBlockId`). Present on blocks a
|
|
221
|
+
* transform produced; lets a persisted transformed Doc keep its typed
|
|
222
|
+
* link back to the source content.
|
|
223
|
+
*/
|
|
224
|
+
sourceBlockId?: string;
|
|
225
|
+
/** All source block ids when this block summarizes several. */
|
|
226
|
+
sourceBlockIds?: string[];
|
|
227
|
+
/** Char offset of the extraction inside the source block's plain text. */
|
|
228
|
+
sourceCharOffset?: number;
|
|
229
|
+
|
|
218
230
|
/**
|
|
219
231
|
* Pre-computed visual layers, rendered back-to-front.
|
|
220
232
|
*
|
|
221
233
|
* Optional — template-derived blocks typically omit this and compute
|
|
222
|
-
* layers on demand via `
|
|
234
|
+
* layers on demand via `materializeBlockLayers()` from `@bendyline/squisq/doc`.
|
|
223
235
|
* Raw blocks (e.g., hand-crafted by AI) may provide layers directly.
|
|
224
236
|
*/
|
|
225
237
|
layers?: Layer[];
|
|
@@ -368,7 +380,8 @@ export type Layer =
|
|
|
368
380
|
| PathLayer
|
|
369
381
|
| MapLayer
|
|
370
382
|
| VideoLayer
|
|
371
|
-
| TableLayer
|
|
383
|
+
| TableLayer
|
|
384
|
+
| TreeLayer;
|
|
372
385
|
|
|
373
386
|
interface BaseLayer {
|
|
374
387
|
/** Unique identifier for this layer */
|
|
@@ -573,14 +586,9 @@ export interface PathLayer extends BaseLayer {
|
|
|
573
586
|
borderStyle?: BorderStyle;
|
|
574
587
|
/** Optional stroke dash pattern (SVG `stroke-dasharray` syntax). */
|
|
575
588
|
dasharray?: string;
|
|
576
|
-
/**
|
|
577
|
-
* Legacy arrowhead flag. Prefer `startMarker`/`endMarker`. When those are
|
|
578
|
-
* unset, `'end'`/`'start'`/`'both'` render a filled-triangle arrowhead.
|
|
579
|
-
*/
|
|
580
|
-
arrow?: 'none' | 'end' | 'start' | 'both';
|
|
581
|
-
/** Marker at the path start (overrides `arrow`). Default: derived from `arrow`. */
|
|
589
|
+
/** Marker at the path start. */
|
|
582
590
|
startMarker?: MarkerStyle;
|
|
583
|
-
/** Marker at the path end
|
|
591
|
+
/** Marker at the path end. */
|
|
584
592
|
endMarker?: MarkerStyle;
|
|
585
593
|
};
|
|
586
594
|
}
|
|
@@ -696,6 +704,61 @@ export interface TableLayerStyle {
|
|
|
696
704
|
borderRadius?: number;
|
|
697
705
|
}
|
|
698
706
|
|
|
707
|
+
/**
|
|
708
|
+
* One node in a `TreeLayer` — a JSON-serializable hierarchy item (mirrors
|
|
709
|
+
* the treeview codec's `TreeItem`). Rendered as an indented filesystem-style
|
|
710
|
+
* row with a folder/file icon and connector rails.
|
|
711
|
+
*/
|
|
712
|
+
export interface TreeLayerItem {
|
|
713
|
+
id: string;
|
|
714
|
+
label: string;
|
|
715
|
+
/** True renders a folder (container) icon; else a file (leaf) icon. */
|
|
716
|
+
isDir?: boolean;
|
|
717
|
+
/** Trailing comment shown muted after the label. */
|
|
718
|
+
comment?: string;
|
|
719
|
+
children: TreeLayerItem[];
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* A hierarchical treeview rendered as interactive HTML inside a
|
|
724
|
+
* `<foreignObject>` (like `TableLayer`): folder/file icons, connector
|
|
725
|
+
* rails, and collapse chevrons. Interactive (collapse/expand) in the live
|
|
726
|
+
* React player; captured fully-expanded and static in frame/PDF export.
|
|
727
|
+
*/
|
|
728
|
+
export interface TreeLayer extends BaseLayer {
|
|
729
|
+
type: 'tree';
|
|
730
|
+
content: {
|
|
731
|
+
items: TreeLayerItem[];
|
|
732
|
+
style: TreeLayerStyle;
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/** Styling options for a TreeLayer. */
|
|
737
|
+
export interface TreeLayerStyle {
|
|
738
|
+
/** Leaf (file) row text color. */
|
|
739
|
+
rowColor: string;
|
|
740
|
+
/** Container (folder) row text color. */
|
|
741
|
+
dirColor: string;
|
|
742
|
+
/** Connector rail / branch color. */
|
|
743
|
+
connectorColor: string;
|
|
744
|
+
/** Icon color. */
|
|
745
|
+
iconColor: string;
|
|
746
|
+
/** Muted comment color. */
|
|
747
|
+
commentColor: string;
|
|
748
|
+
/** Font size in pixels. */
|
|
749
|
+
fontSize: number;
|
|
750
|
+
/** Row label font family. */
|
|
751
|
+
fontFamily?: string;
|
|
752
|
+
/** Monospace font for the connector rails. */
|
|
753
|
+
monoFontFamily?: string;
|
|
754
|
+
/** Indent step per depth level, in pixels. */
|
|
755
|
+
indentPx: number;
|
|
756
|
+
/** FontAwesome icon token for containers (default `folder`). */
|
|
757
|
+
folderIcon?: string;
|
|
758
|
+
/** FontAwesome icon token for leaves (default `file`). */
|
|
759
|
+
fileIcon?: string;
|
|
760
|
+
}
|
|
761
|
+
|
|
699
762
|
/**
|
|
700
763
|
* Available map tile styles from free/open-source providers.
|
|
701
764
|
*/
|
package/src/schemas/Media.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Media-clip timing model.
|
|
3
3
|
*
|
|
4
|
-
* An additive layer on top of the
|
|
5
|
-
* narration track. A {@link MediaClip} is a piece
|
|
4
|
+
* An additive layer on top of the simple sequential `Doc.audio.segments[]`
|
|
5
|
+
* narration track, which remains first-class. A {@link MediaClip} is a piece
|
|
6
|
+
* of audio or video whose
|
|
6
7
|
* timing is expressed *relative to its parent block* (or the whole document),
|
|
7
8
|
* with an optional `startAt` offset and an optional `spillover` past the
|
|
8
9
|
* block's end. {@link resolveMediaSchedule} flattens these into absolute,
|
|
@@ -51,6 +52,15 @@ export interface MediaClip {
|
|
|
51
52
|
* `startAt`) back to the exact line. Absent for programmatically built clips.
|
|
52
53
|
*/
|
|
53
54
|
sourceLine?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Round-trip home of the authoring annotation: the block whose contents
|
|
57
|
+
* held the paragraph, its position in that block's ORIGINAL contents
|
|
58
|
+
* array (before extraction), and the paragraph's exact source text.
|
|
59
|
+
* `docToMarkdown` re-inserts the annotation from this — `raw` verbatim
|
|
60
|
+
* when present, a re-serialized annotation otherwise. Absent for
|
|
61
|
+
* programmatically built clips (those emit at the document top).
|
|
62
|
+
*/
|
|
63
|
+
origin?: { blockId: string; index: number; raw?: string };
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
/**
|
package/src/schemas/Theme.ts
CHANGED
|
@@ -23,13 +23,15 @@
|
|
|
23
23
|
import type { LayoutHints } from './LayoutStrategy.js';
|
|
24
24
|
import type { AnimationType, ImageTreatment, TransitionType } from './Doc.js';
|
|
25
25
|
import type { PersistentLayerConfig } from './BlockTemplates.js';
|
|
26
|
+
import { THEME_SCHEMA_VERSION } from './themeConstants.js';
|
|
27
|
+
import { validateTheme } from './themeValidator.js';
|
|
28
|
+
import { cloneAndFreezeData } from '../internal/immutable.js';
|
|
26
29
|
|
|
27
30
|
// ============================================
|
|
28
31
|
// Schema version
|
|
29
32
|
// ============================================
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
export const THEME_SCHEMA_VERSION = '1' as const;
|
|
34
|
+
export { THEME_SCHEMA_VERSION } from './themeConstants.js';
|
|
33
35
|
export type ThemeSchemaVersion = typeof THEME_SCHEMA_VERSION;
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -354,33 +356,51 @@ export function applySurface(theme: Theme, surface: SurfaceScheme): Theme {
|
|
|
354
356
|
}
|
|
355
357
|
|
|
356
358
|
// ============================================
|
|
357
|
-
//
|
|
359
|
+
// Caller-owned registry — for custom themes
|
|
358
360
|
// ============================================
|
|
359
361
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
* Registered themes take precedence over built-ins with the same id.
|
|
367
|
-
*/
|
|
368
|
-
export function registerTheme(theme: Theme): void {
|
|
369
|
-
CUSTOM_THEME_REGISTRY.set(theme.id, theme);
|
|
362
|
+
/** A caller-owned custom-theme registry for SSR tenants, tests, and embedders. */
|
|
363
|
+
export interface ThemeRegistry {
|
|
364
|
+
register(theme: Theme): void;
|
|
365
|
+
unregister(id: string): boolean;
|
|
366
|
+
get(id: string): Theme | undefined;
|
|
367
|
+
list(): Theme[];
|
|
370
368
|
}
|
|
371
369
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
370
|
+
function validatedThemeSnapshot(theme: Theme): Theme {
|
|
371
|
+
const result = validateTheme(theme);
|
|
372
|
+
if (!result.valid || !result.theme) {
|
|
373
|
+
const details = result.errors
|
|
374
|
+
.slice(0, 5)
|
|
375
|
+
.map((error) => `${error.path || '<root>'}: ${error.message}`)
|
|
376
|
+
.join('; ');
|
|
377
|
+
throw new TypeError(`Cannot register invalid theme: ${details}`);
|
|
378
|
+
}
|
|
379
|
+
return cloneAndFreezeData(result.theme);
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
/**
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
382
|
+
/**
|
|
383
|
+
* Create a registry whose state is owned by the caller rather than the
|
|
384
|
+
* process. Registered values are validated and stored as deeply frozen
|
|
385
|
+
* snapshots, so later caller mutation cannot alter resolution behavior.
|
|
386
|
+
*/
|
|
387
|
+
export function createThemeRegistry(initialThemes: readonly Theme[] = []): ThemeRegistry {
|
|
388
|
+
const themes = new Map<string, Theme>();
|
|
389
|
+
const registry: ThemeRegistry = {
|
|
390
|
+
register(theme): void {
|
|
391
|
+
const snapshot = validatedThemeSnapshot(theme);
|
|
392
|
+
themes.set(snapshot.id, snapshot);
|
|
393
|
+
},
|
|
394
|
+
unregister(id): boolean {
|
|
395
|
+
return themes.delete(id);
|
|
396
|
+
},
|
|
397
|
+
get(id): Theme | undefined {
|
|
398
|
+
return themes.get(id);
|
|
399
|
+
},
|
|
400
|
+
list(): Theme[] {
|
|
401
|
+
return Array.from(themes.values());
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
for (const theme of initialThemes) registry.register(theme);
|
|
405
|
+
return Object.freeze(registry);
|
|
386
406
|
}
|
package/src/schemas/Viewport.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - landscape (16:9) - Default, standard video/presentation format
|
|
9
9
|
* - portrait (9:16) - Vertical video, mobile stories
|
|
10
10
|
* - square (1:1) - Social media posts
|
|
11
|
-
* - standard (4:3) -
|
|
11
|
+
* - standard (4:3) - Classic presentation format
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -33,7 +33,7 @@ export const VIEWPORT_PRESETS = {
|
|
|
33
33
|
portrait: { width: 1080, height: 1920, name: '9:16 Portrait' },
|
|
34
34
|
/** 1:1 square (social media) */
|
|
35
35
|
square: { width: 1080, height: 1080, name: '1:1 Square' },
|
|
36
|
-
/** 4:3 standard
|
|
36
|
+
/** 4:3 standard */
|
|
37
37
|
standard: { width: 1440, height: 1080, name: '4:3 Standard' },
|
|
38
38
|
} as const;
|
|
39
39
|
|
|
@@ -258,3 +258,82 @@ export function buildGoogleFontsUrl(families: Array<FontFamily | undefined>): st
|
|
|
258
258
|
|
|
259
259
|
/** Default fallback families exposed for tools that need them. */
|
|
260
260
|
export const FONT_FALLBACKS = FALLBACK_BY_KIND;
|
|
261
|
+
|
|
262
|
+
// ── Arbitrary font-name matching ─────────────────────────────────────
|
|
263
|
+
//
|
|
264
|
+
// Used by file-import theme inference (OOXML fontScheme → FontFamily):
|
|
265
|
+
// a typeface name from an office document either matches a curated stack
|
|
266
|
+
// or becomes a `{ custom }` reference that preserves the original face.
|
|
267
|
+
|
|
268
|
+
/** Normalize a raw typeface name for lookup: trim, unquote, lowercase, collapse whitespace. */
|
|
269
|
+
function normalizeFontName(name: string): string {
|
|
270
|
+
return name
|
|
271
|
+
.trim()
|
|
272
|
+
.replace(/^["']+|["']+$/g, '')
|
|
273
|
+
.replace(/\s+/g, ' ')
|
|
274
|
+
.toLowerCase();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Normalized name → stackId. Seeded from every stack's label and Google
|
|
279
|
+
* Fonts family name, plus explicit aliases for common variants and the
|
|
280
|
+
* web-safe faces that already anchor the system stacks' CSS families.
|
|
281
|
+
*/
|
|
282
|
+
const STACK_NAME_ALIASES: Record<string, string> = (() => {
|
|
283
|
+
const aliases: Record<string, string> = {};
|
|
284
|
+
for (const stack of AVAILABLE_FONT_STACKS) {
|
|
285
|
+
aliases[normalizeFontName(stack.label)] = stack.id;
|
|
286
|
+
if (stack.googleFontFamily) aliases[normalizeFontName(stack.googleFontFamily)] = stack.id;
|
|
287
|
+
}
|
|
288
|
+
Object.assign(aliases, {
|
|
289
|
+
playfair: 'playfair',
|
|
290
|
+
'source serif': 'source-serif',
|
|
291
|
+
'source serif pro': 'source-serif',
|
|
292
|
+
'crimson pro': 'crimson',
|
|
293
|
+
cormorant: 'cormorant',
|
|
294
|
+
georgia: 'system-serif',
|
|
295
|
+
'times new roman': 'system-serif',
|
|
296
|
+
times: 'system-serif',
|
|
297
|
+
consolas: 'system-mono',
|
|
298
|
+
'courier new': 'system-mono',
|
|
299
|
+
courier: 'system-mono',
|
|
300
|
+
'segoe ui': 'system-sans',
|
|
301
|
+
'system-ui': 'system-sans',
|
|
302
|
+
});
|
|
303
|
+
return aliases;
|
|
304
|
+
})();
|
|
305
|
+
|
|
306
|
+
const MONO_NAME_RE =
|
|
307
|
+
/\b(mono|monospace|consolas|courier|menlo|inconsolata|cascadia|fira code|source code|code)\b/;
|
|
308
|
+
const SERIF_NAME_RE =
|
|
309
|
+
/\b(georgia|times|garamond|cambria|caslon|baskerville|bodoni|didot|palatino|book antiqua|goudy|minion|charter|constantia|century schoolbook|antiqua|roman)\b/;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Guess the structured fallback bucket for an arbitrary typeface name.
|
|
313
|
+
* Deliberately never guesses `system-ui` — a wrong serif/sans guess is
|
|
314
|
+
* recoverable in the customizer; `system-ui` erases the signal entirely.
|
|
315
|
+
*/
|
|
316
|
+
export function guessFontFallback(
|
|
317
|
+
name: string,
|
|
318
|
+
): 'serif' | 'sans-serif' | 'monospace' | 'system-ui' {
|
|
319
|
+
const n = normalizeFontName(name);
|
|
320
|
+
if (MONO_NAME_RE.test(n)) return 'monospace';
|
|
321
|
+
if ((n.includes('serif') && !n.includes('sans')) || SERIF_NAME_RE.test(n)) return 'serif';
|
|
322
|
+
return 'sans-serif';
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Map an arbitrary typeface name (e.g. from an imported office document's
|
|
327
|
+
* fontScheme) to a `FontFamily`: a curated `{ stackId }` when the name
|
|
328
|
+
* matches a known stack, else `{ custom }` preserving the original name
|
|
329
|
+
* (original casing, quotes stripped) with a heuristic fallback bucket.
|
|
330
|
+
* Empty/blank names resolve to the system sans stack.
|
|
331
|
+
*/
|
|
332
|
+
export function matchFontFamily(name: string): FontFamily {
|
|
333
|
+
const normalized = normalizeFontName(name);
|
|
334
|
+
if (!normalized) return { stackId: 'system-sans' };
|
|
335
|
+
const stackId = STACK_NAME_ALIASES[normalized];
|
|
336
|
+
if (stackId) return { stackId };
|
|
337
|
+
const displayName = name.trim().replace(/^["']+|["']+$/g, '');
|
|
338
|
+
return { custom: { name: displayName, fallback: guessFontFallback(name) } };
|
|
339
|
+
}
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
oklchSetChroma,
|
|
29
29
|
pickContrastingText,
|
|
30
30
|
relativeLuminance,
|
|
31
|
+
deriveScale,
|
|
32
|
+
isHex,
|
|
31
33
|
} from './colorUtils.js';
|
|
32
34
|
|
|
33
35
|
/** Internal default theme used to fill in fields the customizer doesn't expose. */
|
|
@@ -134,6 +136,19 @@ export function deriveColorPalette(
|
|
|
134
136
|
};
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Expand one accent color into a full `{bg, text, accent}` color scheme via
|
|
141
|
+
* the OKLCh scale — dark saturated bg, light readable text, the picked accent.
|
|
142
|
+
* Falls back to a neutral scheme when the input isn't a valid hex. Shared by
|
|
143
|
+
* the editor's accent list and file-import theme inference so both derive
|
|
144
|
+
* identical schemes from the same accent.
|
|
145
|
+
*/
|
|
146
|
+
export function accentToColorScheme(accent: string): ThemeColorScheme {
|
|
147
|
+
if (!isHex(accent)) return { bg: '#1a202c', text: '#e2e8f0', accent: '#63b3ed' };
|
|
148
|
+
const scale = deriveScale(accent, 0.3);
|
|
149
|
+
return { bg: scale.darker2, text: scale.lighter2, accent: scale.base };
|
|
150
|
+
}
|
|
151
|
+
|
|
137
152
|
/** Map a contrast preset to numeric spread used by `deriveColorPalette`. */
|
|
138
153
|
export type ContrastPreset = 'subtle' | 'balanced' | 'high';
|
|
139
154
|
|
|
@@ -9,17 +9,21 @@
|
|
|
9
9
|
* ```ts
|
|
10
10
|
* import { THEMES, resolveTheme } from '@bendyline/squisq/schemas';
|
|
11
11
|
*
|
|
12
|
-
* const theme = resolveTheme('minimalist'); // by id
|
|
12
|
+
* const theme = resolveTheme('minimalist'); // built-in lookup by id
|
|
13
13
|
* const theme = THEMES.documentary; // direct access to a built-in
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { Theme } from './Theme.js';
|
|
18
|
-
import { lookupRegisteredTheme } from './Theme.js';
|
|
17
|
+
import type { Theme, ThemeRegistry } from './Theme.js';
|
|
19
18
|
import { BUILTIN_THEMES } from './themes/index.js';
|
|
19
|
+
import { cloneAndFreezeData } from '../internal/immutable.js';
|
|
20
20
|
|
|
21
21
|
/** All built-in themes, keyed by id. */
|
|
22
|
-
export const THEMES: Record<string, Theme
|
|
22
|
+
export const THEMES: Readonly<Record<string, Theme>> = Object.freeze(
|
|
23
|
+
Object.fromEntries(
|
|
24
|
+
Object.entries(BUILTIN_THEMES).map(([id, theme]) => [id, cloneAndFreezeData(theme)]),
|
|
25
|
+
),
|
|
26
|
+
);
|
|
23
27
|
|
|
24
28
|
/** The default theme id. */
|
|
25
29
|
export const DEFAULT_THEME_ID = 'standard';
|
|
@@ -28,27 +32,29 @@ export const DEFAULT_THEME_ID = 'standard';
|
|
|
28
32
|
export const DEFAULT_THEME: Theme = THEMES[DEFAULT_THEME_ID];
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
|
-
* Resolve a theme by id.
|
|
32
|
-
* take precedence over built-ins;
|
|
33
|
-
* the default theme is returned for unknown ids.
|
|
35
|
+
* Resolve a theme by id. When a caller-owned registry is supplied its themes
|
|
36
|
+
* take precedence over built-ins; unknown ids fall back to the default.
|
|
34
37
|
*/
|
|
35
|
-
export function resolveTheme(id: string | undefined): Theme {
|
|
36
|
-
const registered =
|
|
38
|
+
export function resolveTheme(id: string | undefined, registry?: ThemeRegistry): Theme {
|
|
39
|
+
const registered = id ? registry?.get(id) : undefined;
|
|
37
40
|
if (registered) return registered;
|
|
38
41
|
if (id && id in THEMES) return THEMES[id];
|
|
39
42
|
return DEFAULT_THEME;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
/** Get
|
|
43
|
-
export function getAvailableThemes(): string[] {
|
|
44
|
-
return
|
|
45
|
+
/** Get built-in ids plus ids from an optional caller-owned registry. */
|
|
46
|
+
export function getAvailableThemes(registry?: ThemeRegistry): string[] {
|
|
47
|
+
return Array.from(
|
|
48
|
+
new Set([...Object.keys(THEMES), ...(registry?.list().map((theme) => theme.id) ?? [])]),
|
|
49
|
+
);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
/** Get
|
|
48
|
-
export function getThemeSummaries(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
/** Get summaries for built-ins plus an optional caller-owned registry. */
|
|
53
|
+
export function getThemeSummaries(
|
|
54
|
+
registry?: ThemeRegistry,
|
|
55
|
+
): Array<{ id: string; name: string; description?: string }> {
|
|
56
|
+
return getAvailableThemes(registry).map((id) => {
|
|
57
|
+
const theme = resolveTheme(id, registry);
|
|
58
|
+
return { id, name: theme.name, description: theme.description };
|
|
59
|
+
});
|
|
54
60
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { Theme, ThemeColorPalette } from './Theme.js';
|
|
14
|
-
import { THEME_SCHEMA_VERSION } from './
|
|
14
|
+
import { THEME_SCHEMA_VERSION } from './themeConstants.js';
|
|
15
15
|
import { isHex } from './colorUtils.js';
|
|
16
16
|
import { isTransitionType } from './Transitions.js';
|
|
17
17
|
|