mulmocast 2.20.0 → 2.21.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.
@@ -13320,6 +13320,175 @@
13320
13320
  "items"
13321
13321
  ],
13322
13322
  "additionalProperties": false
13323
+ },
13324
+ {
13325
+ "type": "object",
13326
+ "properties": {
13327
+ "layout": {
13328
+ "type": "string",
13329
+ "const": "figure"
13330
+ },
13331
+ "accentColor": {
13332
+ "type": "string",
13333
+ "enum": [
13334
+ "primary",
13335
+ "accent",
13336
+ "success",
13337
+ "warning",
13338
+ "danger",
13339
+ "info",
13340
+ "highlight"
13341
+ ]
13342
+ },
13343
+ "style": {
13344
+ "type": "object",
13345
+ "properties": {
13346
+ "bgColor": {
13347
+ "type": "string"
13348
+ },
13349
+ "bgGradient": {
13350
+ "type": "string"
13351
+ },
13352
+ "decorations": {
13353
+ "type": "boolean"
13354
+ },
13355
+ "bgOpacity": {
13356
+ "type": "number"
13357
+ },
13358
+ "footer": {
13359
+ "type": "string"
13360
+ }
13361
+ },
13362
+ "additionalProperties": false
13363
+ },
13364
+ "eyebrow": {
13365
+ "type": "object",
13366
+ "properties": {
13367
+ "label": {
13368
+ "type": "string"
13369
+ },
13370
+ "color": {
13371
+ "type": "string",
13372
+ "enum": [
13373
+ "primary",
13374
+ "accent",
13375
+ "success",
13376
+ "warning",
13377
+ "danger",
13378
+ "info",
13379
+ "highlight"
13380
+ ]
13381
+ }
13382
+ },
13383
+ "required": [
13384
+ "label"
13385
+ ],
13386
+ "additionalProperties": false
13387
+ },
13388
+ "density": {
13389
+ "type": "string",
13390
+ "enum": [
13391
+ "compact",
13392
+ "default"
13393
+ ]
13394
+ },
13395
+ "titleSize": {
13396
+ "type": "string",
13397
+ "enum": [
13398
+ "small",
13399
+ "default",
13400
+ "large",
13401
+ "hero"
13402
+ ]
13403
+ },
13404
+ "subtitleSize": {
13405
+ "type": "string",
13406
+ "enum": [
13407
+ "default",
13408
+ "big",
13409
+ "lead"
13410
+ ]
13411
+ },
13412
+ "intro": {
13413
+ "type": "string",
13414
+ "enum": [
13415
+ "fade",
13416
+ "fade-up",
13417
+ "fade-down",
13418
+ "slide-left",
13419
+ "slide-right",
13420
+ "zoom-in"
13421
+ ]
13422
+ },
13423
+ "staggerMs": {
13424
+ "type": "integer",
13425
+ "minimum": 0,
13426
+ "maximum": 2000
13427
+ },
13428
+ "title": {
13429
+ "type": "string"
13430
+ },
13431
+ "stepLabel": {
13432
+ "type": "string"
13433
+ },
13434
+ "subtitle": {
13435
+ "type": "string"
13436
+ },
13437
+ "figure": {
13438
+ "oneOf": [
13439
+ {
13440
+ "type": "object",
13441
+ "properties": {
13442
+ "type": {
13443
+ "type": "string",
13444
+ "const": "chart"
13445
+ },
13446
+ "chartData": {
13447
+ "type": "object",
13448
+ "propertyNames": {
13449
+ "type": "string"
13450
+ },
13451
+ "additionalProperties": {}
13452
+ },
13453
+ "title": {
13454
+ "type": "string"
13455
+ }
13456
+ },
13457
+ "required": [
13458
+ "type",
13459
+ "chartData"
13460
+ ],
13461
+ "additionalProperties": false
13462
+ },
13463
+ {
13464
+ "type": "object",
13465
+ "properties": {
13466
+ "type": {
13467
+ "type": "string",
13468
+ "const": "mermaid"
13469
+ },
13470
+ "code": {
13471
+ "type": "string"
13472
+ },
13473
+ "title": {
13474
+ "type": "string"
13475
+ }
13476
+ },
13477
+ "required": [
13478
+ "type",
13479
+ "code"
13480
+ ],
13481
+ "additionalProperties": false
13482
+ }
13483
+ ]
13484
+ }
13485
+ },
13486
+ "required": [
13487
+ "layout",
13488
+ "title",
13489
+ "figure"
13490
+ ],
13491
+ "additionalProperties": false
13323
13492
  }
13324
13493
  ]
13325
13494
  },
@@ -4207,6 +4207,72 @@ export declare const mulmoImageAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
4207
4207
  }>>;
4208
4208
  staggerMs: z.ZodOptional<z.ZodNumber>;
4209
4209
  layout: z.ZodLiteral<"manifesto">;
4210
+ }, z.core.$strip>, z.ZodObject<{
4211
+ title: z.ZodString;
4212
+ stepLabel: z.ZodOptional<z.ZodString>;
4213
+ subtitle: z.ZodOptional<z.ZodString>;
4214
+ figure: z.ZodDiscriminatedUnion<[z.ZodObject<{
4215
+ type: z.ZodLiteral<"chart">;
4216
+ chartData: z.ZodRecord<z.ZodString, z.ZodUnknown>;
4217
+ title: z.ZodOptional<z.ZodString>;
4218
+ }, z.core.$strip>, z.ZodObject<{
4219
+ type: z.ZodLiteral<"mermaid">;
4220
+ code: z.ZodString;
4221
+ title: z.ZodOptional<z.ZodString>;
4222
+ }, z.core.$strip>], "type">;
4223
+ accentColor: z.ZodOptional<z.ZodEnum<{
4224
+ primary: "primary";
4225
+ accent: "accent";
4226
+ success: "success";
4227
+ warning: "warning";
4228
+ danger: "danger";
4229
+ info: "info";
4230
+ highlight: "highlight";
4231
+ }>>;
4232
+ style: z.ZodOptional<z.ZodObject<{
4233
+ bgColor: z.ZodOptional<z.ZodString>;
4234
+ bgGradient: z.ZodOptional<z.ZodString>;
4235
+ decorations: z.ZodOptional<z.ZodBoolean>;
4236
+ bgOpacity: z.ZodOptional<z.ZodNumber>;
4237
+ footer: z.ZodOptional<z.ZodString>;
4238
+ }, z.core.$strip>>;
4239
+ eyebrow: z.ZodOptional<z.ZodObject<{
4240
+ label: z.ZodString;
4241
+ color: z.ZodOptional<z.ZodEnum<{
4242
+ primary: "primary";
4243
+ accent: "accent";
4244
+ success: "success";
4245
+ warning: "warning";
4246
+ danger: "danger";
4247
+ info: "info";
4248
+ highlight: "highlight";
4249
+ }>>;
4250
+ }, z.core.$strip>>;
4251
+ density: z.ZodOptional<z.ZodEnum<{
4252
+ default: "default";
4253
+ compact: "compact";
4254
+ }>>;
4255
+ titleSize: z.ZodOptional<z.ZodEnum<{
4256
+ default: "default";
4257
+ small: "small";
4258
+ large: "large";
4259
+ hero: "hero";
4260
+ }>>;
4261
+ subtitleSize: z.ZodOptional<z.ZodEnum<{
4262
+ lead: "lead";
4263
+ big: "big";
4264
+ default: "default";
4265
+ }>>;
4266
+ intro: z.ZodOptional<z.ZodEnum<{
4267
+ fade: "fade";
4268
+ "fade-up": "fade-up";
4269
+ "fade-down": "fade-down";
4270
+ "slide-left": "slide-left";
4271
+ "slide-right": "slide-right";
4272
+ "zoom-in": "zoom-in";
4273
+ }>>;
4274
+ staggerMs: z.ZodOptional<z.ZodNumber>;
4275
+ layout: z.ZodLiteral<"figure">;
4210
4276
  }, z.core.$strip>], "layout">;
4211
4277
  reference: z.ZodOptional<z.ZodString>;
4212
4278
  branding: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -8644,6 +8710,72 @@ export declare const mulmoBeatSchema: z.ZodObject<{
8644
8710
  }>>;
8645
8711
  staggerMs: z.ZodOptional<z.ZodNumber>;
8646
8712
  layout: z.ZodLiteral<"manifesto">;
8713
+ }, z.core.$strip>, z.ZodObject<{
8714
+ title: z.ZodString;
8715
+ stepLabel: z.ZodOptional<z.ZodString>;
8716
+ subtitle: z.ZodOptional<z.ZodString>;
8717
+ figure: z.ZodDiscriminatedUnion<[z.ZodObject<{
8718
+ type: z.ZodLiteral<"chart">;
8719
+ chartData: z.ZodRecord<z.ZodString, z.ZodUnknown>;
8720
+ title: z.ZodOptional<z.ZodString>;
8721
+ }, z.core.$strip>, z.ZodObject<{
8722
+ type: z.ZodLiteral<"mermaid">;
8723
+ code: z.ZodString;
8724
+ title: z.ZodOptional<z.ZodString>;
8725
+ }, z.core.$strip>], "type">;
8726
+ accentColor: z.ZodOptional<z.ZodEnum<{
8727
+ primary: "primary";
8728
+ accent: "accent";
8729
+ success: "success";
8730
+ warning: "warning";
8731
+ danger: "danger";
8732
+ info: "info";
8733
+ highlight: "highlight";
8734
+ }>>;
8735
+ style: z.ZodOptional<z.ZodObject<{
8736
+ bgColor: z.ZodOptional<z.ZodString>;
8737
+ bgGradient: z.ZodOptional<z.ZodString>;
8738
+ decorations: z.ZodOptional<z.ZodBoolean>;
8739
+ bgOpacity: z.ZodOptional<z.ZodNumber>;
8740
+ footer: z.ZodOptional<z.ZodString>;
8741
+ }, z.core.$strip>>;
8742
+ eyebrow: z.ZodOptional<z.ZodObject<{
8743
+ label: z.ZodString;
8744
+ color: z.ZodOptional<z.ZodEnum<{
8745
+ primary: "primary";
8746
+ accent: "accent";
8747
+ success: "success";
8748
+ warning: "warning";
8749
+ danger: "danger";
8750
+ info: "info";
8751
+ highlight: "highlight";
8752
+ }>>;
8753
+ }, z.core.$strip>>;
8754
+ density: z.ZodOptional<z.ZodEnum<{
8755
+ default: "default";
8756
+ compact: "compact";
8757
+ }>>;
8758
+ titleSize: z.ZodOptional<z.ZodEnum<{
8759
+ default: "default";
8760
+ small: "small";
8761
+ large: "large";
8762
+ hero: "hero";
8763
+ }>>;
8764
+ subtitleSize: z.ZodOptional<z.ZodEnum<{
8765
+ lead: "lead";
8766
+ big: "big";
8767
+ default: "default";
8768
+ }>>;
8769
+ intro: z.ZodOptional<z.ZodEnum<{
8770
+ fade: "fade";
8771
+ "fade-up": "fade-up";
8772
+ "fade-down": "fade-down";
8773
+ "slide-left": "slide-left";
8774
+ "slide-right": "slide-right";
8775
+ "zoom-in": "zoom-in";
8776
+ }>>;
8777
+ staggerMs: z.ZodOptional<z.ZodNumber>;
8778
+ layout: z.ZodLiteral<"figure">;
8647
8779
  }, z.core.$strip>], "layout">;
8648
8780
  reference: z.ZodOptional<z.ZodString>;
8649
8781
  branding: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -13927,6 +14059,72 @@ export declare const mulmoScriptSchema: z.ZodObject<{
13927
14059
  }>>;
13928
14060
  staggerMs: z.ZodOptional<z.ZodNumber>;
13929
14061
  layout: z.ZodLiteral<"manifesto">;
14062
+ }, z.core.$strip>, z.ZodObject<{
14063
+ title: z.ZodString;
14064
+ stepLabel: z.ZodOptional<z.ZodString>;
14065
+ subtitle: z.ZodOptional<z.ZodString>;
14066
+ figure: z.ZodDiscriminatedUnion<[z.ZodObject<{
14067
+ type: z.ZodLiteral<"chart">;
14068
+ chartData: z.ZodRecord<z.ZodString, z.ZodUnknown>;
14069
+ title: z.ZodOptional<z.ZodString>;
14070
+ }, z.core.$strip>, z.ZodObject<{
14071
+ type: z.ZodLiteral<"mermaid">;
14072
+ code: z.ZodString;
14073
+ title: z.ZodOptional<z.ZodString>;
14074
+ }, z.core.$strip>], "type">;
14075
+ accentColor: z.ZodOptional<z.ZodEnum<{
14076
+ primary: "primary";
14077
+ accent: "accent";
14078
+ success: "success";
14079
+ warning: "warning";
14080
+ danger: "danger";
14081
+ info: "info";
14082
+ highlight: "highlight";
14083
+ }>>;
14084
+ style: z.ZodOptional<z.ZodObject<{
14085
+ bgColor: z.ZodOptional<z.ZodString>;
14086
+ bgGradient: z.ZodOptional<z.ZodString>;
14087
+ decorations: z.ZodOptional<z.ZodBoolean>;
14088
+ bgOpacity: z.ZodOptional<z.ZodNumber>;
14089
+ footer: z.ZodOptional<z.ZodString>;
14090
+ }, z.core.$strip>>;
14091
+ eyebrow: z.ZodOptional<z.ZodObject<{
14092
+ label: z.ZodString;
14093
+ color: z.ZodOptional<z.ZodEnum<{
14094
+ primary: "primary";
14095
+ accent: "accent";
14096
+ success: "success";
14097
+ warning: "warning";
14098
+ danger: "danger";
14099
+ info: "info";
14100
+ highlight: "highlight";
14101
+ }>>;
14102
+ }, z.core.$strip>>;
14103
+ density: z.ZodOptional<z.ZodEnum<{
14104
+ default: "default";
14105
+ compact: "compact";
14106
+ }>>;
14107
+ titleSize: z.ZodOptional<z.ZodEnum<{
14108
+ default: "default";
14109
+ small: "small";
14110
+ large: "large";
14111
+ hero: "hero";
14112
+ }>>;
14113
+ subtitleSize: z.ZodOptional<z.ZodEnum<{
14114
+ lead: "lead";
14115
+ big: "big";
14116
+ default: "default";
14117
+ }>>;
14118
+ intro: z.ZodOptional<z.ZodEnum<{
14119
+ fade: "fade";
14120
+ "fade-up": "fade-up";
14121
+ "fade-down": "fade-down";
14122
+ "slide-left": "slide-left";
14123
+ "slide-right": "slide-right";
14124
+ "zoom-in": "zoom-in";
14125
+ }>>;
14126
+ staggerMs: z.ZodOptional<z.ZodNumber>;
14127
+ layout: z.ZodLiteral<"figure">;
13930
14128
  }, z.core.$strip>], "layout">;
13931
14129
  reference: z.ZodOptional<z.ZodString>;
13932
14130
  branding: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -18734,6 +18932,72 @@ export declare const mulmoStudioSchema: z.ZodObject<{
18734
18932
  }>>;
18735
18933
  staggerMs: z.ZodOptional<z.ZodNumber>;
18736
18934
  layout: z.ZodLiteral<"manifesto">;
18935
+ }, z.core.$strip>, z.ZodObject<{
18936
+ title: z.ZodString;
18937
+ stepLabel: z.ZodOptional<z.ZodString>;
18938
+ subtitle: z.ZodOptional<z.ZodString>;
18939
+ figure: z.ZodDiscriminatedUnion<[z.ZodObject<{
18940
+ type: z.ZodLiteral<"chart">;
18941
+ chartData: z.ZodRecord<z.ZodString, z.ZodUnknown>;
18942
+ title: z.ZodOptional<z.ZodString>;
18943
+ }, z.core.$strip>, z.ZodObject<{
18944
+ type: z.ZodLiteral<"mermaid">;
18945
+ code: z.ZodString;
18946
+ title: z.ZodOptional<z.ZodString>;
18947
+ }, z.core.$strip>], "type">;
18948
+ accentColor: z.ZodOptional<z.ZodEnum<{
18949
+ primary: "primary";
18950
+ accent: "accent";
18951
+ success: "success";
18952
+ warning: "warning";
18953
+ danger: "danger";
18954
+ info: "info";
18955
+ highlight: "highlight";
18956
+ }>>;
18957
+ style: z.ZodOptional<z.ZodObject<{
18958
+ bgColor: z.ZodOptional<z.ZodString>;
18959
+ bgGradient: z.ZodOptional<z.ZodString>;
18960
+ decorations: z.ZodOptional<z.ZodBoolean>;
18961
+ bgOpacity: z.ZodOptional<z.ZodNumber>;
18962
+ footer: z.ZodOptional<z.ZodString>;
18963
+ }, z.core.$strip>>;
18964
+ eyebrow: z.ZodOptional<z.ZodObject<{
18965
+ label: z.ZodString;
18966
+ color: z.ZodOptional<z.ZodEnum<{
18967
+ primary: "primary";
18968
+ accent: "accent";
18969
+ success: "success";
18970
+ warning: "warning";
18971
+ danger: "danger";
18972
+ info: "info";
18973
+ highlight: "highlight";
18974
+ }>>;
18975
+ }, z.core.$strip>>;
18976
+ density: z.ZodOptional<z.ZodEnum<{
18977
+ default: "default";
18978
+ compact: "compact";
18979
+ }>>;
18980
+ titleSize: z.ZodOptional<z.ZodEnum<{
18981
+ default: "default";
18982
+ small: "small";
18983
+ large: "large";
18984
+ hero: "hero";
18985
+ }>>;
18986
+ subtitleSize: z.ZodOptional<z.ZodEnum<{
18987
+ lead: "lead";
18988
+ big: "big";
18989
+ default: "default";
18990
+ }>>;
18991
+ intro: z.ZodOptional<z.ZodEnum<{
18992
+ fade: "fade";
18993
+ "fade-up": "fade-up";
18994
+ "fade-down": "fade-down";
18995
+ "slide-left": "slide-left";
18996
+ "slide-right": "slide-right";
18997
+ "zoom-in": "zoom-in";
18998
+ }>>;
18999
+ staggerMs: z.ZodOptional<z.ZodNumber>;
19000
+ layout: z.ZodLiteral<"figure">;
18737
19001
  }, z.core.$strip>], "layout">;
18738
19002
  reference: z.ZodOptional<z.ZodString>;
18739
19003
  branding: z.ZodOptional<z.ZodNullable<z.ZodObject<{
@@ -1,15 +1,11 @@
1
1
  import type { MulmoChartMedia } from "../../types/index.js";
2
- import type { BeatHtmlFragment } from "./type.js";
2
+ import type { BeatHtmlFragment, BeatHtmlOptions } from "./type.js";
3
3
  /**
4
- * A chart beat as markup a host can inject.
4
+ * A chart beat as a deck `figure` slide, so it shares the `slide` beat's theme and its one
5
+ * host code path: `slideUtilityCss`, and the `[data-mulmo-chart]` canvas driven from the
6
+ * attribute rather than from an inline `<script>`, which neither runs through `innerHTML`
7
+ * nor survives sanitizing.
5
8
  *
6
- * The config rides on the canvas as `data-mulmo-chart` rather than in an inline `<script>`:
7
- * a script injected through `innerHTML` does not execute, and does not survive sanitizing
8
- * either. The attribute shape matches `@mulmocast/deck`'s, so a host that already drives
9
- * `[data-mulmo-chart]` for slides drives this too without a second code path.
10
- *
11
- * The markup itself comes from `image_plugins/chart_html.ts`, the same module the Node
12
- * render path uses — a second copy of it would drift, and the two paths have to draw the
13
- * same chart.
9
+ * The PNG path still draws from its own template, so the browser and the PNG differ in look.
14
10
  */
15
- export declare const chartToHtml: (image: MulmoChartMedia, idPrefix: string) => BeatHtmlFragment;
11
+ export declare const chartToHtml: (image: MulmoChartMedia, options: BeatHtmlOptions) => BeatHtmlFragment;
@@ -1,21 +1,10 @@
1
- import { chartFragmentHtml, chartPluginCdns, chartTypeOf } from "../image_plugins/chart_html.js";
1
+ import { deckSlideToHtml } from "./slide.js";
2
2
  /**
3
- * A chart beat as markup a host can inject.
3
+ * A chart beat as a deck `figure` slide, so it shares the `slide` beat's theme and its one
4
+ * host code path: `slideUtilityCss`, and the `[data-mulmo-chart]` canvas driven from the
5
+ * attribute rather than from an inline `<script>`, which neither runs through `innerHTML`
6
+ * nor survives sanitizing.
4
7
  *
5
- * The config rides on the canvas as `data-mulmo-chart` rather than in an inline `<script>`:
6
- * a script injected through `innerHTML` does not execute, and does not survive sanitizing
7
- * either. The attribute shape matches `@mulmocast/deck`'s, so a host that already drives
8
- * `[data-mulmo-chart]` for slides drives this too without a second code path.
9
- *
10
- * The markup itself comes from `image_plugins/chart_html.ts`, the same module the Node
11
- * render path uses — a second copy of it would drift, and the two paths have to draw the
12
- * same chart.
8
+ * The PNG path still draws from its own template, so the browser and the PNG differ in look.
13
9
  */
14
- export const chartToHtml = (image, idPrefix) => {
15
- const plugins = chartPluginCdns(chartTypeOf(image.chartData));
16
- return {
17
- html: chartFragmentHtml(image.chartData, image.title, `${idPrefix}-chart`),
18
- requires: ["chart"],
19
- ...(plugins.length > 0 ? { chartPlugins: plugins } : {}),
20
- };
21
- };
10
+ export const chartToHtml = (image, options) => deckSlideToHtml({ layout: "figure", title: image.title, figure: { type: "chart", chartData: image.chartData } }, undefined, options);
@@ -46,9 +46,9 @@ export const beatToHtml = (beat, options) => {
46
46
  case "markdown":
47
47
  return markdownToHtml(image, options.idPrefix);
48
48
  case "chart":
49
- return chartToHtml(image, options.idPrefix);
49
+ return chartToHtml(image, options);
50
50
  case "mermaid":
51
- return mermaidToHtml(image, options.idPrefix);
51
+ return mermaidToHtml(image, options);
52
52
  case "image":
53
53
  // The only description of the picture this module can reach. A host with more should
54
54
  // set its own alt; an <img> with none makes a screen reader read the file name.
@@ -1,14 +1,11 @@
1
1
  import type { MulmoMermaidMedia } from "../../types/index.js";
2
- import type { BeatHtmlFragment } from "./type.js";
2
+ import type { BeatHtmlFragment, BeatHtmlOptions } from "./type.js";
3
3
  /**
4
- * A mermaid beat as markup a host can inject.
4
+ * A mermaid beat as a deck `figure` slide — see `chart.ts` for why deck draws it.
5
5
  *
6
6
  * Only `code.kind === "text"` renders. The other kinds — `url`, `path`, `base64` — are
7
7
  * resolved by `MulmoMediaSourceMethods.getText`, which fetches and reads files, so they
8
8
  * cannot be reached from here and `beatToHtml` returns undefined rather than inventing a
9
9
  * placeholder. `mermaid.ts`'s own markdown dump already draws the same line.
10
- *
11
- * The markup comes from `image_plugins/mermaid_html.ts`, the module the Node render path
12
- * uses, so the browser and the PNG draw the same diagram.
13
10
  */
14
- export declare const mermaidToHtml: (image: MulmoMermaidMedia, idPrefix: string) => BeatHtmlFragment | undefined;
11
+ export declare const mermaidToHtml: (image: MulmoMermaidMedia, options: BeatHtmlOptions) => BeatHtmlFragment | undefined;
@@ -1,22 +1,16 @@
1
- import { mermaidHtml } from "../image_plugins/mermaid_html.js";
1
+ import { deckSlideToHtml } from "./slide.js";
2
2
  /**
3
- * A mermaid beat as markup a host can inject.
3
+ * A mermaid beat as a deck `figure` slide — see `chart.ts` for why deck draws it.
4
4
  *
5
5
  * Only `code.kind === "text"` renders. The other kinds — `url`, `path`, `base64` — are
6
6
  * resolved by `MulmoMediaSourceMethods.getText`, which fetches and reads files, so they
7
7
  * cannot be reached from here and `beatToHtml` returns undefined rather than inventing a
8
8
  * placeholder. `mermaid.ts`'s own markdown dump already draws the same line.
9
- *
10
- * The markup comes from `image_plugins/mermaid_html.ts`, the module the Node render path
11
- * uses, so the browser and the PNG draw the same diagram.
12
9
  */
13
- export const mermaidToHtml = (image, idPrefix) => {
10
+ export const mermaidToHtml = (image, options) => {
14
11
  if (image.code.kind !== "text")
15
12
  return undefined;
16
13
  const appendix = image.appendix?.join("\n") ?? "";
17
14
  const code = `${image.code.text}\n${appendix}`.trim();
18
- return {
19
- html: mermaidHtml(code, `${idPrefix}-mermaid`, image.title || "Diagram"),
20
- requires: ["mermaid"],
21
- };
15
+ return deckSlideToHtml({ layout: "figure", title: image.title || "Diagram", figure: { type: "mermaid", code } }, undefined, options);
22
16
  };
@@ -1,7 +1,8 @@
1
- import type { MulmoSlideMedia } from "@mulmocast/deck";
1
+ import type { MulmoSlideMedia, SlideLayout, SlideTheme } from "@mulmocast/deck";
2
2
  import type { BeatHtmlFragment, BeatHtmlOptions } from "./type.js";
3
3
  /**
4
- * A slide beat as markup a host can inject.
4
+ * A deck slide as markup a host can inject. Shared by the beat types deck draws: `slide`,
5
+ * and `chart` / `mermaid` as a one-block `figure` slide.
5
6
  *
6
7
  * `generateSlideFragment` is the body-only counterpart of the `generateSlideHTML` the Node
7
8
  * render path uses, so the two draw the same slide from the same layouts — the fragment is
@@ -13,9 +14,10 @@ import type { BeatHtmlFragment, BeatHtmlOptions } from "./type.js";
13
14
  * which the browser bundle does not need.
14
15
  *
15
16
  * The scope class is derived from `idPrefix` so a re-render of the same beat keeps it: the
16
- * css is written against that class and a generated one would change every render, leaving
17
- * the rules matching nothing. It is not returned separately — deck already puts it on the
18
- * root of `html`, verified in a browser: injecting `html` and attaching `css`, with no
19
- * wrapper class of the host's own, resolves `--d-bg` to the beat's theme.
17
+ * css is written against that class, and deck derives chart / mermaid ids from it, so a
18
+ * generated one would change every render. It is not returned separately — deck already puts
19
+ * it on the root of `html`, verified in a browser: injecting `html` and attaching `css`, with
20
+ * no wrapper class of the host's own, resolves `--d-bg` to the beat's theme.
20
21
  */
22
+ export declare const deckSlideToHtml: (slide: SlideLayout, beatTheme: SlideTheme | undefined, options: BeatHtmlOptions) => BeatHtmlFragment;
21
23
  export declare const slideToHtml: (image: MulmoSlideMedia, options: BeatHtmlOptions) => BeatHtmlFragment;
@@ -3,7 +3,8 @@
3
3
  import { generateSlideFragment } from "@mulmocast/deck/lib/fragment.js";
4
4
  import { slideThemes } from "../../data/slideThemes.js";
5
5
  /**
6
- * A slide beat as markup a host can inject.
6
+ * A deck slide as markup a host can inject. Shared by the beat types deck draws: `slide`,
7
+ * and `chart` / `mermaid` as a one-block `figure` slide.
7
8
  *
8
9
  * `generateSlideFragment` is the body-only counterpart of the `generateSlideHTML` the Node
9
10
  * render path uses, so the two draw the same slide from the same layouts — the fragment is
@@ -15,14 +16,14 @@ import { slideThemes } from "../../data/slideThemes.js";
15
16
  * which the browser bundle does not need.
16
17
  *
17
18
  * The scope class is derived from `idPrefix` so a re-render of the same beat keeps it: the
18
- * css is written against that class and a generated one would change every render, leaving
19
- * the rules matching nothing. It is not returned separately — deck already puts it on the
20
- * root of `html`, verified in a browser: injecting `html` and attaching `css`, with no
21
- * wrapper class of the host's own, resolves `--d-bg` to the beat's theme.
19
+ * css is written against that class, and deck derives chart / mermaid ids from it, so a
20
+ * generated one would change every render. It is not returned separately — deck already puts
21
+ * it on the root of `html`, verified in a browser: injecting `html` and attaching `css`, with
22
+ * no wrapper class of the host's own, resolves `--d-bg` to the beat's theme.
22
23
  */
23
- export const slideToHtml = (image, options) => {
24
- const theme = image.theme ?? options.slideTheme ?? slideThemes.corporate;
25
- const fragment = generateSlideFragment(theme, image.slide, { scopeClass: `${options.idPrefix}-slide` });
24
+ export const deckSlideToHtml = (slide, beatTheme, options) => {
25
+ const theme = beatTheme ?? options.slideTheme ?? slideThemes.corporate;
26
+ const fragment = generateSlideFragment(theme, slide, { scopeClass: `${options.idPrefix}-slide` });
26
27
  return {
27
28
  html: fragment.html,
28
29
  css: fragment.css,
@@ -31,3 +32,4 @@ export const slideToHtml = (image, options) => {
31
32
  ...(fragment.mermaidTheme ? { mermaidTheme: fragment.mermaidTheme } : {}),
32
33
  };
33
34
  };
35
+ export const slideToHtml = (image, options) => deckSlideToHtml(image.slide, image.theme, options);
@@ -69,11 +69,12 @@ export type BeatHtmlOptions = {
69
69
  */
70
70
  idPrefix: string;
71
71
  /**
72
- * The deck-level slide theme, for `slide` beats. A beat's own `image.theme` wins over it,
73
- * and the built-in `corporate` theme is the fallback — the same order
72
+ * The deck-level slide theme, for the beats deck draws: `slide`, `chart` and `mermaid`.
73
+ * A slide beat's own `image.theme` wins over it, and the built-in `corporate` theme is the
74
+ * fallback — the same order
74
75
  * `MulmoPresentationStyleMethods.getResolvedSlideTheme` uses on the Node side.
75
76
  *
76
- * Optional because only slide beats read it, and because the host may not have a deck
77
+ * Optional because only those beats read it, and because the host may not have a deck
77
78
  * theme to give.
78
79
  */
79
80
  slideTheme?: SlideTheme;
@@ -2132,6 +2132,37 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
2132
2132
  subtitleSize?: "default" | "big" | "lead" | undefined;
2133
2133
  intro?: "fade" | "fade-up" | "fade-down" | "slide-left" | "slide-right" | "zoom-in" | undefined;
2134
2134
  staggerMs?: number | undefined;
2135
+ } | {
2136
+ title: string;
2137
+ figure: {
2138
+ type: "chart";
2139
+ chartData: Record<string, unknown>;
2140
+ title?: string | undefined;
2141
+ } | {
2142
+ type: "mermaid";
2143
+ code: string;
2144
+ title?: string | undefined;
2145
+ };
2146
+ layout: "figure";
2147
+ stepLabel?: string | undefined;
2148
+ subtitle?: string | undefined;
2149
+ accentColor?: "success" | "info" | "primary" | "accent" | "warning" | "danger" | "highlight" | undefined;
2150
+ style?: {
2151
+ bgColor?: string | undefined;
2152
+ bgGradient?: string | undefined;
2153
+ decorations?: boolean | undefined;
2154
+ bgOpacity?: number | undefined;
2155
+ footer?: string | undefined;
2156
+ } | undefined;
2157
+ eyebrow?: {
2158
+ label: string;
2159
+ color?: "success" | "info" | "primary" | "accent" | "warning" | "danger" | "highlight" | undefined;
2160
+ } | undefined;
2161
+ density?: "default" | "compact" | undefined;
2162
+ titleSize?: "default" | "small" | "large" | "hero" | undefined;
2163
+ subtitleSize?: "default" | "big" | "lead" | undefined;
2164
+ intro?: "fade" | "fade-up" | "fade-down" | "slide-left" | "slide-right" | "zoom-in" | undefined;
2165
+ staggerMs?: number | undefined;
2135
2166
  };
2136
2167
  theme?: {
2137
2168
  colors: {
@@ -4787,6 +4818,37 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
4787
4818
  subtitleSize?: "default" | "big" | "lead" | undefined;
4788
4819
  intro?: "fade" | "fade-up" | "fade-down" | "slide-left" | "slide-right" | "zoom-in" | undefined;
4789
4820
  staggerMs?: number | undefined;
4821
+ } | {
4822
+ title: string;
4823
+ figure: {
4824
+ type: "chart";
4825
+ chartData: Record<string, unknown>;
4826
+ title?: string | undefined;
4827
+ } | {
4828
+ type: "mermaid";
4829
+ code: string;
4830
+ title?: string | undefined;
4831
+ };
4832
+ layout: "figure";
4833
+ stepLabel?: string | undefined;
4834
+ subtitle?: string | undefined;
4835
+ accentColor?: "success" | "info" | "primary" | "accent" | "warning" | "danger" | "highlight" | undefined;
4836
+ style?: {
4837
+ bgColor?: string | undefined;
4838
+ bgGradient?: string | undefined;
4839
+ decorations?: boolean | undefined;
4840
+ bgOpacity?: number | undefined;
4841
+ footer?: string | undefined;
4842
+ } | undefined;
4843
+ eyebrow?: {
4844
+ label: string;
4845
+ color?: "success" | "info" | "primary" | "accent" | "warning" | "danger" | "highlight" | undefined;
4846
+ } | undefined;
4847
+ density?: "default" | "compact" | undefined;
4848
+ titleSize?: "default" | "small" | "large" | "hero" | undefined;
4849
+ subtitleSize?: "default" | "big" | "lead" | undefined;
4850
+ intro?: "fade" | "fade-up" | "fade-down" | "slide-left" | "slide-right" | "zoom-in" | undefined;
4851
+ staggerMs?: number | undefined;
4790
4852
  };
4791
4853
  theme?: {
4792
4854
  colors: {
@@ -4,16 +4,6 @@ export declare const resolveChartPlugins: (chartType: string) => string;
4
4
  export declare const stringifyChartData: (chartData: MulmoChartMedia["chartData"]) => string;
5
5
  /** For a standalone document, where the inline script runs. */
6
6
  export declare const chartHtml: (chartDataJson: string, title: string, chartId: string) => string;
7
- /**
8
- * For a host that injects the markup into its own page, where an injected `<script>`
9
- * neither survives sanitizing nor executes via innerHTML. The config rides on the canvas
10
- * instead, in the shape `@mulmocast/deck` already uses so one host runtime drives both.
11
- */
12
- export declare const chartFragmentHtml: (chartData: MulmoChartMedia["chartData"], title: string, chartId: string) => string;
13
- /** `chartData` is a free record, so the type may be absent or not a string. */
14
- export declare const chartTypeOf: (chartData: MulmoChartMedia["chartData"]) => string;
15
- /** The Chart.js plugin CDNs a chart type needs, for a host that loads them once per page. */
16
- export declare const chartPluginCdns: (chartType: string) => string[];
17
7
  /**
18
8
  * The two values the PNG/PDF/movie template interpolates from user data, escaped for the
19
9
  * contexts it drops them into: `<h1>${title}</h1>` and `const chartData = ${chart_data};`.
@@ -1,17 +1,12 @@
1
1
  // Deep import: the package barrel pulls in every layout and all of zod, which measured
2
- // 551kb against 1.5kb for this file, and the browser fragment path bundles this module.
2
+ // 551kb against 1.5kb for this file.
3
3
  import { escapeHtml } from "@mulmocast/deck/lib/utils.js";
4
4
  import { escapeJsonForScript } from "../html_escape.js";
5
5
  import { assertSafeElementId } from "../element_id.js";
6
6
  /**
7
- * Chart.js markup and plugin resolution. Pure — no Node, no filesystem — because both the
8
- * Node render path and the browser fragment path draw the same chart and must draw it the
9
- * same way.
10
- *
11
- * The canvas id is a parameter rather than generated here: the Node path renders once to a
12
- * PNG so a random id is fine, while the browser path re-renders and needs the same beat to
13
- * produce the same markup, or a host diffing fragments sees every chart change identity on
14
- * every render.
7
+ * Chart.js markup and plugin resolution for the Node render path. Pure — no Node, no
8
+ * filesystem — so it can be tested without either. The browser path draws charts through
9
+ * `@mulmocast/deck` instead (`beat_html/chart.ts`).
15
10
  */
16
11
  /**
17
12
  * Chart.js plugin CDN URLs keyed by chart type. A Map rather than an object literal: the
@@ -30,8 +25,7 @@ export const resolveChartPlugins = (chartType) => {
30
25
  return `<script src="${cdn}"></script>`;
31
26
  };
32
27
  export const stringifyChartData = (chartData) => JSON.stringify(chartData, null, 2);
33
- /** The card both paths draw: a heading and a fixed-height canvas. `trailing` is where the
34
- * document path puts its driver script; the fragment path leaves it empty. */
28
+ /** A heading and a fixed-height canvas, followed by `trailing` — the driver script. */
35
29
  const chartCard = (title, canvas, trailing) => `
36
30
  <div class="chart-container mb-6">
37
31
  <h3 class="text-xl font-semibold mb-4">${escapeHtml(title || "Chart")}</h3>
@@ -51,26 +45,6 @@ export const chartHtml = (chartDataJson, title, chartId) => {
51
45
  </script>`;
52
46
  return chartCard(title, `<canvas id="${chartId}"></canvas>`, script);
53
47
  };
54
- /**
55
- * For a host that injects the markup into its own page, where an injected `<script>`
56
- * neither survives sanitizing nor executes via innerHTML. The config rides on the canvas
57
- * instead, in the shape `@mulmocast/deck` already uses so one host runtime drives both.
58
- */
59
- export const chartFragmentHtml = (chartData, title, chartId) => {
60
- assertSafeElementId(chartId);
61
- const config = escapeHtml(JSON.stringify(chartData));
62
- return chartCard(title, `<canvas id="${chartId}" data-chart-ready="false" data-mulmo-chart="${config}"></canvas>`, "");
63
- };
64
- /** `chartData` is a free record, so the type may be absent or not a string. */
65
- export const chartTypeOf = (chartData) => {
66
- const type = chartData?.type;
67
- return typeof type === "string" ? type : "";
68
- };
69
- /** The Chart.js plugin CDNs a chart type needs, for a host that loads them once per page. */
70
- export const chartPluginCdns = (chartType) => {
71
- const cdn = CHART_PLUGIN_CDNS.get(chartType);
72
- return cdn ? [cdn] : [];
73
- };
74
48
  /**
75
49
  * The two values the PNG/PDF/movie template interpolates from user data, escaped for the
76
50
  * contexts it drops them into: `<h1>${title}</h1>` and `const chartData = ${chart_data};`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "2.20.0",
3
+ "version": "2.21.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",
@@ -114,7 +114,7 @@
114
114
  "@modelcontextprotocol/sdk": "^1.32.1",
115
115
  "@modernized/fluent-ffmpeg": "^1.0.3",
116
116
  "@mozilla/readability": "^0.6.0",
117
- "@mulmocast/deck": "^2.0.2",
117
+ "@mulmocast/deck": "^2.1.0",
118
118
  "@tavily/core": "^0.7.14",
119
119
  "archiver": "^8.0.0",
120
120
  "clipboardy": "^5.3.2",