@bendyline/squisq 2.4.0 → 2.4.2

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 (35) hide show
  1. package/dist/{Doc-DLpyOAXJ.d.ts → Doc-BKKcPjfe.d.ts} +137 -9
  2. package/dist/{ImageEditDoc-Cu30xb9b.d.ts → ImageEditDoc-CU1cXxRd.d.ts} +1 -1
  3. package/dist/{annotationCoercion-PtRQhk5V.d.ts → annotationCoercion-CPHEggo3.d.ts} +1 -1
  4. package/dist/{chunk-F2IEPSMA.js → chunk-2HY2ZA7U.js} +161 -80
  5. package/dist/{chunk-D4LPP3P5.js → chunk-7TJJA2RI.js} +3 -1
  6. package/dist/{chunk-KPBZZVGY.js → chunk-AQF5ZYDI.js} +50 -14
  7. package/dist/{chunk-2VCNTDNZ.js → chunk-D6YTLQCL.js} +71 -0
  8. package/dist/{chunk-32R2RZAO.js → chunk-DAMIRKTO.js} +1 -1
  9. package/dist/{chunk-ZHLNKB2I.js → chunk-EMXYZLRH.js} +1 -1
  10. package/dist/{chunk-2S74DPJH.js → chunk-GAZKTT4R.js} +24 -4
  11. package/dist/{chunk-REDUXXDJ.js → chunk-GODLNXO4.js} +45 -3
  12. package/dist/{chunk-ZYO3DBTA.js → chunk-JUAC2QWP.js} +1 -1
  13. package/dist/{chunk-C33GTPUZ.js → chunk-SBAX4ZPO.js} +438 -0
  14. package/dist/doc/index.d.ts +17 -7
  15. package/dist/doc/index.js +11 -10
  16. package/dist/generate/index.d.ts +2 -2
  17. package/dist/imageEdit/index.d.ts +4 -4
  18. package/dist/index.d.ts +7 -7
  19. package/dist/index.js +20 -14
  20. package/dist/jsonForm/index.d.ts +2 -2
  21. package/dist/jsonForm/index.js +4 -4
  22. package/dist/markdown/index.d.ts +3 -3
  23. package/dist/markdown/index.js +3 -3
  24. package/dist/{materializePageSection-CgNs5Qmw.d.ts → materializePageSection-WDJCTJEm.d.ts} +2 -2
  25. package/dist/narration/index.d.ts +2 -2
  26. package/dist/narration/index.js +4 -4
  27. package/dist/recommend/index.d.ts +1 -1
  28. package/dist/schemas/index.d.ts +33 -6
  29. package/dist/schemas/index.js +9 -3
  30. package/dist/storage/index.d.ts +2 -3
  31. package/dist/{themeLibrary-RWsNtlOu.d.ts → themeLibrary-BMXXLZBU.d.ts} +1 -1
  32. package/dist/timing/index.d.ts +1 -2
  33. package/dist/transform/index.d.ts +3 -3
  34. package/dist/{types-CUNc9biN.d.ts → types-CcrDFdWH.d.ts} +1 -1
  35. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { a0 as Transition, a2 as TransitionType, M as MarkdownBlockNode, r as MarkdownHeading } from './types-CUNc9biN.js';
1
+ import { a1 as Transition, a3 as TransitionType, M as MarkdownBlockNode, r as MarkdownHeading } from './types-CcrDFdWH.js';
2
2
 
3
3
  /**
4
4
  * Media-clip timing model.
@@ -25,6 +25,14 @@ import { a0 as Transition, a2 as TransitionType, M as MarkdownBlockNode, r as Ma
25
25
  * above the composed slide.
26
26
  */
27
27
  type VideoPlacement = 'content' | 'picture-in-picture' | 'overlay';
28
+ /** Player-level placement of scheduled video relative to slide content. */
29
+ type VideoPresentation = 'background' | 'full-frame' | 'picture-in-picture';
30
+ /** Optional per-video override for picture-in-picture size. */
31
+ type VideoPipSize = 'small' | 'large';
32
+ /** Optional per-video override for the picture-in-picture frame shape. */
33
+ type VideoPipShape = 'square' | 'wide';
34
+ /** Optional per-video override for the picture-in-picture corner. */
35
+ type VideoPipPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
28
36
  /**
29
37
  * A timed piece of media attached to a block (or the document).
30
38
  */
@@ -36,6 +44,12 @@ interface MediaClip {
36
44
  kind: 'audio' | 'video';
37
45
  /** Per-video placement. Omitted audio and legacy video use player defaults. */
38
46
  placement?: Exclude<VideoPlacement, 'content'>;
47
+ /** Per-video PIP size. Omitted clips use the document/player setting. */
48
+ pipSize?: VideoPipSize;
49
+ /** Per-video PIP shape. Omitted clips use the document/player setting. */
50
+ pipShape?: VideoPipShape;
51
+ /** Per-video PIP corner. Omitted clips use the document/player setting. */
52
+ pipPosition?: VideoPipPosition;
39
53
  /**
40
54
  * Whether a placed video is locked to its owning block's timeline span.
41
55
  * `true` clips start with and are capped by the block. `false` clips are
@@ -95,6 +109,12 @@ interface ScheduledClip {
95
109
  kind: 'audio' | 'video';
96
110
  /** Per-video placement carried through to the player-level compositor. */
97
111
  placement?: Exclude<VideoPlacement, 'content'>;
112
+ /** Per-video PIP size carried through to the player-level compositor. */
113
+ pipSize?: VideoPipSize;
114
+ /** Per-video PIP shape carried through to the player-level compositor. */
115
+ pipShape?: VideoPipShape;
116
+ /** Per-video PIP corner carried through to the player-level compositor. */
117
+ pipPosition?: VideoPipPosition;
98
118
  /** Authored placed-video lock state, when applicable. */
99
119
  lockToBlock?: boolean;
100
120
  /** Absolute doc-timeline second the clip starts. */
@@ -109,17 +129,36 @@ interface ScheduledClip {
109
129
  /** 1-based source line of the authoring annotation, when known. */
110
130
  sourceLine?: number;
111
131
  }
132
+ /** Options for {@link resolveMediaSchedule} / {@link getDocPlaybackDuration}. */
133
+ interface MediaScheduleOptions {
134
+ /**
135
+ * Optional lookup of a media file's intrinsic duration in seconds (e.g.
136
+ * probed from the decoded file). When a clip has no authored out-point
137
+ * (`clipEnd`) and is not locked to its block, its scheduled end is capped at
138
+ * this natural length instead of filling to the block/document end — so an
139
+ * unlocked video plays for its own length and then goes inactive rather than
140
+ * holding its last frame until the timeline ends.
141
+ *
142
+ * Applied only as an upper bound: it can pull a clip's end earlier but never
143
+ * extends it, so the overall timeline length is unchanged. Return undefined
144
+ * (the default when no probe is wired) to preserve the historical
145
+ * fill-to-end behavior. Locked clips ignore it — they fill their owning
146
+ * block by design.
147
+ */
148
+ intrinsicDuration?: (clip: MediaClip) => number | undefined;
149
+ }
112
150
  /**
113
151
  * Flatten every block clip and document clip into absolute-timed
114
- * `ScheduledClip`s. Pure — depends only on `doc`.
152
+ * `ScheduledClip`s. Pure — depends only on `doc` (plus the optional intrinsic
153
+ * media durations in {@link MediaScheduleOptions}).
115
154
  */
116
- declare function resolveMediaSchedule(doc: Doc): ScheduledClip[];
155
+ declare function resolveMediaSchedule(doc: Doc, opts?: MediaScheduleOptions): ScheduledClip[];
117
156
  /**
118
157
  * Total playback duration including any media that spills past the last
119
158
  * block (or audio segment). Export uses this for the frame count and the
120
159
  * player for its effective timeline length.
121
160
  */
122
- declare function getDocPlaybackDuration(doc: Doc): number;
161
+ declare function getDocPlaybackDuration(doc: Doc, opts?: MediaScheduleOptions): number;
123
162
 
124
163
  /**
125
164
  * Viewport Configuration
@@ -282,13 +321,13 @@ declare function getSafeTextBounds(orientation: ViewportOrientation): {
282
321
  /**
283
322
  * Block Templates Schema
284
323
  *
285
- * Defines a template system for AI-generated doc blocks. Instead of
286
- * specifying low-level layers, positions, and animations, AI can use
324
+ * Defines a template system for generated or programmatic doc blocks. Instead
325
+ * of specifying low-level layers, positions, and animations, callers can use
287
326
  * high-level templates like "title" or "statHighlight" with simple
288
327
  * content parameters.
289
328
  *
290
329
  * Templates are expanded into full Block structures at render time,
291
- * ensuring consistent styling and reducing AI generation errors.
330
+ * ensuring consistent styling and reducing generation errors.
292
331
  *
293
332
  * Template Types:
294
333
  * - title: Doc intro with title + subtitle
@@ -1510,6 +1549,41 @@ interface ThemeStyle {
1510
1549
  * template via `imageTreatment: 'none'`.
1511
1550
  */
1512
1551
  imageTreatment?: ImageTreatment;
1552
+ /**
1553
+ * Framing for scheduled picture-in-picture presenter video, so a theme can
1554
+ * style the PiP (border, shadow, corner radius) to match. All fields are
1555
+ * optional — anything omitted is derived from the rest of the theme by
1556
+ * `pipStyleVars()`. See {@link PipStyle}.
1557
+ */
1558
+ pip?: PipStyle;
1559
+ }
1560
+ /**
1561
+ * Theme-driven framing for scheduled picture-in-picture presenter video. Every
1562
+ * field is optional; `pipStyleVars()` fills any gaps by deriving a fitting
1563
+ * default from the palette and {@link ThemeStyle.borderRadius}, so a theme that
1564
+ * declares no `pip` block still gets a PiP consistent with its look.
1565
+ */
1566
+ interface PipStyle {
1567
+ /**
1568
+ * Corner radius of the PiP frame — a number (px), a CSS length/percentage
1569
+ * string (e.g. `'18%'`, `'50%'`), or `0` for square corners. Omitted →
1570
+ * derived from {@link ThemeStyle.borderRadius} (0 stays square).
1571
+ */
1572
+ cornerRadius?: number | string;
1573
+ /**
1574
+ * Frame border. `'none'` removes it; an explicit `{ width, color }` sets it.
1575
+ * Omitted → a subtle rim in the theme's text color that reads on both light
1576
+ * and dark slides.
1577
+ */
1578
+ border?: 'none' | {
1579
+ width?: number | string;
1580
+ color?: string;
1581
+ };
1582
+ /**
1583
+ * Drop shadow. `false` / `'none'` → no shadow; `true` (or omitted) → a soft
1584
+ * themed shadow; a string → an explicit CSS `box-shadow` value.
1585
+ */
1586
+ shadow?: boolean | string;
1513
1587
  }
1514
1588
  /**
1515
1589
  * Render-style algorithm preset. Controls layout tweaks, default animations,
@@ -1744,6 +1818,29 @@ interface CustomTemplateDefinition {
1744
1818
  */
1745
1819
  layers: CustomTemplateLayer[];
1746
1820
  }
1821
+ /** A structural problem found while decoding a custom template. */
1822
+ interface CustomTemplateValidationError {
1823
+ /** JSON-style path to the invalid value. */
1824
+ path: string;
1825
+ /** Human-readable description of the required shape. */
1826
+ message: string;
1827
+ }
1828
+ /** Result returned by {@link validateCustomTemplateDefinition}. */
1829
+ interface CustomTemplateValidationResult {
1830
+ valid: boolean;
1831
+ errors: CustomTemplateValidationError[];
1832
+ /** Present only when the complete input is structurally valid. */
1833
+ template?: CustomTemplateDefinition;
1834
+ }
1835
+ /**
1836
+ * Validate an untrusted custom-template definition before it reaches template
1837
+ * expansion or rendering. Unknown object keys are ignored for forward
1838
+ * compatibility, but every currently supported layer's required shape is
1839
+ * checked recursively.
1840
+ */
1841
+ declare function validateCustomTemplateDefinition(input: unknown): CustomTemplateValidationResult;
1842
+ /** Type guard form of {@link validateCustomTemplateDefinition}. */
1843
+ declare function isCustomTemplateDefinition(input: unknown): input is CustomTemplateDefinition;
1747
1844
  /**
1748
1845
  * Tag value for the YAML frontmatter key that carries inlined custom
1749
1846
  * template definitions. Exported so the markdown bridge stays in sync.
@@ -1819,7 +1916,7 @@ interface Doc {
1819
1916
  blocks: Block[];
1820
1917
  /** Audio track configuration */
1821
1918
  audio: AudioTrack;
1822
- /** Caption track for closed captions (generated by postprocess-doc) */
1919
+ /** Optional caption track for closed captions. */
1823
1920
  captions?: CaptionTrack;
1824
1921
  /**
1825
1922
  * Start/resting block shown before playback begins.
@@ -1910,6 +2007,30 @@ interface Doc {
1910
2007
  * Merge order at render time: template defaults → `templateData` →
1911
2008
  * `templateOverrides`.
1912
2009
  */
2010
+ /**
2011
+ * Provenance for a template tag that an author (usually an LLM) placed in a
2012
+ * block's BODY instead of on its heading, and which `markdownToDoc` promoted to
2013
+ * the block's template. Ephemeral — like `autoTemplate` — but round-tripped
2014
+ * lazily: `docToMarkdown` re-emits the tag in the body verbatim while the block
2015
+ * is unedited, and relocates it onto the heading (`# Heading {[…]}`) once the
2016
+ * block's `template`/`templateOverrides` change. See `promoteBodyAnnotation.ts`.
2017
+ */
2018
+ interface PromotedBodyAnnotation {
2019
+ /** Authored template name (pre-alias), e.g. `title` or `titleBlock`. */
2020
+ template: string;
2021
+ /** Authored params, unquoted/unescaped. */
2022
+ params: Record<string, string>;
2023
+ /** Where the tag lived in the body, for byte-faithful re-emission. */
2024
+ origin: {
2025
+ kind: 'paragraph';
2026
+ index: number;
2027
+ raw: string;
2028
+ } | {
2029
+ kind: 'trailing';
2030
+ index: number;
2031
+ suffix: string;
2032
+ };
2033
+ }
1913
2034
  interface Block {
1914
2035
  /** Unique identifier for this block.
1915
2036
  * Defaults to a slug derived from the heading text. May be overridden by
@@ -1976,6 +2097,13 @@ interface Block {
1976
2097
  template?: string;
1977
2098
  params?: Record<string, string>;
1978
2099
  };
2100
+ /**
2101
+ * Set when this block's `template` was PROMOTED from a `{[…]}` tag that
2102
+ * appeared in the block's body (rather than on the heading). Ephemeral and
2103
+ * round-tripped lazily by `docToMarkdown`: the tag stays in the body until the
2104
+ * block is edited, then moves onto the heading. See `promoteBodyAnnotation.ts`.
2105
+ */
2106
+ promotedBodyAnnotation?: PromotedBodyAnnotation;
1979
2107
  /**
1980
2108
  * Display title for template rendering.
1981
2109
  * Extracted from the sourceHeading when the block is created by markdownToDoc().
@@ -2642,4 +2770,4 @@ declare function getBlockAtTime(blocks: Block[], time: number): Block | null;
2642
2770
  */
2643
2771
  declare function getCaptionAtTime(captions: CaptionTrack | undefined, time: number): CaptionPhrase | null;
2644
2772
 
2645
- export { LIGHT_SURFACE as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, DARK_SURFACE as D, type DateEventInput as E, type DeepPartial as F, type DefinitionCardInput as G, type DiagramBlockInput as H, type DiagramEdgeAnchor as I, type DiagramTemplateEdge as J, type DiagramTemplateNode as K, type Doc as L, type DocBlock as M, type DocDiagnostic as N, type DonutChartInput as O, type DrawingBlockInput as P, FRONTMATTER_CUSTOM_TEMPLATES_KEY as Q, FRONTMATTER_CUSTOM_THEMES_KEY as R, type FactCardInput as S, type FontFamily as T, type FontFamilyKind as U, type FullBleedQuoteInput as V, type GradientBackgroundConfig as W, type ImageBackgroundConfig as X, type ImageLayer as Y, type ImageTreatment as Z, type ImageWithCaptionInput as _, type AccentPosition as a, type StartBlockConfig as a$, type Layer as a0, type LayerRepeat as a1, type LayoutHints as a2, type LeftFeatureInput as a3, type LineChartInput as a4, type LinearGradient as a5, type ListBlockInput as a6, type MapBlockInput as a7, type MapLayer as a8, type MapMarker as a9, type PageHeadingTreatment as aA, type PageSectionKind as aB, type PageSectionOverride as aC, type PageTokens as aD, type PathLayer as aE, type PatternBackgroundConfig as aF, type PersistentLayer as aG, type PersistentLayerConfig as aH, type PersistentLayerTemplate as aI, type PersistentLayerTemplateConfig as aJ, type PersistentLayerTemplateType as aK, type PhotoGridInput as aL, type PieChartInput as aM, type Position as aN, type ProgressIndicatorConfig as aO, type PullQuoteInput as aP, type QuoteBlockInput as aQ, type RawLayersInput as aR, type RenderStyle as aS, type RightFeatureInput as aT, type ScatterChartInput as aU, type ScheduledClip as aV, type SectionHeaderInput as aW, type ShapeFilter as aX, type ShapeLayer as aY, type ShapePattern as aZ, type SolidBackgroundConfig as a_, type MapTileStyle as aa, type MarkerStyle as ab, type MediaClip as ac, type MermaidLayer as ad, PAGE_ACCENT_STRATEGIES as ae, PAGE_BACKGROUNDS as af, PAGE_BACKGROUND_RHYTHMS as ag, PAGE_DESIGN_FAMILIES as ah, PAGE_DIVIDERS as ai, PAGE_EMPHASES as aj, PAGE_EYEBROWS as ak, PAGE_HEADING_CASES as al, PAGE_HEADING_SCALES as am, PAGE_HEADING_UNDERLINES as an, PAGE_HERO_STYLES as ao, PAGE_IMAGE_FRAMINGS as ap, PAGE_NUMERAL_STYLES as aq, PAGE_PATTERNS as ar, PAGE_QUOTE_MARKS as as, PAGE_SECTION_KINDS as at, PAGE_SECTION_SPACINGS as au, PAGE_SHADOWS as av, type PageAccentRotation as aw, type PageBackground as ax, type PageDesignFamily as ay, type PageEmphasis as az, type AmbientGradientConfig as b, type StatHighlightInput as b0, type SurfaceScheme as b1, THEME_SCHEMA_VERSION as b2, type TableLayer as b3, type TableLayerStyle as b4, type TemplateBlock as b5, type TemplateContext as b6, type TemplateFunction as b7, type TemplateRegistry as b8, type TextLayer as b9, type VideoWithCaptionInput as bA, type ViewportConfig as bB, type ViewportOrientation as bC, type ViewportPreset as bD, type VignetteConfig as bE, applySurface as bF, calculateDuration as bG, calculateFontScale as bH, createTemplateContext as bI, createTheme as bJ, createThemeRegistry as bK, getAspectRatioString as bL, getBlockAtTime as bM, getCaptionAtTime as bN, getDocPlaybackDuration as bO, getLayoutHints as bP, getSafeTextBounds as bQ, getSegmentAtTime as bR, getTwoColumnPositions as bS, getViewport as bT, getViewportOrientation as bU, isPersistentLayerTemplate as bV, isTemplateBlock as bW, scaledFontSize$1 as bX, resolveMediaSchedule as bY, scaledFontSize as bZ, type TextStyle as ba, type Theme as bb, type ThemeColorPalette as bc, type ThemeColorScheme as bd, type ThemePageStyle as be, type ThemeRegistry as bf, type ThemeSchemaVersion as bg, type ThemeSeedColors as bh, type ThemeStyle as bi, type ThemeTypography as bj, type TimelineBlockInput as bk, type TimelineTemplateEvent as bl, type TimelineTemplateLink as bm, type TimelineTemplateTrack as bn, type TitleBlockInput as bo, type TitleCaptionConfig as bp, type TreeBlockInput as bq, type TreeLayer as br, type TreeLayerItem as bs, type TreeLayerStyle as bt, type TreeTemplateItem as bu, type TwoColumnInput as bv, VIEWPORT_PRESETS as bw, type VideoLayer as bx, type VideoPlacement as by, type VideoPullQuoteInput as bz, type Animation as c, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type Block as j, type BlockConnection as k, type BorderStyle as l, type CaptionTrack as m, type CaptionWord as n, type ChartBaseFields as o, type ChartTemplateInput as p, type ColorScheme as q, type ColumnChartInput as r, type ComparisonBarInput as s, type ContentBlockInput as t, type CornerBrandingConfig as u, type CustomTemplateDefinition as v, type CustomTemplateLayer as w, DEFAULT_DOC_FONT as x, DEFAULT_TITLE_FONT as y, type DataTableInput as z };
2773
+ export { type ImageTreatment as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, DARK_SURFACE as D, DEFAULT_TITLE_FONT as E, type DataTableInput as F, type DateEventInput as G, type DeepPartial as H, type DefinitionCardInput as I, type DiagramBlockInput as J, type DiagramEdgeAnchor as K, type DiagramTemplateEdge as L, type DiagramTemplateNode as M, type Doc as N, type DocBlock as O, type DocDiagnostic as P, type DonutChartInput as Q, type DrawingBlockInput as R, FRONTMATTER_CUSTOM_TEMPLATES_KEY as S, FRONTMATTER_CUSTOM_THEMES_KEY as T, type FactCardInput as U, type FontFamily as V, type FontFamilyKind as W, type FullBleedQuoteInput as X, type GradientBackgroundConfig as Y, type ImageBackgroundConfig as Z, type ImageLayer as _, type AccentPosition as a, type SectionHeaderInput as a$, type ImageWithCaptionInput as a0, LIGHT_SURFACE as a1, type Layer as a2, type LayerRepeat as a3, type LayoutHints as a4, type LeftFeatureInput as a5, type LineChartInput as a6, type LinearGradient as a7, type ListBlockInput as a8, type MapBlockInput as a9, type PageBackground as aA, type PageDesignFamily as aB, type PageEmphasis as aC, type PageHeadingTreatment as aD, type PageSectionKind as aE, type PageSectionOverride as aF, type PageTokens as aG, type PathLayer as aH, type PatternBackgroundConfig as aI, type PersistentLayer as aJ, type PersistentLayerConfig as aK, type PersistentLayerTemplate as aL, type PersistentLayerTemplateConfig as aM, type PersistentLayerTemplateType as aN, type PhotoGridInput as aO, type PieChartInput as aP, type PipStyle as aQ, type Position as aR, type ProgressIndicatorConfig as aS, type PromotedBodyAnnotation as aT, type PullQuoteInput as aU, type QuoteBlockInput as aV, type RawLayersInput as aW, type RenderStyle as aX, type RightFeatureInput as aY, type ScatterChartInput as aZ, type ScheduledClip as a_, type MapLayer as aa, type MapMarker as ab, type MapTileStyle as ac, type MarkerStyle as ad, type MediaClip as ae, type MediaScheduleOptions as af, type MermaidLayer as ag, PAGE_ACCENT_STRATEGIES as ah, PAGE_BACKGROUNDS as ai, PAGE_BACKGROUND_RHYTHMS as aj, PAGE_DESIGN_FAMILIES as ak, PAGE_DIVIDERS as al, PAGE_EMPHASES as am, PAGE_EYEBROWS as an, PAGE_HEADING_CASES as ao, PAGE_HEADING_SCALES as ap, PAGE_HEADING_UNDERLINES as aq, PAGE_HERO_STYLES as ar, PAGE_IMAGE_FRAMINGS as as, PAGE_NUMERAL_STYLES as at, PAGE_PATTERNS as au, PAGE_QUOTE_MARKS as av, PAGE_SECTION_KINDS as aw, PAGE_SECTION_SPACINGS as ax, PAGE_SHADOWS as ay, type PageAccentRotation as az, type AmbientGradientConfig as b, getTwoColumnPositions as b$, type ShapeFilter as b0, type ShapeLayer as b1, type ShapePattern as b2, type SolidBackgroundConfig as b3, type StartBlockConfig as b4, type StatHighlightInput as b5, type SurfaceScheme as b6, THEME_SCHEMA_VERSION as b7, type TableLayer as b8, type TableLayerStyle as b9, type TwoColumnInput as bA, VIEWPORT_PRESETS as bB, type VideoLayer as bC, type VideoPipPosition as bD, type VideoPipShape as bE, type VideoPipSize as bF, type VideoPlacement as bG, type VideoPresentation as bH, type VideoPullQuoteInput as bI, type VideoWithCaptionInput as bJ, type ViewportConfig as bK, type ViewportOrientation as bL, type ViewportPreset as bM, type VignetteConfig as bN, applySurface as bO, calculateDuration as bP, calculateFontScale as bQ, createTemplateContext as bR, createTheme as bS, createThemeRegistry as bT, getAspectRatioString as bU, getBlockAtTime as bV, getCaptionAtTime as bW, getDocPlaybackDuration as bX, getLayoutHints as bY, getSafeTextBounds as bZ, getSegmentAtTime as b_, type TemplateBlock as ba, type TemplateContext as bb, type TemplateFunction as bc, type TemplateRegistry as bd, type TextLayer as be, type TextStyle as bf, type Theme as bg, type ThemeColorPalette as bh, type ThemeColorScheme as bi, type ThemePageStyle as bj, type ThemeRegistry as bk, type ThemeSchemaVersion as bl, type ThemeSeedColors as bm, type ThemeStyle as bn, type ThemeTypography as bo, type TimelineBlockInput as bp, type TimelineTemplateEvent as bq, type TimelineTemplateLink as br, type TimelineTemplateTrack as bs, type TitleBlockInput as bt, type TitleCaptionConfig as bu, type TreeBlockInput as bv, type TreeLayer as bw, type TreeLayerItem as bx, type TreeLayerStyle as by, type TreeTemplateItem as bz, type Animation as c, getViewport as c0, getViewportOrientation as c1, isCustomTemplateDefinition as c2, isPersistentLayerTemplate as c3, isTemplateBlock as c4, scaledFontSize$1 as c5, resolveMediaSchedule as c6, scaledFontSize as c7, validateCustomTemplateDefinition as c8, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type Block as j, type BlockConnection as k, type BorderStyle as l, type CaptionTrack as m, type CaptionWord as n, type ChartBaseFields as o, type ChartTemplateInput as p, type ColorScheme as q, type ColumnChartInput as r, type ComparisonBarInput as s, type ContentBlockInput as t, type CornerBrandingConfig as u, type CustomTemplateDefinition as v, type CustomTemplateLayer as w, type CustomTemplateValidationError as x, type CustomTemplateValidationResult as y, DEFAULT_DOC_FONT as z };
@@ -1,4 +1,4 @@
1
- import { Y as ImageLayer, b9 as TextLayer, aY as ShapeLayer, aE as PathLayer } from './Doc-DLpyOAXJ.js';
1
+ import { _ as ImageLayer, be as TextLayer, b1 as ShapeLayer, aH as PathLayer } from './Doc-BKKcPjfe.js';
2
2
 
3
3
  /**
4
4
  * ImageEditDoc — JSON document describing a layered, editable image.
@@ -1,4 +1,4 @@
1
- import { ab as BlockConnection, a2 as TransitionType, a1 as TransitionDirection } from './types-CUNc9biN.js';
1
+ import { ac as BlockConnection, a3 as TransitionType, a2 as TransitionDirection } from './types-CcrDFdWH.js';
2
2
 
3
3
  /**
4
4
  * Heading-attribute value coercion.
@@ -30,9 +30,10 @@ import {
30
30
  pickContrastingText,
31
31
  relativeLuminance,
32
32
  resolveFontFamily,
33
+ validateCustomTemplateDefinition,
33
34
  validateTheme,
34
35
  withAlpha
35
- } from "./chunk-C33GTPUZ.js";
36
+ } from "./chunk-SBAX4ZPO.js";
36
37
  import {
37
38
  VIEWPORT_PRESETS,
38
39
  cloneData,
@@ -45,14 +46,17 @@ import {
45
46
  } from "./chunk-BAOV476U.js";
46
47
  import {
47
48
  KNOWN_BLOCK_META_KEYS,
49
+ TABLE_FED_TEMPLATES,
48
50
  coerceAnnotationValues,
51
+ isContainerTemplate,
49
52
  matchTrailingTemplateAnnotation,
50
53
  parseNumber,
51
54
  parseTimeSeconds,
55
+ resolveTemplateName,
52
56
  sanitizeUrl,
53
57
  splitKeyValueToken,
54
58
  tokenizeAttrTokens
55
- } from "./chunk-2VCNTDNZ.js";
59
+ } from "./chunk-D6YTLQCL.js";
56
60
  import {
57
61
  extractPlainText,
58
62
  readFrontmatterThemeId,
@@ -411,33 +415,6 @@ function wrapWithPersistentLayers(layers, block, bottomLayers, topLayers) {
411
415
  ];
412
416
  }
413
417
 
414
- // src/doc/templates/templateNames.ts
415
- var TEMPLATE_ALIASES = Object.freeze({
416
- titleBlock: "title",
417
- quoteBlock: "quote",
418
- mapBlock: "map",
419
- listBlock: "list",
420
- diagramBlock: "diagram",
421
- diagramNode: "diagram"
422
- });
423
- function resolveTemplateName(name) {
424
- return TEMPLATE_ALIASES[name] ?? name;
425
- }
426
- var TABLE_FED_TEMPLATES = /* @__PURE__ */ new Set([
427
- "dataTable",
428
- "barChart",
429
- "columnChart",
430
- "pieChart",
431
- "donutChart",
432
- "lineChart",
433
- "areaChart",
434
- "scatterChart"
435
- ]);
436
- var CONTAINER_TEMPLATES = /* @__PURE__ */ new Set(["diagram", "drawing", "layout"]);
437
- function isContainerTemplate(name) {
438
- return !!name && CONTAINER_TEMPLATES.has(resolveTemplateName(name));
439
- }
440
-
441
418
  // src/doc/utils/themeUtils.ts
442
419
  var FALLBACK_COLOR_SCHEME = {
443
420
  bg: "#1a365d",
@@ -8919,7 +8896,8 @@ function expandDocBlocks(blocks, options = {}) {
8919
8896
  audioSegments,
8920
8897
  customTemplates,
8921
8898
  failureMode = "fallback",
8922
- onDiagnostic
8899
+ onDiagnostic,
8900
+ splitLongBlocks = true
8923
8901
  } = opts;
8924
8902
  const totalBlocks = blocks.length;
8925
8903
  const registry = customTemplates && customTemplates.length > 0 ? buildRegistry(customTemplates) : templateRegistry;
@@ -9110,27 +9088,29 @@ function expandDocBlocks(blocks, options = {}) {
9110
9088
  }
9111
9089
  }
9112
9090
  const MAX_BLOCK_DURATION = 20;
9113
- for (let i = 0; i < segmentExpandedBlocks.length; i++) {
9114
- const block = segmentExpandedBlocks[i];
9115
- if (block.duration > MAX_BLOCK_DURATION) {
9116
- const numParts = Math.ceil(block.duration / MAX_BLOCK_DURATION);
9117
- const partDuration = block.duration / numParts;
9118
- if (partDuration >= MIN_TRANSITION_GAP) {
9119
- block.duration = partDuration;
9120
- for (let p = 1; p < numParts; p++) {
9121
- const splitBlock = {
9122
- id: `${block.id}-split-${p}`,
9123
- startTime: block.startTime + p * partDuration,
9124
- duration: partDuration,
9125
- audioSegment: block.audioSegment,
9126
- layers: (block.layers ?? []).map((layer) => ({
9127
- ...cloneData(layer),
9128
- id: `${layer.id}-split-${p}`
9129
- })),
9130
- transition: { type: "dissolve", duration: 1 },
9131
- template: block.template
9132
- };
9133
- expandedBlocks.push(splitBlock);
9091
+ if (splitLongBlocks) {
9092
+ for (let i = 0; i < segmentExpandedBlocks.length; i++) {
9093
+ const block = segmentExpandedBlocks[i];
9094
+ if (block.duration > MAX_BLOCK_DURATION) {
9095
+ const numParts = Math.ceil(block.duration / MAX_BLOCK_DURATION);
9096
+ const partDuration = block.duration / numParts;
9097
+ if (partDuration >= MIN_TRANSITION_GAP) {
9098
+ block.duration = partDuration;
9099
+ for (let p = 1; p < numParts; p++) {
9100
+ const splitBlock = {
9101
+ id: `${block.id}-split-${p}`,
9102
+ startTime: block.startTime + p * partDuration,
9103
+ duration: partDuration,
9104
+ audioSegment: block.audioSegment,
9105
+ layers: (block.layers ?? []).map((layer) => ({
9106
+ ...cloneData(layer),
9107
+ id: `${layer.id}-split-${p}`
9108
+ })),
9109
+ transition: { type: "dissolve", duration: 1 },
9110
+ template: block.template
9111
+ };
9112
+ expandedBlocks.push(splitBlock);
9113
+ }
9134
9114
  }
9135
9115
  }
9136
9116
  }
@@ -9230,16 +9210,15 @@ function readCustomTemplatesFromFrontmatter(frontmatter) {
9230
9210
  for (const entry of candidates) {
9231
9211
  if (!entry || typeof entry !== "object") continue;
9232
9212
  const e = entry;
9233
- if (typeof e.name !== "string" || typeof e.label !== "string") continue;
9234
- if (!Array.isArray(e.layers)) continue;
9235
- const def = {
9213
+ const candidate = {
9236
9214
  name: e.name,
9237
9215
  label: e.label,
9238
- viewport: readViewport(e.viewport),
9216
+ viewport: e.viewport ?? { ...DEFAULT_VIEWPORT },
9239
9217
  layers: e.layers
9240
9218
  };
9241
- if (typeof e.description === "string") def.description = e.description;
9242
- out.push(def);
9219
+ if (e.description !== void 0) candidate.description = e.description;
9220
+ const result = validateCustomTemplateDefinition(candidate);
9221
+ if (result.template) out.push(result.template);
9243
9222
  }
9244
9223
  return out.length > 0 ? out : void 0;
9245
9224
  }
@@ -9255,15 +9234,6 @@ function writeCustomTemplatesToFrontmatter(templates, options) {
9255
9234
  }
9256
9235
  return JSON.stringify(map, null, options?.pretty ? 2 : void 0);
9257
9236
  }
9258
- function readViewport(raw) {
9259
- if (raw && typeof raw === "object") {
9260
- const v = raw;
9261
- const w = typeof v.width === "number" ? v.width : DEFAULT_VIEWPORT.width;
9262
- const h = typeof v.height === "number" ? v.height : DEFAULT_VIEWPORT.height;
9263
- return { width: w, height: h };
9264
- }
9265
- return DEFAULT_VIEWPORT;
9266
- }
9267
9237
  function expandCompactMap(map) {
9268
9238
  return Object.entries(map).map(([name, raw]) => {
9269
9239
  const e = raw && typeof raw === "object" ? raw : {};
@@ -9506,14 +9476,8 @@ function extractTableData(table) {
9506
9476
  }
9507
9477
 
9508
9478
  // src/doc/standaloneAnnotation.ts
9509
- function parseStandaloneAnnotation(node) {
9510
- if (node.type !== "paragraph") return null;
9511
- const children = node.children ?? [];
9512
- if (children.length !== 1 || children[0].type !== "text") return null;
9513
- const text = children[0].value.trim();
9514
- const match = matchTrailingTemplateAnnotation(text);
9515
- if (!match || match.index !== 0) return null;
9516
- const tokens = tokenizeAttrTokens(match.inner.trim());
9479
+ function parseAnnotationInner(inner) {
9480
+ const tokens = tokenizeAttrTokens(inner.trim());
9517
9481
  const firstIsParam = tokens.length > 0 && tokens[0].indexOf("=") > 0;
9518
9482
  const template = firstIsParam || tokens.length === 0 ? void 0 : tokens[0];
9519
9483
  const startIdx = firstIsParam ? 0 : 1;
@@ -9524,6 +9488,15 @@ function parseStandaloneAnnotation(node) {
9524
9488
  }
9525
9489
  return { template, params };
9526
9490
  }
9491
+ function parseStandaloneAnnotation(node) {
9492
+ if (node.type !== "paragraph") return null;
9493
+ const children = node.children ?? [];
9494
+ if (children.length !== 1 || children[0].type !== "text") return null;
9495
+ const text = children[0].value.trim();
9496
+ const match = matchTrailingTemplateAnnotation(text);
9497
+ if (!match || match.index !== 0) return null;
9498
+ return parseAnnotationInner(match.inner);
9499
+ }
9527
9500
 
9528
9501
  // src/doc/mediaAnnotations.ts
9529
9502
  var MEDIA_TEMPLATES = /* @__PURE__ */ new Set(["audio", "video", "media"]);
@@ -9546,6 +9519,15 @@ function videoPlacement(params) {
9546
9519
  function lockToBlock(raw) {
9547
9520
  return raw !== "false" && raw !== "0";
9548
9521
  }
9522
+ function videoPipSize(raw) {
9523
+ return raw === "small" || raw === "large" ? raw : void 0;
9524
+ }
9525
+ function videoPipShape(raw) {
9526
+ return raw === "square" || raw === "wide" ? raw : void 0;
9527
+ }
9528
+ function videoPipPosition(raw) {
9529
+ return raw === "top-left" || raw === "top-right" || raw === "bottom-left" || raw === "bottom-right" ? raw : void 0;
9530
+ }
9549
9531
  function toMediaClip(parsed, id) {
9550
9532
  const { template, params } = parsed;
9551
9533
  if (!template || !MEDIA_TEMPLATES.has(template)) return null;
@@ -9562,6 +9544,12 @@ function toMediaClip(parsed, id) {
9562
9544
  };
9563
9545
  const placement = kind === "video" ? videoPlacement(params) : void 0;
9564
9546
  if (placement && placement !== "content") clip.placement = placement;
9547
+ const pipSize = videoPipSize(params.pipSize);
9548
+ const pipShape = videoPipShape(params.pipShape);
9549
+ const pipPosition = videoPipPosition(params.pipPosition);
9550
+ if (pipSize) clip.pipSize = pipSize;
9551
+ if (pipShape) clip.pipShape = pipShape;
9552
+ if (pipPosition) clip.pipPosition = pipPosition;
9565
9553
  if (kind === "video" && placement && placement !== "content" && params.lockToBlock != null) {
9566
9554
  const locked = lockToBlock(params.lockToBlock);
9567
9555
  clip.lockToBlock = locked;
@@ -9626,6 +9614,12 @@ function htmlVideoClip(node, id) {
9626
9614
  startAt: locked ? 0 : time(element.attributes["data-squisq-video-start-at"]) ?? 0,
9627
9615
  anchor: locked ? "block" : "document"
9628
9616
  };
9617
+ const pipSize = videoPipSize(element.attributes["data-squisq-video-pip-size"]);
9618
+ const pipShape = videoPipShape(element.attributes["data-squisq-video-pip-shape"]);
9619
+ const pipPosition = videoPipPosition(element.attributes["data-squisq-video-pip-position"]);
9620
+ if (pipSize) clip.pipSize = pipSize;
9621
+ if (pipShape) clip.pipShape = pipShape;
9622
+ if (pipPosition) clip.pipPosition = pipPosition;
9629
9623
  const clipStart = time(element.attributes["data-squisq-video-clip-start"]);
9630
9624
  const clipEnd = time(element.attributes["data-squisq-video-clip-end"]);
9631
9625
  if (clipStart != null) clip.clipStart = clipStart;
@@ -9716,6 +9710,78 @@ function extractTemplateBlocksFromContents(contents, options) {
9716
9710
  return { leading, blocks };
9717
9711
  }
9718
9712
 
9713
+ // src/doc/promoteBodyAnnotation.ts
9714
+ function lastTextChildValue(node) {
9715
+ if (node.type !== "paragraph") return null;
9716
+ const children = node.children;
9717
+ if (children.length === 0) return null;
9718
+ const last = children[children.length - 1];
9719
+ return last.type === "text" ? last.value : null;
9720
+ }
9721
+ function isBodyAnnotationNode(node) {
9722
+ if (parseStandaloneAnnotation(node)?.template) return true;
9723
+ const value = lastTextChildValue(node);
9724
+ if (value == null) return false;
9725
+ const match = matchTrailingTemplateAnnotation(value);
9726
+ return !!match && match.index > 0 && !!parseAnnotationInner(match.inner).template;
9727
+ }
9728
+ function stripTrailingToken(contents, index, cut) {
9729
+ const out = [...contents];
9730
+ const para = out[index];
9731
+ if (para.type !== "paragraph") return out;
9732
+ const children = [...para.children];
9733
+ const last = children[children.length - 1];
9734
+ if (last.type !== "text") return out;
9735
+ const kept = last.value.slice(0, cut);
9736
+ if (kept.length === 0 && children.length === 1) {
9737
+ out.splice(index, 1);
9738
+ } else {
9739
+ children[children.length - 1] = { ...last, value: kept };
9740
+ out[index] = { ...para, children };
9741
+ }
9742
+ return out;
9743
+ }
9744
+ function detectPromotableBodyAnnotation(contents) {
9745
+ if (!contents || contents.length === 0) return null;
9746
+ const lastIndex = contents.length - 1;
9747
+ const last = contents[lastIndex];
9748
+ let data = null;
9749
+ let strippedContents = null;
9750
+ const whole = parseStandaloneAnnotation(last);
9751
+ if (whole?.template && last.type === "paragraph") {
9752
+ const first = last.children[0];
9753
+ data = {
9754
+ template: whole.template,
9755
+ params: whole.params,
9756
+ origin: {
9757
+ kind: "paragraph",
9758
+ index: lastIndex,
9759
+ raw: first && first.type === "text" ? first.value.trim() : ""
9760
+ }
9761
+ };
9762
+ strippedContents = contents.slice(0, lastIndex);
9763
+ } else {
9764
+ const value = lastTextChildValue(last);
9765
+ const match = value != null ? matchTrailingTemplateAnnotation(value) : null;
9766
+ if (value != null && match && match.index > 0) {
9767
+ const parsed = parseAnnotationInner(match.inner);
9768
+ if (parsed.template) {
9769
+ data = {
9770
+ template: parsed.template,
9771
+ params: parsed.params,
9772
+ origin: { kind: "trailing", index: lastIndex, suffix: value.slice(match.index) }
9773
+ };
9774
+ strippedContents = stripTrailingToken(contents, lastIndex, match.index);
9775
+ }
9776
+ }
9777
+ }
9778
+ if (!data || !strippedContents) return null;
9779
+ for (let i = 0; i < lastIndex; i++) {
9780
+ if (isBodyAnnotationNode(contents[i])) return null;
9781
+ }
9782
+ return { data, strippedContents };
9783
+ }
9784
+
9719
9785
  // src/doc/markdownToDoc.ts
9720
9786
  var SLUG_NON_WORD_RE = /[^\w\s-]/g;
9721
9787
  var SLUG_SPACES_RE = /[\s_]+/g;
@@ -9761,6 +9827,9 @@ function pinnedHeadingMeta(heading) {
9761
9827
  return { ...fromAnnotation, ...fromPandoc };
9762
9828
  }
9763
9829
  function pinnedMeta(block) {
9830
+ if (block.promotedBodyAnnotation?.params) {
9831
+ return coerceAnnotationValues(block.promotedBodyAnnotation.params).blockMeta;
9832
+ }
9764
9833
  if (block.sourceHeading) return pinnedHeadingMeta(block.sourceHeading);
9765
9834
  if (block.sourceAnnotation?.params) {
9766
9835
  return coerceAnnotationValues(block.sourceAnnotation.params).blockMeta;
@@ -9770,6 +9839,22 @@ function pinnedMeta(block) {
9770
9839
  function getPinnedBlockMeta(block) {
9771
9840
  return pinnedMeta(block);
9772
9841
  }
9842
+ function promoteBodyAnnotations(blocks) {
9843
+ for (const block of blocks) {
9844
+ if (!block.sourceHeading || block.sourceHeading.templateAnnotation?.template) continue;
9845
+ const found = detectPromotableBodyAnnotation(block.contents);
9846
+ if (!found) continue;
9847
+ const { template, params } = found.data;
9848
+ if (isMediaAnnotationName(template) || !hasTemplate(template)) continue;
9849
+ block.template = resolveTemplateName(template);
9850
+ if (Object.keys(params).length > 0) {
9851
+ block.templateOverrides = params;
9852
+ applyBlockMeta2(block, coerceAnnotationValues(params).blockMeta);
9853
+ }
9854
+ block.contents = found.strippedContents;
9855
+ block.promotedBodyAnnotation = found.data;
9856
+ }
9857
+ }
9773
9858
  function expandStandaloneAnnotations(blocks, makeId, defaultDuration) {
9774
9859
  const out = [];
9775
9860
  for (const block of blocks) {
@@ -9906,6 +9991,7 @@ function markdownToDoc(markdownDoc, options) {
9906
9991
  if (rootBlocks.length > 0 && !rootBlocks[0].sourceHeading && (rootBlocks[0].contents?.length ?? 0) === 0 && (rootBlocks[0].children?.length ?? 0) === 0 && !rootBlocks[0].media) {
9907
9992
  rootBlocks.shift();
9908
9993
  }
9994
+ promoteBodyAnnotations(flattenBlocks(rootBlocks));
9909
9995
  const makeStandaloneId = (parsed) => {
9910
9996
  const base = parsed.params.title ?? parsed.template ?? "block";
9911
9997
  return idGenerator ? idGenerator.fromText(base) : slugify(base);
@@ -10165,7 +10251,7 @@ function frontmatterDisablesAutoTemplates(markdownDoc) {
10165
10251
  }
10166
10252
  function applyAutoTemplates(blocks, resolvedDefault, state) {
10167
10253
  for (const block of blocks) {
10168
- const annotated = !!block.sourceHeading?.templateAnnotation?.template;
10254
+ const annotated = !!block.sourceHeading?.templateAnnotation?.template || !!block.promotedBodyAnnotation;
10169
10255
  if (block.sourceHeading && !annotated && block.template === resolvedDefault) {
10170
10256
  const profile = profileBlockContents(block.contents ?? []);
10171
10257
  const picked = pickAutoTemplate(profile, state.featureIndex);
@@ -10604,11 +10690,6 @@ export {
10604
10690
  getPersistentLayersFromTheme,
10605
10691
  resolvePersistentLayers,
10606
10692
  wrapWithPersistentLayers,
10607
- TEMPLATE_ALIASES,
10608
- resolveTemplateName,
10609
- TABLE_FED_TEMPLATES,
10610
- CONTAINER_TEMPLATES,
10611
- isContainerTemplate,
10612
10693
  resolveColorScheme,
10613
10694
  getThemeFont,
10614
10695
  themedFontSize,
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  coerceAnnotationValues,
3
+ isReservedAnnotationToken,
3
4
  matchTrailingPandocAttr,
4
5
  matchTrailingTemplateAnnotation,
5
6
  quoteAttrValue,
6
7
  splitKeyValueToken,
7
8
  tokenizeAttrTokens
8
- } from "./chunk-2VCNTDNZ.js";
9
+ } from "./chunk-D6YTLQCL.js";
9
10
  import {
10
11
  resolveIcon
11
12
  } from "./chunk-7N4G32LG.js";
@@ -303,6 +304,7 @@ function splitTextOnIcons(value, position) {
303
304
  const out = [];
304
305
  while ((match = ICON_TOKEN_RE.exec(value)) !== null) {
305
306
  const token = match[1];
307
+ if (isReservedAnnotationToken(token)) continue;
306
308
  const icon = resolveIcon(token);
307
309
  if (!icon) continue;
308
310
  if (match.index > lastIndex) {