@datatechsolutions/tympan-tokens 0.4.2 → 0.5.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 (80) hide show
  1. package/THIRD_PARTY_NOTICES.md +5 -5
  2. package/dist/fonts.css +80 -80
  3. package/dist/index.d.ts +229 -55
  4. package/dist/index.js +359 -16
  5. package/dist/index.js.map +1 -1
  6. package/dist/print-themes/print-aquarela.css +7 -7
  7. package/dist/print-themes/print-art-nouveau.css +2 -2
  8. package/dist/print-themes/print-atlas-oficial.css +7 -7
  9. package/dist/print-themes/print-azulejo-modernista.css +2 -2
  10. package/dist/print-themes/print-bauhaus.css +2 -2
  11. package/dist/print-themes/print-blocos-coloridos.css +5 -5
  12. package/dist/print-themes/print-brutalista.css +8 -8
  13. package/dist/print-themes/print-caderno.css +14 -14
  14. package/dist/print-themes/print-cartao-postal.css +5 -5
  15. package/dist/print-themes/print-cientifico.css +3 -3
  16. package/dist/print-themes/print-concretismo.css +8 -8
  17. package/dist/print-themes/print-construtivismo.css +6 -6
  18. package/dist/print-themes/print-cordel.css +6 -6
  19. package/dist/print-themes/print-dados-br.css +12 -12
  20. package/dist/print-themes/print-dashboard.css +18 -18
  21. package/dist/print-themes/print-diagrama-modernista.css +3 -3
  22. package/dist/print-themes/print-divulgacao.css +3 -3
  23. package/dist/print-themes/print-fluxo-historico.css +3 -3
  24. package/dist/print-themes/print-grade-holandesa.css +2 -2
  25. package/dist/print-themes/print-graficos-1900.css +6 -6
  26. package/dist/print-themes/print-infografico-ilustrado.css +6 -6
  27. package/dist/print-themes/print-isotype.css +2 -2
  28. package/dist/print-themes/print-jornal-1959.css +5 -5
  29. package/dist/print-themes/print-jornal.css +6 -6
  30. package/dist/print-themes/print-mapa-de-metro.css +1 -1
  31. package/dist/print-themes/print-memphis.css +5 -5
  32. package/dist/print-themes/print-minimo-de-tinta.css +4 -4
  33. package/dist/print-themes/print-papel-recortado.css +2 -2
  34. package/dist/print-themes/print-papel-salmao.css +6 -6
  35. package/dist/print-themes/print-pictogramas.css +2 -2
  36. package/dist/print-themes/print-pop-art.css +2 -2
  37. package/dist/print-themes/print-prancheta-clara.css +5 -5
  38. package/dist/print-themes/print-prancheta.css +5 -5
  39. package/dist/print-themes/print-proporcao-modular.css +2 -2
  40. package/dist/print-themes/print-riso.css +4 -4
  41. package/dist/print-themes/print-semanario.css +13 -13
  42. package/dist/print-themes/print-sinalizacao.css +8 -8
  43. package/dist/print-themes/print-suico.css +4 -4
  44. package/dist/print-themes/print-tropicalia.css +3 -3
  45. package/dist/print-themes.css +133 -133
  46. package/fonts/ibmplexsans/ibmplexsans-italic-cyrillic-400_500_600.woff2 +0 -0
  47. package/fonts/ibmplexsans/ibmplexsans-italic-cyrillic-ext-400_500_600.woff2 +0 -0
  48. package/fonts/ibmplexsans/ibmplexsans-italic-greek-400_500_600.woff2 +0 -0
  49. package/fonts/ibmplexsans/ibmplexsans-italic-latin-400_500_600.woff2 +0 -0
  50. package/fonts/ibmplexsans/ibmplexsans-italic-latin-ext-400_500_600.woff2 +0 -0
  51. package/fonts/ibmplexsans/ibmplexsans-italic-vietnamese-400_500_600.woff2 +0 -0
  52. package/fonts/manifest.json +998 -820
  53. package/fonts/nunitosans/nunitosans-normal-cyrillic-400_600_700_800.woff2 +0 -0
  54. package/fonts/nunitosans/nunitosans-normal-cyrillic-ext-400_600_700_800.woff2 +0 -0
  55. package/fonts/nunitosans/nunitosans-normal-latin-400_600_700_800.woff2 +0 -0
  56. package/fonts/nunitosans/nunitosans-normal-latin-ext-400_600_700_800.woff2 +0 -0
  57. package/fonts/nunitosans/nunitosans-normal-vietnamese-400_600_700_800.woff2 +0 -0
  58. package/fonts/sourceserif4/sourceserif4-italic-cyrillic-400_600.woff2 +0 -0
  59. package/fonts/sourceserif4/sourceserif4-italic-cyrillic-ext-400_600.woff2 +0 -0
  60. package/fonts/sourceserif4/sourceserif4-italic-greek-400_600.woff2 +0 -0
  61. package/fonts/sourceserif4/sourceserif4-italic-latin-400_600.woff2 +0 -0
  62. package/fonts/sourceserif4/sourceserif4-italic-latin-ext-400_600.woff2 +0 -0
  63. package/fonts/sourceserif4/sourceserif4-italic-vietnamese-400_600.woff2 +0 -0
  64. package/package.json +1 -1
  65. package/src/fonts.ts +2 -2
  66. package/src/index.ts +1 -0
  67. package/src/print-book-themes.ts +239 -0
  68. package/src/print-presets.ts +220 -10
  69. /package/fonts/ibmplexsans/{ibmplexsans-italic-cyrillic.woff2 → ibmplexsans-italic-cyrillic-400.woff2} +0 -0
  70. /package/fonts/ibmplexsans/{ibmplexsans-italic-cyrillic-ext.woff2 → ibmplexsans-italic-cyrillic-ext-400.woff2} +0 -0
  71. /package/fonts/ibmplexsans/{ibmplexsans-italic-greek.woff2 → ibmplexsans-italic-greek-400.woff2} +0 -0
  72. /package/fonts/ibmplexsans/{ibmplexsans-italic-latin.woff2 → ibmplexsans-italic-latin-400.woff2} +0 -0
  73. /package/fonts/ibmplexsans/{ibmplexsans-italic-latin-ext.woff2 → ibmplexsans-italic-latin-ext-400.woff2} +0 -0
  74. /package/fonts/ibmplexsans/{ibmplexsans-italic-vietnamese.woff2 → ibmplexsans-italic-vietnamese-400.woff2} +0 -0
  75. /package/fonts/sourceserif4/{sourceserif4-italic-cyrillic.woff2 → sourceserif4-italic-cyrillic-400.woff2} +0 -0
  76. /package/fonts/sourceserif4/{sourceserif4-italic-cyrillic-ext.woff2 → sourceserif4-italic-cyrillic-ext-400.woff2} +0 -0
  77. /package/fonts/sourceserif4/{sourceserif4-italic-greek.woff2 → sourceserif4-italic-greek-400.woff2} +0 -0
  78. /package/fonts/sourceserif4/{sourceserif4-italic-latin.woff2 → sourceserif4-italic-latin-400.woff2} +0 -0
  79. /package/fonts/sourceserif4/{sourceserif4-italic-latin-ext.woff2 → sourceserif4-italic-latin-ext-400.woff2} +0 -0
  80. /package/fonts/sourceserif4/{sourceserif4-italic-vietnamese.woff2 → sourceserif4-italic-vietnamese-400.woff2} +0 -0
package/dist/index.js CHANGED
@@ -1767,7 +1767,16 @@ const ESTADOS_PROVA = [
1767
1767
  "sem-dado",
1768
1768
  "nao-testada"
1769
1769
  ];
1770
- /** The word printed for each proof state (always visible, whatever the mark's shape). */
1770
+ /** The word printed for each proof state in English (tympan-print picks by the book's `lang`). */
1771
+ const ROTULOS_PROVA_EN = {
1772
+ sustentada: "Supported",
1773
+ refutada: "Refuted",
1774
+ "nao-da-para-afirmar": "Cannot claim",
1775
+ pendente: "Pending",
1776
+ "sem-dado": "No data",
1777
+ "nao-testada": "Not tested"
1778
+ };
1779
+ /** The word printed for each proof state (always visible, whatever the mark's shape); pt-BR. */
1771
1780
  const ROTULOS_PROVA = {
1772
1781
  sustentada: "Sustentada",
1773
1782
  refutada: "Refutada",
@@ -1805,8 +1814,8 @@ const dashboard = {
1805
1814
  tinta2: "#3d3933",
1806
1815
  tinta3: "#5f594f",
1807
1816
  linha: "#d6cfc2",
1808
- destaque: "#1c1a17",
1809
- destaque2: "#9a4f2a",
1817
+ destaque: "#9a4f2a",
1818
+ destaque2: "#c4b8a8",
1810
1819
  marcaTexto: "#f3e6cf",
1811
1820
  contexto: "#8f877a",
1812
1821
  prova: {
@@ -1838,7 +1847,8 @@ const dashboard = {
1838
1847
  rotuloCaixa: "alta",
1839
1848
  notas: "dentro",
1840
1849
  figura: "simples",
1841
- minusculas: false
1850
+ minusculas: false,
1851
+ preencher: true
1842
1852
  }
1843
1853
  };
1844
1854
  const graficos1900 = {
@@ -4249,15 +4259,56 @@ function mergeCores(base, over) {
4249
4259
  if (!over) return base;
4250
4260
  const { prova, ...rest } = over;
4251
4261
  const clean = Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== void 0));
4262
+ const temas = base.temas || clean.temas ? { temas: {
4263
+ ...base.temas,
4264
+ ...clean.temas
4265
+ } } : {};
4266
+ const categorias = base.categorias || clean.categorias ? { categorias: {
4267
+ ...base.categorias,
4268
+ ...clean.categorias
4269
+ } } : {};
4252
4270
  return {
4253
4271
  ...base,
4254
4272
  ...clean,
4273
+ ...temas,
4274
+ ...categorias,
4255
4275
  prova: {
4256
4276
  ...base.prova,
4257
4277
  ...prova ?? {}
4258
4278
  }
4259
4279
  };
4260
4280
  }
4281
+ function mergeExtras(base, over) {
4282
+ const out = {};
4283
+ const marcas = {
4284
+ ...base.marcas,
4285
+ ...over.marcas
4286
+ };
4287
+ if (Object.keys(marcas).length) out.marcas = marcas;
4288
+ const pagina = {
4289
+ ...base.pagina,
4290
+ ...over.pagina
4291
+ };
4292
+ if (Object.keys(pagina).length) out.pagina = pagina;
4293
+ const folio = {
4294
+ ...base.folio,
4295
+ ...over.folio
4296
+ };
4297
+ if (Object.keys(folio).length) out.folio = folio;
4298
+ const fl = over.fontesLocais ?? base.fontesLocais;
4299
+ if (fl) out.fontesLocais = fl;
4300
+ const rs = {
4301
+ ...base.rastro,
4302
+ ...over.rastro
4303
+ };
4304
+ if (Object.keys(rs).length) out.rastro = rs;
4305
+ const tx = {
4306
+ ...base.textos,
4307
+ ...over.textos
4308
+ };
4309
+ if (Object.keys(tx).length) out.textos = tx;
4310
+ return out;
4311
+ }
4261
4312
  /** A style with the editor's overrides applied (nested, partial). */
4262
4313
  function mergePrintStyle(style, overrides) {
4263
4314
  if (!overrides) return style;
@@ -4282,19 +4333,24 @@ function mergePrintStyle(style, overrides) {
4282
4333
  marcaProva: overrides.marcaProva ?? style.marcaProva,
4283
4334
  raio: overrides.raio ?? style.raio,
4284
4335
  caixaAlta: overrides.caixaAlta ?? style.caixaAlta,
4285
- pb: overrides.pb ? mergeCores({
4286
- ...style.cor,
4336
+ pb: overrides.pb ? {
4287
4337
  ...style.pb,
4288
- prova: {
4289
- ...style.cor.prova,
4290
- ...style.pb.prova
4291
- }
4292
- }, overrides.pb) : style.pb,
4338
+ ...overrides.pb,
4339
+ ...style.pb.prova || overrides.pb.prova ? { prova: {
4340
+ ...style.pb.prova,
4341
+ ...overrides.pb.prova
4342
+ } } : {}
4343
+ } : style.pb,
4293
4344
  estrutura: {
4294
4345
  ...style.estrutura,
4295
4346
  ...overrides.estrutura
4296
4347
  },
4297
- logo: overrides.logo ?? style.logo
4348
+ logo: overrides.logo ?? style.logo,
4349
+ ...overrides.texto || style.texto ? { texto: {
4350
+ ...style.texto,
4351
+ ...overrides.texto
4352
+ } } : {},
4353
+ ...mergeExtras(style, overrides)
4298
4354
  };
4299
4355
  }
4300
4356
  const fromLinear = (c) => c <= .0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - .055;
@@ -4323,7 +4379,11 @@ function printStyleCoresPb(style) {
4323
4379
  marcaTexto: toGrey(g.marcaTexto),
4324
4380
  contexto: toGrey(g.contexto),
4325
4381
  prova: Object.fromEntries(ESTADOS_PROVA.map((e) => [e, toGrey(g.prova[e])])),
4326
- ...g.ornamento ? { ornamento: g.ornamento.map(toGrey) } : {}
4382
+ ...g.ornamento ? { ornamento: g.ornamento.map(toGrey) } : {},
4383
+ ...g.interesse ? { interesse: toGrey(g.interesse) } : {},
4384
+ ...g.temas ? { temas: Object.fromEntries(Object.entries(g.temas).map(([k, v]) => [k, toGrey(v)])) } : {},
4385
+ ...g.divergente ? { divergente: g.divergente.map(toGrey) } : {},
4386
+ categorica: categoricaDoEstilo(style).map(toGrey)
4327
4387
  }, style.pb);
4328
4388
  }
4329
4389
  /**
@@ -4351,6 +4411,62 @@ const kebab = {
4351
4411
  contexto: "contexto"
4352
4412
  };
4353
4413
  const num = (n) => String(Math.round(n * 1e3) / 1e3);
4414
+ /**
4415
+ * `cor` moved along OKLCH lightness (hue and chroma kept) until it reaches `min`:1 against `papel`: the
4416
+ * context grey of a theme stays visible on cream paper (areas ≥ 1.5:1, strokes ≥ 3:1).
4417
+ */
4418
+ function contrasteMinimo(cor, papel, min) {
4419
+ const p = parseColor(papel);
4420
+ if (contrastRatio(parseColor(cor), p) >= min) return toHex(parseColor(cor));
4421
+ const v = rgbToOklch(parseColor(cor));
4422
+ const passo = luminance(p) > .2 ? -.005 : .005;
4423
+ let out = parseColor(cor);
4424
+ for (let i = 0; i < 200 && contrastRatio(out, p) < min; i++) {
4425
+ v.l = Math.min(.995, Math.max(.02, v.l + passo));
4426
+ out = oklchToRgb(v);
4427
+ }
4428
+ return toHex(out);
4429
+ }
4430
+ const SELETORES_PAPEL = {
4431
+ titulo: ":is(h1, h2, h3, h4, .ty-print-title, .ty-print-figure-title, [class*=\"-title\"]:not(.ty-print-panel-title, .ty-print-block-title, .ty-print-margin-title))",
4432
+ numero: ":is(.ty-print-number-value, .ty-print-table td[data-numerica], .ty-print-parliament-total, [class*=\"-numero\"], [class*=\"-number\"])",
4433
+ rotulo: ":is(.ty-print-panel-title, .ty-print-block-title, .ty-print-margin-title, .ty-print-sobretitle, .ty-print-table th, .ty-print-map-legend, .ty-print-running-head, .ty-print-folio, .ty-print-letter)",
4434
+ corpo: "",
4435
+ anotacao: ":is(.ty-print-annotation, .ty-print-margin, .ty-print-callout-text)",
4436
+ mono: ":is(code, pre, .ty-print-mono, .ty-print-table td[data-mono])"
4437
+ };
4438
+ /**
4439
+ * Unlayered rules (they win over `@layer tympan-print`) for a theme's per-role font weights and figures,
4440
+ * scoped to `seletor`; '' when the theme sets neither.
4441
+ */
4442
+ function printTextoRolesCss(style, seletor) {
4443
+ const out = [];
4444
+ for (const [papel, peso] of Object.entries(style.texto?.pesos ?? {})) {
4445
+ const s = SELETORES_PAPEL[papel];
4446
+ out.push(`${seletor}${s ? ` ${s}` : ""} { font-weight: ${peso}; }`);
4447
+ }
4448
+ for (const [papel, a] of Object.entries(style.texto?.algarismos ?? {})) {
4449
+ const s = SELETORES_PAPEL[papel];
4450
+ out.push(`${seletor}${s ? ` ${s}` : ""} { font-variant-numeric: ${a === "tabular" ? "tabular-nums lining-nums" : "proportional-nums"}; }`);
4451
+ }
4452
+ return out.join("\n");
4453
+ }
4454
+ /** Qualitative palette (Okabe & Ito 2008, colour-blind safe) used when a style defines none. */
4455
+ const CATEGORICA_PADRAO = [
4456
+ "#0072b2",
4457
+ "#e69f00",
4458
+ "#009e73",
4459
+ "#cc79a7",
4460
+ "#56b4e9",
4461
+ "#d55e00",
4462
+ "#f0e442",
4463
+ "#555555"
4464
+ ];
4465
+ /** The eight qualitative data colours of a style: its own `categorica`, completed by CATEGORICA_PADRAO. */
4466
+ function categoricaDoEstilo(style) {
4467
+ const own = style.cor.categorica ?? [];
4468
+ return Array.from({ length: 8 }, (_, i) => own[i] ?? CATEGORICA_PADRAO[i]);
4469
+ }
4354
4470
  /** Custom properties of a resolved style, in a stable order. */
4355
4471
  function printStyleVariables(style) {
4356
4472
  const vars = [];
@@ -4375,6 +4491,21 @@ function printStyleVariables(style) {
4375
4491
  vars.push(["--ty-print-rotulo-caixa", minusculas ? "lowercase" : rc === "alta" ? "uppercase" : "none"]);
4376
4492
  vars.push(["--ty-print-rotulo-variante", rc === "versalete" ? "small-caps" : "normal"]);
4377
4493
  vars.push(["--ty-print-rotulo-espaco", rc === "normal" ? "normal" : "0.07em"]);
4494
+ vars.push(["--ty-print-pagina-largura", `${num(style.pagina?.largura ?? 170)}mm`]);
4495
+ vars.push(["--ty-print-pagina-altura", `${num(style.pagina?.altura ?? 240)}mm`]);
4496
+ const preservar = style.texto?.nomesProprios === "preservar";
4497
+ vars.push(["--ty-print-titulo1-caixa", preservar ? "none" : style.caixaAlta ? "uppercase" : minusculas ? "lowercase" : "none"]);
4498
+ vars.push(["--ty-print-sobretitulo-caixa", preservar ? "none" : minusculas ? "lowercase" : rc === "alta" ? "uppercase" : "none"]);
4499
+ vars.push(["--ty-print-celula-caixa", preservar ? "none" : minusculas ? "lowercase" : "none"]);
4500
+ vars.push(["--ty-print-tabela-numeros", style.texto?.numerosTabela === "proporcional" ? "proportional-nums lining-nums" : "tabular-nums lining-nums"]);
4501
+ for (const [k, v] of Object.entries(style.cor.temas ?? {})) vars.push([`--ty-print-tema-${k.replace(/[^a-z0-9-]/gi, "")}`, v]);
4502
+ vars.push(["--ty-print-interesse", style.cor.interesse ?? style.cor.destaque]);
4503
+ vars.push(["--ty-print-contexto-area", contrasteMinimo(style.cor.contexto, style.cor.papel, 1.5)]);
4504
+ vars.push(["--ty-print-contexto-traco", contrasteMinimo(style.cor.contexto, style.cor.papel, 3)]);
4505
+ const dv = style.cor.divergente ?? [style.cor.destaque2, style.cor.destaque];
4506
+ vars.push(["--ty-print-divergente-1", dv[0]]);
4507
+ vars.push(["--ty-print-divergente-2", dv[1]]);
4508
+ categoricaDoEstilo(style).forEach((c, i) => vars.push([`--ty-print-categorica-${i + 1}`, c]));
4378
4509
  const orn = style.cor.ornamento ?? [];
4379
4510
  const reserva = [
4380
4511
  style.cor.destaque,
@@ -5337,8 +5468,8 @@ function flowToneRules() {
5337
5468
  //#region src/fonts.ts
5338
5469
  /** Base stacks of every preset: Source Serif 4, IBM Plex Sans, IBM Plex Mono. */
5339
5470
  const BASE_FONT_SPECS = [
5340
- "Source Serif 4:ital,opsz,wght@0,8..60,400;0,8..60,600;0,8..60,700;1,8..60,400",
5341
- "IBM Plex Sans:ital,wght@0,400;0,500;0,600;0,700;1,400",
5471
+ "Source Serif 4:ital,opsz,wght@0,8..60,400;0,8..60,600;0,8..60,700;1,8..60,400;1,8..60,600",
5472
+ "IBM Plex Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600",
5342
5473
  "IBM Plex Mono:ital,wght@0,400;0,500;0,600;0,700;1,400"
5343
5474
  ];
5344
5475
  const NOTO_WEIGHTS = "wght@400;500;600;700";
@@ -5481,9 +5612,221 @@ function fontFaceCss(manifest, specs, base) {
5481
5612
  }).join("\n");
5482
5613
  }
5483
5614
  //#endregion
5615
+ //#region src/print-book-themes.ts
5616
+ const REGISTRO = /* @__PURE__ */ new Map();
5617
+ /** A style with overrides and theme extras applied (same as mergePrintStyle, kept for readability). */
5618
+ const mergePrintTheme = mergePrintStyle;
5619
+ /** Resolves a theme id or a preset id to a complete PrintStyle (`name` = the theme id). */
5620
+ function printThemeById(id, visitados = []) {
5621
+ const tema = REGISTRO.get(id);
5622
+ if (!tema) return printPresetById(id);
5623
+ if (visitados.includes(id)) throw new Error(`tympan: book theme cycle ${[...visitados, id].join(" → ")}`);
5624
+ const base = printThemeById(tema.base, [...visitados, id]);
5625
+ const { id: _id, base: _base, referencia, ...over } = tema;
5626
+ return {
5627
+ ...mergePrintTheme(base, over),
5628
+ name: tema.id,
5629
+ label: tema.label ?? base.label,
5630
+ referencia: referencia ?? `Tema sobre ${base.name}: ${base.referencia}`
5631
+ };
5632
+ }
5633
+ /** True when `id` names a registered theme or a preset. */
5634
+ function isPrintThemeId(id) {
5635
+ return REGISTRO.has(id) || resolvePrintStyleName(id) !== void 0;
5636
+ }
5637
+ function normalizarCores(c) {
5638
+ if (!c) return void 0;
5639
+ const cor = (v) => typeof v === "string" ? v : toHex(fromDtcgColor(v));
5640
+ const out = {};
5641
+ for (const [k, v] of Object.entries(c)) if ((k === "prova" || k === "temas" || k === "categorias") && v && typeof v === "object") out[k] = Object.fromEntries(Object.entries(v).map(([e, x]) => [e, cor(x)]));
5642
+ else if ((k === "ornamento" || k === "categorica" || k === "divergente") && Array.isArray(v)) out[k] = v.map(cor);
5643
+ else out[k] = cor(v);
5644
+ return out;
5645
+ }
5646
+ /** Validates and normalises a theme read from JSON (colours may be hex or DTCG colour objects). */
5647
+ function printThemeFromJson(json) {
5648
+ const j = typeof json === "string" ? JSON.parse(json) : json;
5649
+ if (!j || typeof j.id !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(j.id)) throw new Error("tympan: a book theme needs an `id` in kebab case");
5650
+ if (typeof j.base !== "string") throw new Error(`tympan: book theme "${j.id}" needs a \`base\` (a preset or a registered theme)`);
5651
+ const { cor, pb, ...rest } = j;
5652
+ const out = { ...rest };
5653
+ const c = normalizarCores(cor);
5654
+ if (c) out.cor = c;
5655
+ const p = normalizarCores(pb);
5656
+ if (p) out.pb = p;
5657
+ return out;
5658
+ }
5659
+ /** Namespaces read for the theme's meta (id/name, base/extends): tympan's own and the short one brand repos use. */
5660
+ const EXTS = ["br.com.datatechsolutions.tympan", "dev.tympan.print"];
5661
+ /** Unwraps a DTCG group into plain values: `{ $value }` leaves become their value; `$`-keys are dropped. */
5662
+ function desembrulhar(n) {
5663
+ if (!n || typeof n !== "object" || Array.isArray(n)) return n;
5664
+ const o = n;
5665
+ if ("$value" in o) {
5666
+ const v = o.$value;
5667
+ if (o.$type === "fontFamily" && Array.isArray(v)) return pilhaDeFontes(v);
5668
+ if (o.$type === "color" && v && typeof v === "object") return toHex(fromDtcgColor(v));
5669
+ if (o.$type === "dimension" && v && typeof v === "object" && "unit" in v) return emMm(v);
5670
+ return v;
5671
+ }
5672
+ const out = {};
5673
+ for (const [k, v] of Object.entries(o)) if (!k.startsWith("$")) out[k] = desembrulhar(v);
5674
+ return out;
5675
+ }
5676
+ const GENERICAS = /^(serif|sans-serif|monospace|cursive|fantasy|system-ui|ui-[a-z-]+)$/;
5677
+ const pilhaDeFontes = (v) => v.map((x) => GENERICAS.test(x) || /^["']/.test(x) ? x : `"${x}"`).join(", ");
5678
+ const emMm = (v) => v.unit === "px" ? v.value * 25.4 / 96 : v.unit === "pt" ? v.value * 25.4 / 72 : v.unit === "cm" ? v.value * 10 : v.value;
5679
+ /** Figures from the meta: an object by role, or a phrase such as "tabular-nums em numero e rotulo". */
5680
+ function lerAlgarismos(v) {
5681
+ if (v && typeof v === "object") return v;
5682
+ if (typeof v !== "string") return void 0;
5683
+ const tipo = /proporc|proportional/.test(v) ? "proporcional" : /tabular/.test(v) ? "tabular" : void 0;
5684
+ if (!tipo) return void 0;
5685
+ const papeis = [
5686
+ "numero",
5687
+ "rotulo",
5688
+ "corpo"
5689
+ ].filter((p) => v.includes(p));
5690
+ return Object.fromEntries((papeis.length ? papeis : ["numero"]).map((p) => [p, tipo]));
5691
+ }
5692
+ /**
5693
+ * A theme from a DTCG (2025.10) tree. The tree mirrors PrintStyleOverrides: each group is a field
5694
+ * (`label`, `fontes.<role>`, `googleFonts`, `cor.<role>`, `cor.prova.<state>`, `cor.categorica.<n>`,
5695
+ * `cor.divergente.<n>`, `traco.largura`, `pb.*`, `estrutura.*`, `texto.*`, `marcas.*`, `pagina.*`, `folio.*`,
5696
+ * `fontesLocais`…) and each `{ "$type", "$value" }` leaf becomes its value (colours as hex or DTCG colour
5697
+ * objects, `fontFamily` arrays become CSS stacks, dimensions become mm). The theme's id and base come from
5698
+ * the root `$extensions["dev.tympan.print"]` (or `["br.com.datatechsolutions.tympan"]`) as `name`/`id` and
5699
+ * `extends`/`base`.
5700
+ */
5701
+ function printThemeFromDtcg(tree) {
5702
+ const t = typeof tree === "string" ? JSON.parse(tree) : tree;
5703
+ const exts = t.$extensions ?? {};
5704
+ const meta = Object.assign({}, ...EXTS.map((e) => exts[e]).filter(Boolean).map((m) => ({
5705
+ ...m.tema,
5706
+ ...m
5707
+ })));
5708
+ const id = meta.id ?? meta.name;
5709
+ const base = meta.base ?? meta.extends;
5710
+ if (!id || !base) throw new Error(`tympan: a DTCG book theme needs $extensions["dev.tympan.print"] with name and extends`);
5711
+ const corpo = desembrulhar(t);
5712
+ const cor = corpo.cor;
5713
+ for (const g of [cor, corpo.pb]) if (g) {
5714
+ for (const k of [
5715
+ "categorica",
5716
+ "divergente",
5717
+ "ornamento"
5718
+ ]) if (g[k] && typeof g[k] === "object" && !Array.isArray(g[k])) g[k] = Object.entries(g[k]).sort(([a], [b]) => a.localeCompare(b, "en", { numeric: true })).map(([, v]) => v);
5719
+ }
5720
+ const texto = { ...corpo.texto };
5721
+ if (meta.pesos && typeof meta.pesos === "object") texto.pesos = {
5722
+ ...meta.pesos,
5723
+ ...texto.pesos
5724
+ };
5725
+ const alg = lerAlgarismos(meta.algarismos);
5726
+ if (alg) texto.algarismos = {
5727
+ ...alg,
5728
+ ...texto.algarismos
5729
+ };
5730
+ if (Object.keys(texto).length) corpo.texto = texto;
5731
+ const dado = meta.dado;
5732
+ if (dado) {
5733
+ const c = { ...corpo.cor };
5734
+ if (dado.interesse && c.interesse === void 0) c.interesse = dado.interesse;
5735
+ if (dado.contexto) c.contexto = dado.contexto;
5736
+ if (dado.perdeu && dado.ganhou && c.divergente === void 0) c.divergente = [dado.perdeu, dado.ganhou];
5737
+ corpo.cor = c;
5738
+ }
5739
+ return printThemeFromJson({
5740
+ ...corpo,
5741
+ id,
5742
+ base,
5743
+ ...meta.referencia ? { referencia: meta.referencia } : {}
5744
+ });
5745
+ }
5746
+ /** Registers (or replaces) a theme; accepts the theme object, its JSON or a DTCG tree. Returns the theme. */
5747
+ function registerPrintTheme(tema) {
5748
+ const obj = typeof tema === "string" ? JSON.parse(tema) : tema;
5749
+ const t = obj.$extensions ? printThemeFromDtcg(obj) : printThemeFromJson(obj);
5750
+ if (resolvePrintStyleName(t.id)) throw new Error(`tympan: book theme id "${t.id}" collides with a preset`);
5751
+ REGISTRO.set(t.id, t);
5752
+ printThemeById(t.id);
5753
+ return t;
5754
+ }
5755
+ /** Removes a registered theme (tests, hot reload). */
5756
+ function unregisterPrintTheme(id) {
5757
+ return REGISTRO.delete(id);
5758
+ }
5759
+ /** Ids of the registered themes, in registration order. */
5760
+ function registeredPrintThemes() {
5761
+ return [...REGISTRO.keys()];
5762
+ }
5763
+ /** `@font-face` rules for a style's local font files ('' when it has none). */
5764
+ function fontesLocaisCss(style) {
5765
+ return (style.fontesLocais ?? []).map((f) => `@font-face { font-family: "${f.familia.replace(/"/g, "")}"; src: url("${f.src.replace(/"/g, "%22")}") format("woff2"); font-weight: ${f.peso ?? 400}; font-style: ${f.estilo ?? "normal"}; font-display: block; }`).join("\n");
5766
+ }
5767
+ /** Trim and bleed of a style (defaults 170 × 240 mm, 3 mm bleed). */
5768
+ function paginaDoEstilo(style) {
5769
+ const p = style.pagina ?? {};
5770
+ return {
5771
+ largura: p.largura ?? 170,
5772
+ altura: p.altura ?? 240,
5773
+ sangria: p.sangria ?? 3,
5774
+ marcasCorte: p.marcasCorte ?? false
5775
+ };
5776
+ }
5777
+ /** A neutral example theme (registered nowhere by default): a small press over `semanario`, in two inks. */
5778
+ const TEMA_EXEMPLO_EDITORA = {
5779
+ id: "editora-exemplo",
5780
+ base: "semanario",
5781
+ label: "Editora Exemplo · coleção ensaios",
5782
+ fontes: { titulo: "\"Source Serif 4\", Georgia, serif" },
5783
+ cor: {
5784
+ destaque: "#1f4e79",
5785
+ destaque2: "#b5562b",
5786
+ marcaTexto: "#e8eef5"
5787
+ },
5788
+ pb: {
5789
+ destaque: "#333333",
5790
+ destaque2: "#8a8a8a"
5791
+ },
5792
+ texto: { nomesProprios: "preservar" },
5793
+ folio: {
5794
+ folio: "centro",
5795
+ cabeco: "externo"
5796
+ },
5797
+ pagina: {
5798
+ largura: 160,
5799
+ altura: 230,
5800
+ sangria: 3
5801
+ }
5802
+ };
5803
+ /** Families named in a style's font stacks (quotes removed), in role order, without generic and system faces. */
5804
+ function familiasDoEstilo(style) {
5805
+ const out = [];
5806
+ for (const pilha of Object.values(style.fontes)) for (const f of pilha.split(",").map((x) => x.trim().replace(/^["']|["']$/g, ""))) if (f && !SYSTEM_FONT_FAMILIES.includes(f) && !out.includes(f)) out.push(f);
5807
+ return out;
5808
+ }
5809
+ /** Families the style names (first of each stack) that have neither a bundled file nor a theme `fontesLocais`. */
5810
+ function familiasSemArquivo(style, manifest) {
5811
+ const proprias = new Set((style.fontesLocais ?? []).map((f) => f.familia));
5812
+ const primeiras = Object.values(style.fontes).map((p) => p.split(",")[0].trim().replace(/^["']|["']$/g, ""));
5813
+ return [...new Set(primeiras)].filter((f) => !SYSTEM_FONT_FAMILIES.includes(f) && !proprias.has(f) && !manifest.families[f]);
5814
+ }
5815
+ /**
5816
+ * @font-face rules for a style from the fonts bundled in this package (`fonts/manifest.json`): every face of
5817
+ * every family its font stacks name (so a mono or label family outside `googleFonts` is not forgotten), with
5818
+ * URLs `<base><file>`, then the theme's own `fontesLocais`, which win for their family.
5819
+ */
5820
+ function fontesEmpacotadasCss(style, manifest, base) {
5821
+ const proprias = new Set((style.fontesLocais ?? []).map((f) => f.familia));
5822
+ const familias = new Set(familiasDoEstilo(style).filter((f) => manifest.families[f] && !proprias.has(f)));
5823
+ const specs = Object.keys(manifest.specs).filter((s) => familias.has(s.split(":")[0]));
5824
+ return [specs.length ? fontFaceCss(manifest, specs, base) : "", fontesLocaisCss(style)].filter(Boolean).join("\n");
5825
+ }
5826
+ //#endregion
5484
5827
  //#region src/index.ts
5485
5828
  const allThemes = [...presets, ...printThemePresets];
5486
5829
  //#endregion
5487
- export { BASE_FONT_SPECS, CJK_FONT_FAMILIES, CJK_FONT_SPECS, CORE_FONT_SPECS, DEFAULT_CHART_HUES, DEFAULT_PRINT_STYLE, DEFAULT_THEME, DENSITIES, ESTADOS_PROVA, FLOW_TOKENS, FLOW_TONES, FONT_ROLE_TOKENS, FORCED_COLORS_VARS, OPAQUE_VARS, PRINT_PRESET_NAMES, PRINT_STYLE_ALIASES, PRINT_THEME_ALIASES, PRINT_THEME_OVERRIDES, PRINT_THEME_PREFIX, RAMP_STEPS, ROLE_ALIASES, ROLE_NAMES, ROTULOS_PROVA, SCRIPT_FONT_FAMILIES, SCRIPT_FONT_SPECS, SYSTEM_FONT_FAMILIES, allThemes, apcaContrast, astrlabeControlePreset, astrlabePreset, buildStylesheet, composite, contrastPairs, contrastRatio, deltaE2000, densityToDtcg, densityVariables, fakhirPreset, flatten, flowCssName, flowToDtcg, flowTokenCss, flowToneRules, flowVariables, fontFaceCss, fontStackToCss, fromDtcgColor, generatePrintThemesCss, generateRamp, generateThemeCss, googleFontsUrl, gradientToCss, highContrastPreset, legibleOn, luminance, mergePrintStyle, neutralPreset, oklchToRgb, papelEscuro, parseColor, parseFontStack, presetThemeVars, presets, printPresetById, printPresets, printStyleAccent, printStyleCoresPb, printStyleToCss, printStyleToTheme, printStyleVariables, printThemeDroppedPins, printThemeFontSpecs, printThemeFontUrls, printThemePresets, resolvePrintStyle, resolvePrintStyleName, resolvePrintThemeName, resolveTheme, rgbToLab, rgbToOklab, rgbToOklch, seedFromColor, shadowToCss, themeSelectors, themeToDtcg, themeVariables, themeVarsFor, toCss, toDtcgColor, toGrey, toHex, tympanPreset, warnDeprecatedPrintId };
5830
+ export { BASE_FONT_SPECS, CATEGORICA_PADRAO, CJK_FONT_FAMILIES, CJK_FONT_SPECS, CORE_FONT_SPECS, DEFAULT_CHART_HUES, DEFAULT_PRINT_STYLE, DEFAULT_THEME, DENSITIES, ESTADOS_PROVA, FLOW_TOKENS, FLOW_TONES, FONT_ROLE_TOKENS, FORCED_COLORS_VARS, OPAQUE_VARS, PRINT_PRESET_NAMES, PRINT_STYLE_ALIASES, PRINT_THEME_ALIASES, PRINT_THEME_OVERRIDES, PRINT_THEME_PREFIX, RAMP_STEPS, ROLE_ALIASES, ROLE_NAMES, ROTULOS_PROVA, ROTULOS_PROVA_EN, SCRIPT_FONT_FAMILIES, SCRIPT_FONT_SPECS, SYSTEM_FONT_FAMILIES, TEMA_EXEMPLO_EDITORA, allThemes, apcaContrast, astrlabeControlePreset, astrlabePreset, buildStylesheet, categoricaDoEstilo, composite, contrastPairs, contrastRatio, contrasteMinimo, deltaE2000, densityToDtcg, densityVariables, fakhirPreset, familiasDoEstilo, familiasSemArquivo, flatten, flowCssName, flowToDtcg, flowTokenCss, flowToneRules, flowVariables, fontFaceCss, fontStackToCss, fontesEmpacotadasCss, fontesLocaisCss, fromDtcgColor, generatePrintThemesCss, generateRamp, generateThemeCss, googleFontsUrl, gradientToCss, highContrastPreset, isPrintThemeId, legibleOn, luminance, mergePrintStyle, mergePrintTheme, neutralPreset, oklchToRgb, paginaDoEstilo, papelEscuro, parseColor, parseFontStack, presetThemeVars, presets, printPresetById, printPresets, printStyleAccent, printStyleCoresPb, printStyleToCss, printStyleToTheme, printStyleVariables, printTextoRolesCss, printThemeById, printThemeDroppedPins, printThemeFontSpecs, printThemeFontUrls, printThemeFromDtcg, printThemeFromJson, printThemePresets, registerPrintTheme, registeredPrintThemes, resolvePrintStyle, resolvePrintStyleName, resolvePrintThemeName, resolveTheme, rgbToLab, rgbToOklab, rgbToOklch, seedFromColor, shadowToCss, themeSelectors, themeToDtcg, themeVariables, themeVarsFor, toCss, toDtcgColor, toGrey, toHex, tympanPreset, unregisterPrintTheme, warnDeprecatedPrintId };
5488
5831
 
5489
5832
  //# sourceMappingURL=index.js.map