@folienbaukasten/extension-toolkit 1.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.
Files changed (63) hide show
  1. package/README.md +109 -0
  2. package/abi/README.md +20 -0
  3. package/abi/abi.json +151 -0
  4. package/abi/pack.d.ts +196 -0
  5. package/abi/pack.js +126 -0
  6. package/abi/provenance.json +5 -0
  7. package/abi/shims/jsx-runtime.js +13 -0
  8. package/abi/shims/platform.js +48 -0
  9. package/abi/shims/react.js +18 -0
  10. package/abi/types/charts/geometry.d.ts +43 -0
  11. package/abi/types/charts/option.d.ts +15 -0
  12. package/abi/types/charts/scale.d.ts +14 -0
  13. package/abi/types/charts/theme.d.ts +16 -0
  14. package/abi/types/charts/waterfall.d.ts +35 -0
  15. package/abi/types/components/Block.d.ts +31 -0
  16. package/abi/types/components/BlockArrow.d.ts +16 -0
  17. package/abi/types/components/Card.d.ts +25 -0
  18. package/abi/types/components/ChartView.d.ts +4 -0
  19. package/abi/types/components/DriverTree.d.ts +9 -0
  20. package/abi/types/components/FindingsBanner.d.ts +21 -0
  21. package/abi/types/components/HarveyBall.d.ts +12 -0
  22. package/abi/types/components/HeaderTitle.d.ts +19 -0
  23. package/abi/types/components/InsightRail.d.ts +13 -0
  24. package/abi/types/components/KpiTile.d.ts +5 -0
  25. package/abi/types/components/Matrix.d.ts +5 -0
  26. package/abi/types/components/QuoteColumn.d.ts +5 -0
  27. package/abi/types/components/SourceLine.d.ts +6 -0
  28. package/abi/types/components/Table.d.ts +5 -0
  29. package/abi/types/components/Timeline.d.ts +5 -0
  30. package/abi/types/components/slide/ContentSlide.d.ts +29 -0
  31. package/abi/types/components/slide/MissingComponent.d.ts +26 -0
  32. package/abi/types/components/slide/SlideFrame.d.ts +20 -0
  33. package/abi/types/components/slide/SlotView.d.ts +30 -0
  34. package/abi/types/components/slide/registry.d.ts +27 -0
  35. package/abi/types/components/slide/views/AgendaSlideView.d.ts +8 -0
  36. package/abi/types/components/slide/views/CardsSlideView.d.ts +12 -0
  37. package/abi/types/components/slide/views/ChaptersSlideView.d.ts +11 -0
  38. package/abi/types/components/slide/views/ChartSlideView.d.ts +3 -0
  39. package/abi/types/components/slide/views/ComponentSlideView.d.ts +19 -0
  40. package/abi/types/components/slide/views/DriverTreeSlideView.d.ts +3 -0
  41. package/abi/types/components/slide/views/FreeformSlideView.d.ts +3 -0
  42. package/abi/types/components/slide/views/KpiSlideView.d.ts +3 -0
  43. package/abi/types/components/slide/views/MatrixSlideView.d.ts +3 -0
  44. package/abi/types/components/slide/views/QuoteSlideView.d.ts +3 -0
  45. package/abi/types/components/slide/views/QuotesSlideView.d.ts +5 -0
  46. package/abi/types/components/slide/views/SplitSlideView.d.ts +3 -0
  47. package/abi/types/components/slide/views/TableSlideView.d.ts +3 -0
  48. package/abi/types/components/slide/views/TimelineSlideView.d.ts +3 -0
  49. package/abi/types/components/slide/views/TitleSlideView.d.ts +7 -0
  50. package/abi/types/components/slide/views/TwoBlockSlideView.d.ts +3 -0
  51. package/abi/types/components/slide/views/WebSlideView.d.ts +23 -0
  52. package/abi/types/components/slide/views/WhileArrowSlideView.d.ts +14 -0
  53. package/abi/types/deck/data.d.ts +127 -0
  54. package/abi/types/deck/host.d.ts +9 -0
  55. package/abi/types/deck/layouts.d.ts +685 -0
  56. package/abi/types/deck/schema.d.ts +437 -0
  57. package/abi/types/deck/web-body.d.ts +47 -0
  58. package/abi/types/lib/format.d.ts +12 -0
  59. package/abi/types/sets/platform.d.ts +45 -0
  60. package/abi/types/sets/types.d.ts +128 -0
  61. package/dist/fbk-pack.js +756 -0
  62. package/package.json +49 -0
  63. package/tsconfig.extension.json +17 -0
@@ -0,0 +1,437 @@
1
+ import type { DataSource } from './data.ts';
2
+ export type { CellValue, DataRef, DataSheet, DataSource } from './data.ts';
3
+ /** Slide canvas in CSS pixels. Maps 1:1 to a 13.333in × 7.5in (16:9) PPTX
4
+ * slide at 96 DPI. */
5
+ export declare const SLIDE_WIDTH = 1280;
6
+ export declare const SLIDE_HEIGHT = 720;
7
+ /** 914400 EMU per inch / 96 px per inch. */
8
+ export declare const EMU_PER_PX = 9525;
9
+ export interface DeckMeta {
10
+ title: string;
11
+ /**
12
+ * One line saying what this deck is for. Shown as the subtitle of a
13
+ * starter-deck card in the New deck dialog, which is where a theme's
14
+ * templates are chosen — `tools/pack-set.ts` reads it straight off the
15
+ * deck when it builds the pack manifest, so a template describes itself
16
+ * rather than being described somewhere else that can drift.
17
+ */
18
+ description?: string;
19
+ author?: string;
20
+ /** ISO date, e.g. "2026-08-16". Formatting is a renderer concern. */
21
+ date?: string;
22
+ /** Footer text shown on every content slide (e.g. confidentiality note). */
23
+ footer?: string;
24
+ /**
25
+ * Small mark shown in the header of every content slide, where the active
26
+ * theme has a place for one. Root-relative like every other image URL
27
+ * (`/logo.svg`, `/project/assets/logo.png`); themes without a logo slot
28
+ * ignore it, which is why it is optional and never a layout prop.
29
+ */
30
+ logoUrl?: string;
31
+ /** Component set that defines this deck's layouts. Default "consulting". */
32
+ componentSet?: string;
33
+ /**
34
+ * Display name of an *installed* theme this deck was written in, recorded
35
+ * so a machine that lacks the theme can say "This deck uses Acme Theme by
36
+ * Acme GmbH" instead of "unknown component set 'acme'". Never set for
37
+ * built-in themes — the recipient has those.
38
+ */
39
+ componentSetName?: string;
40
+ /** Publisher of the installed theme, for the same message. */
41
+ componentSetPublisher?: string;
42
+ /**
43
+ * Version of an *installed* theme (ui.md A9) this deck was written against,
44
+ * e.g. "2.1.0". Only its major matters: fixes and additions inside a major
45
+ * are picked up automatically, while a theme that changes how slides look
46
+ * ships a new major and installs beside the old one — so a deck someone has
47
+ * already presented keeps rendering as it did until they choose otherwise.
48
+ * Absent (the normal case, and every deck in a built-in theme) means "the
49
+ * newest installed".
50
+ */
51
+ componentSetVersion?: string;
52
+ /**
53
+ * Web Mode: the deck trades its PowerPoint export for
54
+ * the whole browser. A validation profile, not a rendering mode — when
55
+ * true, the web-only vocabulary (extra chart types, web-only extension
56
+ * components) validates, and PPTX export is refused with a clear message.
57
+ * Absent or false = PowerPoint mode = the strict profile. Toggled by the
58
+ * editor's "Activate Web Mode" button, never by the model.
59
+ */
60
+ webMode?: boolean;
61
+ }
62
+ /** A slide as the platform sees it; the selected component set gives
63
+ * `layout` meaning and types `props`. */
64
+ export interface SlideSpec {
65
+ layout: string;
66
+ props: unknown;
67
+ }
68
+ export interface Deck {
69
+ meta: DeckMeta;
70
+ slides: SlideSpec[];
71
+ /**
72
+ * Workbook data imported into this deck (src/deck/data.ts). Any prop in
73
+ * any slide may be a `{ "$ref": "source!Sheet!A1:D9" }` pointer into it
74
+ * instead of a literal; every render path resolves the deck before it
75
+ * renders, so components never see a ref.
76
+ */
77
+ data?: DataSource[];
78
+ }
79
+ /** Action title + sub-action title shown at the top of content slides. */
80
+ export interface HeaderSpec {
81
+ /**
82
+ * A substring of `title` to render in the theme's highlight colour — the
83
+ * one phrase the slide turns on ("what we *found*"). Must appear in the
84
+ * title verbatim; ignored when it does not. One phrase per slide: a
85
+ * highlight that repeats stops being one.
86
+ */
87
+ highlight?: string;
88
+ title: string;
89
+ subtitle?: string;
90
+ /** Short category label above the title, e.g. "Market entry" — a few words,
91
+ * not a sentence. Sets that have no place for one ignore it. */
92
+ kicker?: string;
93
+ }
94
+ /** Harvey ball fill level in quarters. */
95
+ export type HarveyValue = 0 | 25 | 50 | 75 | 100;
96
+ /**
97
+ * A content block. `box` is the neutral container, `callout` the
98
+ * accent-colored findings box. Body strings are separate paragraphs.
99
+ */
100
+ export interface BlockSpec {
101
+ title?: string;
102
+ body: string | string[];
103
+ /**
104
+ * Bulleted points under the body. Use for parallel items a reader scans
105
+ * (evidence, criteria, steps); keep prose in `body`. Both may appear —
106
+ * body sets up the point, bullets enumerate it.
107
+ */
108
+ bullets?: string[];
109
+ variant?: 'box' | 'callout';
110
+ /** Optional harvey-ball rating rendered next to the block title. */
111
+ rating?: HarveyValue;
112
+ }
113
+ /** Findings/recommendation banner: accent label segment + statement bar. */
114
+ export interface FindingSpec {
115
+ /** Label in the accent segment. Default "Findings". */
116
+ label?: string;
117
+ text: string;
118
+ }
119
+ /** One KPI stat tile. */
120
+ export interface KpiSpec {
121
+ /** Rendered uppercase. */
122
+ label: string;
123
+ /** Numbers are formatted per valueStyle; strings pass through. */
124
+ value: number | string;
125
+ valueStyle?: 'plain' | 'compact' | 'percent';
126
+ /** Fraction, e.g. 0.42 → "▲ 42%"; sign picks the arrow. */
127
+ delta?: number;
128
+ /** Context after the delta, e.g. "vs PY". */
129
+ deltaLabel?: string;
130
+ /** Which direction is good (colors the delta). Default 'up'; churn-like
131
+ * metrics use 'down' so a falling value shows green. */
132
+ deltaGood?: 'up' | 'down';
133
+ /**
134
+ * The run behind the number, oldest first, and ENDING AT THE PERIOD
135
+ * `value` REPORTS — the last point is the same figure the tile shows, in
136
+ * the same units. A series that ends anywhere else draws a line that
137
+ * contradicts the number printed above it, which is worse than no line.
138
+ *
139
+ * Supply the readings only. Every coordinate is derived from them: the run
140
+ * is normalised to its own min and max, so units never matter and no axis
141
+ * is drawn. Do not compute positions, percentages or a path.
142
+ *
143
+ * A delta says the number moved; a sparkline says how it moved, and the
144
+ * two answer different objections. Six to eight points read cleanly; fewer
145
+ * looks arbitrary, more turns to noise at tile size.
146
+ *
147
+ * @minItems 2
148
+ */
149
+ series?: number[];
150
+ /**
151
+ * Goal for the period, in the value's units. Draws a meter under the
152
+ * number instead of a sparkline, and turns "24.3M" into "24.3M of the 30M
153
+ * we committed to".
154
+ *
155
+ * `deltaGood` sets which way the goal reads. The default 'up' makes it a
156
+ * TARGET to reach, and the meter fills toward it. 'down' makes it a CAP
157
+ * not to breach — the meter then fills with how much of the allowance is
158
+ * spent, and going over reads in the negative colour instead of showing a
159
+ * full bar, which is what a churn figure at 140% of its goal would
160
+ * otherwise look like.
161
+ *
162
+ * A tile takes a sparkline or a meter, not both — two rows of geometry
163
+ * under one number is the point at which a tile stops being readable from
164
+ * the third row. `series` wins if a deck sets both.
165
+ */
166
+ target?: number;
167
+ /** One short line under the number: the caveat, the denominator, the
168
+ * thing an audience asks about before it believes the figure. */
169
+ note?: string;
170
+ /** The one tile the slide is actually about — drawn in the theme's
171
+ * emphasis treatment. Marking every tile marks none. */
172
+ emphasis?: boolean;
173
+ }
174
+ /** One numbered entry of an agenda / table of contents. */
175
+ export interface AgendaItemSpec {
176
+ title: string;
177
+ /** Optional one-line detail under the topic. */
178
+ note?: string;
179
+ }
180
+ /** One box on a 2×2 matrix. */
181
+ export interface MatrixPointSpec {
182
+ label: string;
183
+ /** Horizontal position, 0 (left) – 100 (right). */
184
+ x: number;
185
+ /** Vertical position, 0 (bottom) – 100 (top). */
186
+ y: number;
187
+ /** Draws the box in the accent color — the option being argued for. */
188
+ emphasis?: boolean;
189
+ }
190
+ /**
191
+ * 2×2 positioning matrix: two named axes, optional quadrant captions and the
192
+ * boxes placed on it. Five to eight points stay readable; beyond that the
193
+ * boxes start to overlap, which the renderer will not resolve for you.
194
+ */
195
+ export interface MatrixSpec {
196
+ /** Axis names, rendered at the low→high end of each axis. */
197
+ xAxis: string;
198
+ yAxis: string;
199
+ /** Quadrant captions, clockwise from top-left. */
200
+ quadrants?: [string, string, string, string];
201
+ points: MatrixPointSpec[];
202
+ }
203
+ /** One branch of a driver tree. */
204
+ export interface DriverSpec {
205
+ title: string;
206
+ /** Separate paragraphs, as in BlockSpec. */
207
+ body?: string | string[];
208
+ }
209
+ /** A verbatim quote with its attribution. */
210
+ export interface QuoteSpec {
211
+ text: string;
212
+ /** Who said it, e.g. "CFO, mid-market retailer". */
213
+ attribution?: string;
214
+ }
215
+ /** One themed column of quotes. `tone` colors the column's accent bar. */
216
+ export interface QuoteColumnSpec {
217
+ title: string;
218
+ tone?: 'positive' | 'negative';
219
+ quotes: QuoteSpec[];
220
+ }
221
+ /** One numbered chapter on a section-divider slide. */
222
+ export interface ChapterSpec {
223
+ title: string;
224
+ /** One or two lines on what the chapter covers. */
225
+ body?: string;
226
+ }
227
+ /** One card in a card grid. */
228
+ export interface CardSpec {
229
+ title?: string;
230
+ body: string | string[];
231
+ /** Accent bar + tinted fill — the card that carries the argument. */
232
+ emphasis?: boolean;
233
+ }
234
+ /** One entry of the insight rail: an accent lead-in and its explanation. */
235
+ export interface InsightSpec {
236
+ label: string;
237
+ text: string;
238
+ }
239
+ /** One event on a timeline, in chronological order. */
240
+ export interface TimelineEventSpec {
241
+ /** Short date or phase label, e.g. "Q1 2027". Display string. */
242
+ date?: string;
243
+ title: string;
244
+ /** Why the event matters — one or two lines. */
245
+ body?: string;
246
+ }
247
+ /**
248
+ * `line`, `bar`, `stacked-bar` and `waterfall` work in every deck — they map
249
+ * to native PowerPoint charts. `pie`, `donut` and `radar` are **Web Mode
250
+ * only**: they render in the browser (preview, HTML and
251
+ * PDF export) but have no faithful pptxgenjs counterpart, so a PowerPoint
252
+ * mode deck rejects them at validation.
253
+ */
254
+ export type ChartType = 'line' | 'bar' | 'stacked-bar' | 'waterfall' | 'pie' | 'donut' | 'radar';
255
+ /**
256
+ * A colour slot, resolved by the theme — never a literal colour. `series`
257
+ * is the series' own place in the theme's ramp; `accent` is the theme's
258
+ * accent (`--color-accent`) for the one series that carries the argument;
259
+ * the rest are the tokens a controlling chart reasons in ("this point is
260
+ * bad news"), so a deck says what a mark *means* and the set says what
261
+ * that looks like.
262
+ */
263
+ export type ChartTone = 'series' | 'positive' | 'negative' | 'neutral' | 'muted' | 'accent';
264
+ export interface ChartSeries {
265
+ name: string;
266
+ /**
267
+ * One value per category. `null` is a gap — a plan that stops where the
268
+ * forecast starts, an actual that has not happened yet. A line breaks
269
+ * there; a bar is simply absent. Never write 0 to mean "no value".
270
+ */
271
+ values: Array<number | null>;
272
+ /**
273
+ * How the series is painted, bar-like types only. `hollow` is an outline
274
+ * with no fill, `hatched` a diagonal pattern — between them, plus solid
275
+ * and a tone, every IBCS scenario notation (actual, previous year, plan,
276
+ * forecast) can be expressed without the platform knowing what a scenario
277
+ * is.
278
+ */
279
+ fill?: 'solid' | 'hollow' | 'hatched';
280
+ /** Colour slot for the whole series. Default: the theme's ramp. */
281
+ tone?: ChartTone;
282
+ /**
283
+ * Colour slot per point; `null` keeps the series colour. What a variance
284
+ * series needs: the same bar is good news or bad news by point, and the
285
+ * sign alone does not say which.
286
+ */
287
+ pointTones?: (ChartTone | null)[];
288
+ /** Dashed stroke, line charts only — a series that is not actual. */
289
+ dash?: boolean;
290
+ }
291
+ /**
292
+ * Which way a bar chart reads. `columns` is vertical (the default);
293
+ * `bars` is horizontal, first category at the TOP — the shape a variance
294
+ * breakdown reads in. Line charts ignore it.
295
+ */
296
+ export type ChartOrientation = 'columns' | 'bars';
297
+ /**
298
+ * The inner plot rect as fractions of the chart box (see
299
+ * `ChartSpec.plotArea`). Re-declared here rather than imported so the deck
300
+ * schema stays one file for the JSON-Schema generator.
301
+ */
302
+ export interface PlotArea {
303
+ /** @minimum 0 @maximum 1 */
304
+ x: number;
305
+ /** @minimum 0 @maximum 1 */
306
+ y: number;
307
+ /** @minimum 0 @maximum 1 */
308
+ w: number;
309
+ /** @minimum 0 @maximum 1 */
310
+ h: number;
311
+ }
312
+ /**
313
+ * Our own chart contract — never raw ECharts options — so the same data
314
+ * renders identically in ECharts (HTML) and as a native PPTX chart.
315
+ *
316
+ * Waterfall: exactly one series whose values are deltas. Indices listed in
317
+ * `totalIndices` are checkpoint bars drawn from zero showing the running
318
+ * total; their value is ignored except at index 0, where it seeds the start.
319
+ * `pointTones` on that series recolours individual bars — how a cost bridge
320
+ * says that a decrease is the good news (default: increase `positive`,
321
+ * decrease `negative`, totals `neutral`).
322
+ *
323
+ * Pie/donut: one series; `categories` name the slices, the series values
324
+ * size them. Radar: `categories` are the spokes, each series one polygon.
325
+ */
326
+ export interface ChartSpec {
327
+ type: ChartType;
328
+ categories: string[];
329
+ series: ChartSeries[];
330
+ /** How values are formatted on axes and labels. percent expects fractions. */
331
+ valueStyle?: 'plain' | 'compact' | 'percent';
332
+ showDataLabels?: boolean;
333
+ /** Bar/stacked-bar only. Default `columns`. */
334
+ orientation?: ChartOrientation;
335
+ /**
336
+ * Pins the inner plot rect — the data area, excluding axis labels — as
337
+ * fractions of the chart's own box. Both renderers take the same four
338
+ * numbers (ECharts an explicit `grid`, PowerPoint a `<c:manualLayout>`
339
+ * with `layoutTarget="inner"`), so the position of a category band stops
340
+ * being each renderer's private business and becomes arithmetic anyone
341
+ * can repeat — which is what lets something OUTSIDE the chart line up
342
+ * with the bars (`src/charts/geometry.ts`).
343
+ *
344
+ * Leave it out and each renderer auto-fits, which looks better on its own
345
+ * and cannot be aligned against. Set it, and leave room: axis labels are
346
+ * drawn outside this rect, so long category names want a bigger `x`.
347
+ */
348
+ plotArea?: PlotArea;
349
+ /** Line charts: draw a symbol at each data point. Default true. */
350
+ showSymbol?: boolean;
351
+ /**
352
+ * Where the value axis starts. Default `zero` — a truncated axis is the
353
+ * commonest way a chart misleads, so `auto` has to be asked for.
354
+ */
355
+ baseline?: 'zero' | 'auto';
356
+ /**
357
+ * Explicit value-axis bounds — the words a shared scale is made of. A
358
+ * grid of small multiples that does not pass the same `valueMax` to every
359
+ * chart is nine different rulers. `valueMin` overrides `baseline`.
360
+ */
361
+ valueMin?: number;
362
+ valueMax?: number;
363
+ /**
364
+ * Distance between gridlines, in value units. Pin it alongside `valueMax`
365
+ * or each renderer picks its own ladder and then draws the pinned maximum
366
+ * as an extra tick on top of the one nearest it — two labels in the same
367
+ * three pixels at the top of the chart.
368
+ */
369
+ valueStep?: number;
370
+ /**
371
+ * Default true. `false` deletes the value axis AND its gridlines, in both
372
+ * renderers — the IBCS look is labels on the marks and no axis furniture,
373
+ * and it is also what lets two stacked charts align: with no value-axis
374
+ * labels there is no label width to disagree about.
375
+ */
376
+ showValueAxis?: boolean;
377
+ /** Default true. `false` for the upper panel of a pair that shares its
378
+ * category axis with the chart below it. */
379
+ showCategoryAxis?: boolean;
380
+ /** Default: shown when there is more than one series. */
381
+ showLegend?: boolean;
382
+ /**
383
+ * Line charts only: print each series' value at its last non-null point.
384
+ * The renderer places the label — no coordinate of ours is involved. The
385
+ * IBCS way to read a trend without hunting through a legend.
386
+ */
387
+ endLabels?: boolean;
388
+ /**
389
+ * Gap between bars as a percentage of bar width (PowerPoint's own unit,
390
+ * mirrored into ECharts). Lower is fatter; 0 makes bars touch.
391
+ * @minimum 0
392
+ * @maximum 500
393
+ */
394
+ barGapPct?: number;
395
+ /**
396
+ * Overlap between adjacent bars WITHIN one category group, in
397
+ * PowerPoint's unit: 0 (the default) makes them touch — the IBCS pair —
398
+ * negative opens a gap, positive overlaps them.
399
+ * @minimum -100
400
+ * @maximum 100
401
+ */
402
+ barOverlapPct?: number;
403
+ /** waterfall only */
404
+ totalIndices?: number[];
405
+ }
406
+ /**
407
+ * A slide body supplied by an installed extension: a bespoke pricing sheet, framework
408
+ * diagram, disclosure block. The platform hosts it in the `component`
409
+ * layout's body region; it cannot touch the chrome bands.
410
+ */
411
+ export interface SlideComponentSpec {
412
+ /**
413
+ * Namespaced component kind, `<extension-id>/<component-name>` — e.g.
414
+ * "acme/pricing-sheet". The namespace makes collisions impossible and
415
+ * tells the install prompt where the component comes from.
416
+ * @pattern ^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$
417
+ */
418
+ kind: string;
419
+ /** Props for the component, validated against the schema its extension
420
+ * ships. Unvalidated when the extension is not installed. */
421
+ props?: unknown;
422
+ }
423
+ /** A table cell: text, a number (formatted per column), or a harvey ball. */
424
+ export type TableCell = string | number | {
425
+ harvey: HarveyValue;
426
+ };
427
+ export interface TableColumn {
428
+ header: string;
429
+ /** Default: numbers right, harvey center, text left. */
430
+ align?: 'left' | 'center' | 'right';
431
+ /** Formatting for numeric cells in this column. */
432
+ valueStyle?: 'plain' | 'compact' | 'percent';
433
+ }
434
+ export interface TableSpec {
435
+ columns: TableColumn[];
436
+ rows: TableCell[][];
437
+ }
@@ -0,0 +1,47 @@
1
+ import type { WebSlideSpec } from './layouts';
2
+ /** Everything in `html` + `css` + `js` together. A body larger than this is
3
+ * a mistake: it lands in deck.json, which is loaded, patched and diffed. */
4
+ export declare const WEB_BODY_MAX_BYTES: number;
5
+ /**
6
+ * Where an image may come from. A data URI, or the app's own root-relative
7
+ * space (`/project/assets/…`, `/logo.svg`) — which is also what the
8
+ * standalone export knows how to inline. Everything else is the network, and
9
+ * the network is not available to a slide (WEB-MODE.md rule 6).
10
+ */
11
+ export declare function isSafeUrl(value: string): boolean;
12
+ /**
13
+ * Everything wrong with one web body, phrased for the model — the same
14
+ * round-trip that carries schema errors and fit findings back to it. `prefix` addresses the slide
15
+ * the way validation messages do: `slides[4].props`.
16
+ */
17
+ export declare function lintWebBody(
18
+ /** `js` is tier B and not in the schema yet;
19
+ * the checks for it are written here because the day it lands is the wrong
20
+ * day to be inventing the message a model gets back. */
21
+ props: WebSlideSpec['props'] & {
22
+ js?: string;
23
+ }, prefix: string): string[];
24
+ /**
25
+ * Rewrite the author's stylesheet so every rule applies inside `scope` and
26
+ * nowhere else: one slide cannot restyle another slide, the chrome, or the
27
+ * editor around it.
28
+ *
29
+ * `:root`, `html` and `body` are rewritten to the scope itself rather than
30
+ * dropped — a body that declares its own custom properties on `:root` is
31
+ * doing the right thing, and it should land on the box it owns.
32
+ */
33
+ export declare function scopeWebCss(css: string, scope: string): string;
34
+ /**
35
+ * The author's markup, rebuilt from a parsed tree with everything the body
36
+ * may not have removed. Browser only (it needs a parser); the lint above is
37
+ * what runs everywhere else.
38
+ *
39
+ * This is a *correctness* boundary rather than a security one — a tier-A
40
+ * body has no scripts by construction, so there is nothing to contain. Its
41
+ * job is to stop a confused model from breaking the page around it.
42
+ *
43
+ * `text` fills the elements the body marked `data-edit="text.…"`: the copy
44
+ * lives in the deck, so editing a line is a write to `props.text` and the
45
+ * markup never has to be rewritten.
46
+ */
47
+ export declare function sanitizeWebHtml(html: string, text?: Record<string, string>): string;
@@ -0,0 +1,12 @@
1
+ export type NumberStyle = 'plain' | 'compact' | 'percent';
2
+ export interface NumberFormatOptions {
3
+ style?: NumberStyle;
4
+ /** Fraction digits. Defaults: plain 0, compact 1, percent auto (see below). */
5
+ decimals?: number;
6
+ }
7
+ /**
8
+ * plain: 1234567 → "1,234,567"
9
+ * compact: 1234567 → "1.2M" (k / M / B)
10
+ * percent: 0.423 → "42%" (input is a fraction)
11
+ */
12
+ export declare function formatNumber(value: number, opts?: NumberFormatOptions): string;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The platform surface an installed theme pack builds against (ui.md A9).
3
+ *
4
+ * A compiled-in set under src/sets/ imports whatever it likes by relative
5
+ * path. A pack cannot: it is built separately, ships as one prebuilt ESM
6
+ * file, and has to keep working against a later app. So the things a theme
7
+ * may reach for are enumerated here, and this module *is* the ABI — adding
8
+ * to it is a minor `PLATFORM_ABI` bump, removing from it a major one.
9
+ *
10
+ * Pack code imports it as `@folienbaukasten/platform`; tools/pack-set.ts
11
+ * rewrites that specifier to a shim reading the live objects off
12
+ * `globalThis` (src/sets/runtime.ts), because a pack cannot bundle its own
13
+ * React — two React copies in one page is two renderers, and the shared
14
+ * components below would be built by the wrong one.
15
+ *
16
+ * Everything here is *rendering* surface. Nothing gives a theme access to
17
+ * the project, the file system, or IPC — a theme styles slides.
18
+ */
19
+ export { Block } from '../components/Block';
20
+ export { BlockArrow } from '../components/BlockArrow';
21
+ export { Card } from '../components/Card';
22
+ export { ChartView } from '../components/ChartView';
23
+ export { DriverTree } from '../components/DriverTree';
24
+ export { FindingsBanner } from '../components/FindingsBanner';
25
+ export { HarveyBall, HARVEY_SIZE_PX, HARVEY_STROKE_PX } from '../components/HarveyBall';
26
+ export { headerTitle } from '../components/HeaderTitle';
27
+ export { InsightRail } from '../components/InsightRail';
28
+ export { KpiTile } from '../components/KpiTile';
29
+ export { Matrix } from '../components/Matrix';
30
+ export { QuoteColumn } from '../components/QuoteColumn';
31
+ export { SourceLine } from '../components/SourceLine';
32
+ export { Table } from '../components/Table';
33
+ export { Timeline } from '../components/Timeline';
34
+ export { ContentSlide } from '../components/slide/ContentSlide';
35
+ export { SlideFrame } from '../components/slide/SlideFrame';
36
+ export { platformDefaults } from '../components/slide/registry';
37
+ export { formatNumber } from '../lib/format';
38
+ export { SLIDE_HEIGHT, SLIDE_WIDTH } from '../deck/schema';
39
+ export { bandCentre, bandCentreX, bandCentreY, spreadLabels, valueY, LABEL_MIN_GAP, } from '../charts/geometry';
40
+ export type { ComponentSet, SetChrome, SlideView, SlideViewProps, LayoutName } from './types';
41
+ export type { NumberFormatOptions, NumberStyle } from '../lib/format';
42
+ export type * from '../deck/layouts';
43
+ export type { DeckMeta, HeaderSpec, SlideSpec } from '../deck/schema';
44
+ export type { PlotArea } from '../charts/geometry';
45
+ export type { ChartOrientation, ChartSeries, ChartSpec, ChartTone, ChartType, } from '../deck/schema';
@@ -0,0 +1,128 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { SharedSlide } from '../deck/layouts';
3
+ import type { DeckMeta, HeaderSpec, SlideSpec } from '../deck/schema';
4
+ /**
5
+ * A component set is a swappable *styling* layer: chrome, tokens, and
6
+ * optional per-layout view overrides. The layout vocabulary is the
7
+ * platform's (src/deck/layouts.ts) — sets own no layouts, so any deck
8
+ * renders under any set by construction. The PPTX/PDF export works for
9
+ * every set unchanged, because sets render into the platform's measured
10
+ * `data-pptx` primitives — that tagging contract is the platform ABI
11
+ * (see src/export/types.ts).
12
+ */
13
+ /** Every layout in the shared vocabulary. */
14
+ export type LayoutName = SharedSlide['layout'];
15
+ /** The chrome a set must supply: header and footer of every content slide.
16
+ * The frame, the bands and the overflow contract are platform-owned and not
17
+ * reachable from a set.
18
+ *
19
+ * The header receives `meta` as well as its own spec: deck-level marks —
20
+ * `meta.logoUrl` — belong to the document, not to a slide, and a header that
21
+ * had to be told the logo on every slide would be a layout prop pretending
22
+ * to be branding. A set with no place for one simply ignores it. */
23
+ export interface SetChrome {
24
+ Header: ComponentType<{
25
+ spec: HeaderSpec;
26
+ meta: DeckMeta;
27
+ }>;
28
+ Footer: ComponentType<{
29
+ meta: DeckMeta;
30
+ slideNumber: number;
31
+ }>;
32
+ }
33
+ /** Props every slide-layout component receives. */
34
+ export interface SlideViewProps<S extends SlideSpec = SlideSpec> {
35
+ slide: S;
36
+ meta: DeckMeta;
37
+ /** 1-based slide number, for footers. */
38
+ slideNumber: number;
39
+ /** The active set's chrome, passed through to `ContentSlide`. */
40
+ chrome: SetChrome;
41
+ /** Extension components reachable from this deck (`ResolvedSet.components`).
42
+ * Only the `component` layout reads it; optional so a view is renderable
43
+ * without it. */
44
+ components?: SetComponents;
45
+ }
46
+ /** A component that renders one layout. */
47
+ export type SlideView = ComponentType<SlideViewProps<any>>;
48
+ /**
49
+ * An extension-supplied slide body: hosted by the platform's `component` layout in the
50
+ * bounded body region. It owns a box, never the slide — the chrome bands
51
+ * and the overflow contract are not reachable from it. A component that
52
+ * renders measurable `data-pptx` primitives works in both modes; one that
53
+ * is interactive, animated or canvas-drawn declares `webOnly` and only
54
+ * validates in a Web Mode deck.
55
+ */
56
+ export interface SetComponentDef {
57
+ component: ComponentType<{
58
+ props: unknown;
59
+ }>;
60
+ /** Needs the Web Mode validation profile. Default false. */
61
+ webOnly?: boolean;
62
+ }
63
+ /** Extension components by namespaced kind ("acme/pricing-sheet"). */
64
+ export type SetComponents = Record<string, SetComponentDef>;
65
+ export interface ComponentSet {
66
+ /** Folder name under src/sets/ — referenced by deck meta.componentSet. */
67
+ id: string;
68
+ /** Human-readable name. */
69
+ name: string;
70
+ /**
71
+ * One line for the theme chooser: what this theme is for, in the register
72
+ * a user picks by ("what a partner presents to a board"), not in tokens.
73
+ */
74
+ description?: string;
75
+ /**
76
+ * A theme we offer to users. Sets without it are regression fixtures —
77
+ * they still render every deck, they are just not something anyone should
78
+ * be *choosing* (BUGS.md, production vs fixture separation). The catalog
79
+ * generator carries this through so the chooser and the theme panel can
80
+ * filter on it.
81
+ */
82
+ production?: boolean;
83
+ /**
84
+ * Header/footer chrome rendered by the platform's ContentSlide.
85
+ *
86
+ * Optional for exactly one shape of pack: a components-only extension
87
+ * (`provides: ['components']`), which ships slide
88
+ * bodies and no styling layer. Such a set is never a deck's theme — the
89
+ * loader imports it only through `loadExtensionComponents` — so nothing
90
+ * ever asks it for a header. A set that *is* a theme has chrome, and
91
+ * `ThemeSet` is the type that says so.
92
+ */
93
+ chrome?: SetChrome;
94
+ /** Layout views this set renders itself; the rest come from the platform
95
+ * (src/components/slide/registry.ts). May not add layouts. */
96
+ overrides?: Partial<Record<LayoutName, SlideView>>;
97
+ /**
98
+ * Slide components this set ships for the `component` layout, keyed by
99
+ * namespaced kind. A separate registry from `overrides`, because a
100
+ * component is not a slide view — it fills a body region the platform
101
+ * hands it.
102
+ */
103
+ components?: SetComponents;
104
+ /**
105
+ * The theme keeps every HTML ↔ PPTX rule (AGENTS.md) and is safe for
106
+ * PowerPoint-mode decks. Default true. A web-only theme sets false and is
107
+ * offered only to Web Mode decks.
108
+ */
109
+ pptxSafe?: boolean;
110
+ }
111
+ /**
112
+ * A set that can dress a deck: a `ComponentSet` that actually has chrome.
113
+ * Every compiled-in set is one, and so is every pack that provides a theme.
114
+ * Requiring it at the door of `resolveSet` is what keeps the optionality on
115
+ * `ComponentSet.chrome` confined to the components-only case that needs it.
116
+ */
117
+ export type ThemeSet = ComponentSet & {
118
+ chrome: SetChrome;
119
+ };
120
+ /** A set with its registry resolved: platform defaults + the set's
121
+ * overrides, and the extension components reachable from this deck (the
122
+ * set's own plus every installed components pack). What the renderer and
123
+ * export paths consume. */
124
+ export interface ResolvedSet extends ComponentSet {
125
+ chrome: SetChrome;
126
+ registry: Record<string, SlideView>;
127
+ components: SetComponents;
128
+ }