@particle-academy/dark-slide 0.6.2 → 0.7.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/dist/index.d.cts CHANGED
@@ -3,7 +3,9 @@
3
3
  * agent JSON, so most fields are optional and extra keys are tolerated; the
4
4
  * Validator is the gate.
5
5
  */
6
- type ElementType = "text" | "image" | "chart" | "code" | "table" | "shape" | "embed";
6
+ type ElementType = "text" | "image" | "chart" | "code" | "table" | "shape" | "embed"
7
+ /** Composites — expand into a `table` before the writer sees them. */
8
+ | "kpiBand" | "metadataGrid";
7
9
  interface ThemeColors {
8
10
  background?: string;
9
11
  text?: string;
@@ -76,8 +78,11 @@ interface SlideElement {
76
78
  columns?: {
77
79
  key: string;
78
80
  label: string;
81
+ width?: number;
82
+ align?: string;
79
83
  }[];
80
84
  rows?: Record<string, unknown>[];
85
+ items?: Record<string, unknown>[];
81
86
  option?: Record<string, unknown>;
82
87
  chartTheme?: string;
83
88
  image?: string;
@@ -215,7 +220,14 @@ declare class Repairer {
215
220
  */
216
221
  declare const Schema: {
217
222
  VERSION: string;
218
- ELEMENT_TYPES: readonly ["text", "image", "chart", "code", "table", "shape", "embed"];
223
+ /**
224
+ * `kpiBand` and `metadataGrid` are COMPOSITES: they expand into a `table`
225
+ * before the writer serialises anything, so they add no OOXML surface and
226
+ * read back as the table they became. See table/composites.
227
+ */
228
+ ELEMENT_TYPES: readonly ["text", "image", "chart", "code", "table", "shape", "embed", "kpiBand", "metadataGrid"];
229
+ /** The subset of ELEMENT_TYPES that is sugar over a `table`. */
230
+ COMPOSITE_ELEMENT_TYPES: readonly ["kpiBand", "metadataGrid"];
219
231
  SLIDE_LAYOUTS: readonly ["blank", "title", "title-content", "two-column", "section-divider", "image-text", "text-image", "quote"];
220
232
  SHAPE_KINDS: readonly ["rect", "rounded-rect", "ellipse", "triangle", "line", "arrow"];
221
233
  TEXT_FORMATS: readonly ["markdown", "html", "plain"];
@@ -250,7 +262,24 @@ declare class PptxWriter {
250
262
  private mediaFiles;
251
263
  /** Ordered list of chart part XML queued for the archive. */
252
264
  private chartFiles;
265
+ /** Extension uri under which the deck's mono typeface is recorded in theme1.xml. */
266
+ static readonly MONO_FONT_EXT_URI = "urn:particle-academy:dark-slide:mono-font";
267
+ /** Namespace for DarkSlide's own elements inside an `<a:ext>`. */
268
+ static readonly NS_DARK_SLIDE = "urn:particle-academy:dark-slide";
253
269
  private themeAccent;
270
+ /** The deck's theme, kept whole so the table resolver can read its colours. */
271
+ private deckTheme;
272
+ /**
273
+ * Monospace typeface for code runs, from `theme.fonts.mono`.
274
+ *
275
+ * There is no third slot in OOXML's `<a:fontScheme>` — a theme carries a
276
+ * major and a minor font and nothing else — so unlike heading and body this
277
+ * cannot ride along in theme1.xml and has to be written onto each code run.
278
+ * That is why it was missed in all three engines: accepted by every
279
+ * validator, published in the JSON Schema handed to an LLM as the tool
280
+ * definition, named in the writers' own docblocks, and applied nowhere.
281
+ */
282
+ private themeMono;
254
283
  private tnId;
255
284
  private pendingSlideRels;
256
285
  constructor(tempDir?: string | null, allowHttpImages?: boolean);
@@ -304,7 +333,22 @@ declare class PptxWriter {
304
333
  private buildCodeShape;
305
334
  private buildHighlightedCodeBody;
306
335
  private buildTable;
336
+ /**
337
+ * Serialise one resolved cell. Makes no styling decisions — every value here
338
+ * was decided by the resolver.
339
+ *
340
+ * Three things in here are load-bearing and easy to get wrong:
341
+ *
342
+ * - `gridSpan` / `rowSpan` / `hMerge` / `vMerge` are attributes of
343
+ * `<a:tc>`, NOT of `<a:tcPr>`. On `tcPr` they parse fine and are silently
344
+ * ignored, so the table renders unmerged with no error anywhere.
345
+ * - `<a:tcPr>` has a FIXED child order: lnL, lnR, lnT, lnB, then the fill.
346
+ * Emitting the fill first produces a file whose fill a reader drops.
347
+ * - "No border" is STATED. An absent `<a:lnL>` is an UNSPECIFIED rule, not
348
+ * an absent one, and a reader supplies its own.
349
+ */
307
350
  private buildTableCell;
351
+ private buildCellRun;
308
352
  private buildChart;
309
353
  private chartPreRenderSrc;
310
354
  private buildChartFrame;
@@ -326,6 +370,28 @@ declare class PptxWriter {
326
370
  private buildPlaceholder;
327
371
  private buildTextBody;
328
372
  private buildRun;
373
+ /**
374
+ * `<a:lnSpc>` / `<a:spcBef>` / `<a:spcAft>` for a paragraph.
375
+ *
376
+ * `lineHeight` is a MULTIPLE (1.4 = 140%), matching CSS and the fancy-slides
377
+ * editor; `spaceBefore` / `spaceAfter` are points. Empty when the style is
378
+ * silent, so decks that predate this keep their bytes.
379
+ */
380
+ private paragraphSpacing;
381
+ /**
382
+ * The bullet markup for a list paragraph.
383
+ *
384
+ * `none` suppresses it, `number` makes an auto-numbered list, and anything
385
+ * else is taken as the literal character — which is all a check-mark list is.
386
+ * The default stays the round bullet the writer has always emitted.
387
+ */
388
+ private bulletMarkup;
389
+ /**
390
+ * Run attributes that apply to every run in the body: letter spacing and
391
+ * capitalisation. Both are `<a:rPr>` attributes, so they have to be built as
392
+ * a string and appended rather than nested.
393
+ */
394
+ private runExtraAttrs;
329
395
  private weightToBold;
330
396
  private alignToAlgn;
331
397
  private xfrmFromFractions;
@@ -344,10 +410,25 @@ declare class PptxWriter {
344
410
  */
345
411
  declare class PptxReader {
346
412
  private currentSlideRels;
413
+ /**
414
+ * The mono typeface this deck was written with, read back from the theme's
415
+ * `<a:extLst>`. Empty when the package does not record one — anything not
416
+ * written by a current DarkSlide — in which case the name sniff below is the
417
+ * only signal available.
418
+ */
419
+ private monoTypeface;
347
420
  private parts;
348
421
  /** Read a PPTX file's bytes into a Deck schema object. */
349
422
  read(bytes: Uint8Array): Record<string, unknown>;
350
423
  fromBytes(bytes: Uint8Array): Record<string, unknown>;
424
+ /**
425
+ * The mono typeface recorded in `theme1.xml`'s `<a:extLst>`, or `""`.
426
+ *
427
+ * Deliberately a regex rather than a parse: this runs before the deck is
428
+ * built, the element is one attribute deep, and a theme part that does not
429
+ * carry the extension is the common case rather than an error.
430
+ */
431
+ private readMonoTypeface;
351
432
  private getPart;
352
433
  private extract;
353
434
  private parseSlideRels;
package/dist/index.d.ts CHANGED
@@ -3,7 +3,9 @@
3
3
  * agent JSON, so most fields are optional and extra keys are tolerated; the
4
4
  * Validator is the gate.
5
5
  */
6
- type ElementType = "text" | "image" | "chart" | "code" | "table" | "shape" | "embed";
6
+ type ElementType = "text" | "image" | "chart" | "code" | "table" | "shape" | "embed"
7
+ /** Composites — expand into a `table` before the writer sees them. */
8
+ | "kpiBand" | "metadataGrid";
7
9
  interface ThemeColors {
8
10
  background?: string;
9
11
  text?: string;
@@ -76,8 +78,11 @@ interface SlideElement {
76
78
  columns?: {
77
79
  key: string;
78
80
  label: string;
81
+ width?: number;
82
+ align?: string;
79
83
  }[];
80
84
  rows?: Record<string, unknown>[];
85
+ items?: Record<string, unknown>[];
81
86
  option?: Record<string, unknown>;
82
87
  chartTheme?: string;
83
88
  image?: string;
@@ -215,7 +220,14 @@ declare class Repairer {
215
220
  */
216
221
  declare const Schema: {
217
222
  VERSION: string;
218
- ELEMENT_TYPES: readonly ["text", "image", "chart", "code", "table", "shape", "embed"];
223
+ /**
224
+ * `kpiBand` and `metadataGrid` are COMPOSITES: they expand into a `table`
225
+ * before the writer serialises anything, so they add no OOXML surface and
226
+ * read back as the table they became. See table/composites.
227
+ */
228
+ ELEMENT_TYPES: readonly ["text", "image", "chart", "code", "table", "shape", "embed", "kpiBand", "metadataGrid"];
229
+ /** The subset of ELEMENT_TYPES that is sugar over a `table`. */
230
+ COMPOSITE_ELEMENT_TYPES: readonly ["kpiBand", "metadataGrid"];
219
231
  SLIDE_LAYOUTS: readonly ["blank", "title", "title-content", "two-column", "section-divider", "image-text", "text-image", "quote"];
220
232
  SHAPE_KINDS: readonly ["rect", "rounded-rect", "ellipse", "triangle", "line", "arrow"];
221
233
  TEXT_FORMATS: readonly ["markdown", "html", "plain"];
@@ -250,7 +262,24 @@ declare class PptxWriter {
250
262
  private mediaFiles;
251
263
  /** Ordered list of chart part XML queued for the archive. */
252
264
  private chartFiles;
265
+ /** Extension uri under which the deck's mono typeface is recorded in theme1.xml. */
266
+ static readonly MONO_FONT_EXT_URI = "urn:particle-academy:dark-slide:mono-font";
267
+ /** Namespace for DarkSlide's own elements inside an `<a:ext>`. */
268
+ static readonly NS_DARK_SLIDE = "urn:particle-academy:dark-slide";
253
269
  private themeAccent;
270
+ /** The deck's theme, kept whole so the table resolver can read its colours. */
271
+ private deckTheme;
272
+ /**
273
+ * Monospace typeface for code runs, from `theme.fonts.mono`.
274
+ *
275
+ * There is no third slot in OOXML's `<a:fontScheme>` — a theme carries a
276
+ * major and a minor font and nothing else — so unlike heading and body this
277
+ * cannot ride along in theme1.xml and has to be written onto each code run.
278
+ * That is why it was missed in all three engines: accepted by every
279
+ * validator, published in the JSON Schema handed to an LLM as the tool
280
+ * definition, named in the writers' own docblocks, and applied nowhere.
281
+ */
282
+ private themeMono;
254
283
  private tnId;
255
284
  private pendingSlideRels;
256
285
  constructor(tempDir?: string | null, allowHttpImages?: boolean);
@@ -304,7 +333,22 @@ declare class PptxWriter {
304
333
  private buildCodeShape;
305
334
  private buildHighlightedCodeBody;
306
335
  private buildTable;
336
+ /**
337
+ * Serialise one resolved cell. Makes no styling decisions — every value here
338
+ * was decided by the resolver.
339
+ *
340
+ * Three things in here are load-bearing and easy to get wrong:
341
+ *
342
+ * - `gridSpan` / `rowSpan` / `hMerge` / `vMerge` are attributes of
343
+ * `<a:tc>`, NOT of `<a:tcPr>`. On `tcPr` they parse fine and are silently
344
+ * ignored, so the table renders unmerged with no error anywhere.
345
+ * - `<a:tcPr>` has a FIXED child order: lnL, lnR, lnT, lnB, then the fill.
346
+ * Emitting the fill first produces a file whose fill a reader drops.
347
+ * - "No border" is STATED. An absent `<a:lnL>` is an UNSPECIFIED rule, not
348
+ * an absent one, and a reader supplies its own.
349
+ */
307
350
  private buildTableCell;
351
+ private buildCellRun;
308
352
  private buildChart;
309
353
  private chartPreRenderSrc;
310
354
  private buildChartFrame;
@@ -326,6 +370,28 @@ declare class PptxWriter {
326
370
  private buildPlaceholder;
327
371
  private buildTextBody;
328
372
  private buildRun;
373
+ /**
374
+ * `<a:lnSpc>` / `<a:spcBef>` / `<a:spcAft>` for a paragraph.
375
+ *
376
+ * `lineHeight` is a MULTIPLE (1.4 = 140%), matching CSS and the fancy-slides
377
+ * editor; `spaceBefore` / `spaceAfter` are points. Empty when the style is
378
+ * silent, so decks that predate this keep their bytes.
379
+ */
380
+ private paragraphSpacing;
381
+ /**
382
+ * The bullet markup for a list paragraph.
383
+ *
384
+ * `none` suppresses it, `number` makes an auto-numbered list, and anything
385
+ * else is taken as the literal character — which is all a check-mark list is.
386
+ * The default stays the round bullet the writer has always emitted.
387
+ */
388
+ private bulletMarkup;
389
+ /**
390
+ * Run attributes that apply to every run in the body: letter spacing and
391
+ * capitalisation. Both are `<a:rPr>` attributes, so they have to be built as
392
+ * a string and appended rather than nested.
393
+ */
394
+ private runExtraAttrs;
329
395
  private weightToBold;
330
396
  private alignToAlgn;
331
397
  private xfrmFromFractions;
@@ -344,10 +410,25 @@ declare class PptxWriter {
344
410
  */
345
411
  declare class PptxReader {
346
412
  private currentSlideRels;
413
+ /**
414
+ * The mono typeface this deck was written with, read back from the theme's
415
+ * `<a:extLst>`. Empty when the package does not record one — anything not
416
+ * written by a current DarkSlide — in which case the name sniff below is the
417
+ * only signal available.
418
+ */
419
+ private monoTypeface;
347
420
  private parts;
348
421
  /** Read a PPTX file's bytes into a Deck schema object. */
349
422
  read(bytes: Uint8Array): Record<string, unknown>;
350
423
  fromBytes(bytes: Uint8Array): Record<string, unknown>;
424
+ /**
425
+ * The mono typeface recorded in `theme1.xml`'s `<a:extLst>`, or `""`.
426
+ *
427
+ * Deliberately a regex rather than a parse: this runs before the deck is
428
+ * built, the element is one attribute deep, and a theme part that does not
429
+ * carry the extension is the common case rather than an error.
430
+ */
431
+ private readMonoTypeface;
351
432
  private getPart;
352
433
  private extract;
353
434
  private parseSlideRels;