@silverpoint/core 0.6.0 → 0.8.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 (46) hide show
  1. package/README.md +14 -0
  2. package/dist/catalog.d.ts +2 -2
  3. package/dist/catalog.js +4 -2
  4. package/dist/catalog.js.map +1 -1
  5. package/dist/{chunk-OLYKR5PS.js → chunk-46QELMCG.js} +8 -213
  6. package/dist/chunk-46QELMCG.js.map +1 -0
  7. package/dist/chunk-5MP3BLZK.js +48 -0
  8. package/dist/chunk-5MP3BLZK.js.map +1 -0
  9. package/dist/chunk-6YFO7OP3.js +84 -0
  10. package/dist/chunk-6YFO7OP3.js.map +1 -0
  11. package/dist/chunk-ANJSW5JX.js +93 -0
  12. package/dist/chunk-ANJSW5JX.js.map +1 -0
  13. package/dist/{chunk-PD4MD7JU.js → chunk-E5CC2NNQ.js} +5 -3
  14. package/dist/chunk-E5CC2NNQ.js.map +1 -0
  15. package/dist/chunk-G7N4X5XD.js +12 -0
  16. package/dist/chunk-G7N4X5XD.js.map +1 -0
  17. package/dist/chunk-NI7B6UEO.js +24 -0
  18. package/dist/chunk-NI7B6UEO.js.map +1 -0
  19. package/dist/chunk-WYFRHI4S.js +179 -0
  20. package/dist/chunk-WYFRHI4S.js.map +1 -0
  21. package/dist/contrast-siWF_R5o.d.ts +30 -0
  22. package/dist/dashboard-demos.d.ts +2 -2
  23. package/dist/index.d.ts +13 -10
  24. package/dist/index.js +20 -9
  25. package/dist/index.js.map +1 -1
  26. package/dist/{model-CLhtoG75.d.ts → model-DVVt59AB.d.ts} +1 -1
  27. package/dist/palettes.d.ts +29 -0
  28. package/dist/palettes.js +79 -0
  29. package/dist/palettes.js.map +1 -0
  30. package/dist/{props-Dq8FC8GG.d.ts → props-BZ9CcrGv.d.ts} +53 -1
  31. package/dist/timeline.d.ts +90 -0
  32. package/dist/timeline.js +125 -0
  33. package/dist/timeline.js.map +1 -0
  34. package/dist/{types-B81k-s9_.d.ts → types-BT3Xm7fP.d.ts} +3 -1
  35. package/dist/types-D5ys35fF.d.ts +576 -0
  36. package/dist/types-DHBJ0PzV.d.ts +57 -0
  37. package/dist/ui-demos.d.ts +14 -3
  38. package/dist/ui-demos.js +163 -1
  39. package/dist/ui-demos.js.map +1 -1
  40. package/dist/ui.d.ts +346 -325
  41. package/dist/ui.js +932 -118
  42. package/dist/ui.js.map +1 -1
  43. package/dist/view-DteS9glE.d.ts +82 -0
  44. package/package.json +13 -1
  45. package/dist/chunk-OLYKR5PS.js.map +0 -1
  46. package/dist/chunk-PD4MD7JU.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/palette/contrast.ts","../src/palette/palette.ts"],"names":[],"mappings":"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","file":"chunk-ANJSW5JX.js","sourcesContent":["import { round2 } from '../render/round';\nimport type { Palette } from './palette';\n\n/** One pair of a palette below its threshold (REQ-465). */\nexport interface PaletteFinding {\n /** The pair's name in Data Model §3.9. */\n readonly pair: string;\n readonly foreground: string;\n readonly background: string;\n /** 2 decimals. */\n readonly ratio: number;\n readonly threshold: number;\n}\n\ninterface Pair {\n readonly pair: string;\n readonly threshold: number;\n readonly foreground: (p: Palette) => string | undefined;\n /** `undefined` measures against the substrate. */\n readonly background?: (p: Palette) => string | undefined;\n}\n\n/** The pairs `checkPalette` and the contrast gate measure (Data Model §3.9), in that order. */\nexport const PALETTE_PAIRS: readonly Pair[] = /* @__PURE__ */ Object.freeze([\n { pair: 'ink', threshold: 4.5, foreground: (p) => p.ink },\n { pair: 'ink-secondary', threshold: 4.5, foreground: (p) => p.inkSecondary },\n { pair: 'text', threshold: 4.5, foreground: (p) => p.text },\n { pair: 'text-muted', threshold: 4.5, foreground: (p) => p.textMuted },\n { pair: 'rule', threshold: 3, foreground: (p) => p.rule },\n { pair: 'grid', threshold: 3, foreground: (p) => p.grid },\n { pair: 'focus', threshold: 3, foreground: (p) => p.focus ?? p.ink },\n { pair: 'heighten-outline', threshold: 3, foreground: (p) => p.ink, background: (p) => p.heighten },\n { pair: 'heighten-text', threshold: 4.5, foreground: (p) => p.text, background: (p) => p.heighten },\n]);\n\n/** The cream substrate of the silverpoint ground: what a palette without one is measured on. */\nconst CREAM = '#EDE7DA';\n\nconst HEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;\n\nfunction luminance(hex: string): number {\n let value = hex.slice(1);\n if (value.length === 3) value = [...value].map((c) => c + c).join('');\n const [r, g, b] = [0, 2, 4].map((i) => {\n const c = parseInt(value.slice(i, i + 2), 16) / 255;\n return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2 contrast ratio of two hex colours (`#rgb` or `#rrggbb`), from 1 to 21. */\nexport function contrastRatio(foreground: string, background: string): number {\n const a = luminance(foreground);\n const b = luminance(background);\n return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n}\n\n/**\n * Every pair of Data Model §3.9 whose two colours are hex and whose ratio is below its threshold.\n * The substrate is the palette's, else `substrate`, else cream (REQ-465).\n */\nexport function checkPalette(palette: Palette, substrate?: string): readonly PaletteFinding[] {\n const ground = palette.substrate ?? substrate ?? CREAM;\n const findings: PaletteFinding[] = [];\n for (const { pair, threshold, foreground, background } of PALETTE_PAIRS) {\n const fg = foreground(palette);\n const bg = background ? background(palette) : ground;\n if (!fg || !bg || !HEX.test(fg) || !HEX.test(bg)) continue;\n const ratio = contrastRatio(fg, bg);\n if (ratio < threshold) findings.push({ pair, foreground: fg, background: bg, ratio: round2(ratio), threshold });\n }\n return findings;\n}\n","import { diagnose } from '../diagnostics/diagnose';\nimport type { ProviderConfig } from '../types/props';\nimport { checkPalette } from './contrast';\n\n/**\n * The colours of one ground's inks, for one element or one section (REQ-460, Data Model §2.26).\n * Every field is optional: an unset field keeps the ground's own. Values are any CSS colour;\n * `checkPalette` can only measure hex values.\n */\nexport interface Palette {\n /** The prepared ground the drawing sits on. */\n readonly substrate?: string;\n /** The main series and the frames of UI components. */\n readonly ink?: string;\n /** The second series and the hatch of tones. */\n readonly inkSecondary?: string;\n /** White heightening on the live value (always outlined with `ink`). */\n readonly heighten?: string;\n /** Rules and baselines. */\n readonly rule?: string;\n /** Grid lines. */\n readonly grid?: string;\n /** Large figures and primary labels. */\n readonly text?: string;\n /** Axis labels and secondary text. */\n readonly textMuted?: string;\n /** Focus ring of UI components; `ink` by default. */\n readonly focus?: string;\n}\n\n/** The fields, in the order of every emitted declaration (REQ-461). */\nconst FIELDS = ['substrate', 'ink', 'inkSecondary', 'heighten', 'rule', 'grid', 'text', 'textMuted', 'focus'] as const;\n\n/** `inkSecondary` → `--sp-ink-secondary`; `focus` is the UI focus ring's own property. */\nconst property = (field: string): `--sp-${string}` =>\n field === 'focus' ? '--sp-ui-focus-color' : `--sp-${field.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}`;\n\n/** Field → custom property, in the order of every emitted declaration (REQ-461). */\nexport const PALETTE_PROPERTIES: Readonly<Record<keyof Palette, `--sp-${string}`>> = /* @__PURE__ */ Object.freeze(\n Object.fromEntries(FIELDS.map((field) => [field, property(field)])) as Record<keyof Palette, `--sp-${string}`>,\n);\n\n/**\n * A CSS colour, by allowlist (REQ-467): a hex, a keyword, or a colour function (`var()` and\n * `color-mix()` included) over numbers, idents and `--custom` names. No quotes, escapes, `;`, `{`,\n * `<` or `:` can pass, and every function named must be a colour function, so a value can neither\n * end its declaration nor load a resource (`url()`, `image-set()`).\n */\nconst COLOUR_CHARS = /^[\\w\\s#%.,/()+-]+$/;\nconst COLOUR_FUNCTIONS = new Set(['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'lab', 'lch', 'oklab', 'oklch', 'color', 'color-mix', 'light-dark', 'var']);\nconst isColour = (value: string): boolean =>\n COLOUR_CHARS.test(value) && [...value.matchAll(/([\\w-]*)\\(/g)].every(([, name]) => COLOUR_FUNCTIONS.has(name!.toLowerCase()));\n\n/**\n * The palettes of an element's layers merged field by field, a later layer winning: call it as\n * `resolvePalette(provider, cell, element)` (REQ-462). Unknown fields and unsafe values are dropped\n * with `SP024`; a weak hex pair is kept and warned `SP023` (REQ-466, REQ-467).\n */\nexport function resolvePalette(...layers: readonly (Palette | undefined)[]): Palette | undefined {\n const out: Record<string, string> = {};\n for (const layer of layers) {\n if (!layer) continue;\n for (const [field, value] of Object.entries(layer)) {\n // An unset field keeps the layer below (REQ-460): Vue and Angular hand absent ones as undefined.\n if (value === undefined) continue;\n const colour = typeof value === 'string' ? value.trim() : '';\n if (!(FIELDS as readonly string[]).includes(field) || !colour || !isColour(colour)) {\n // Dropped in every build; only the warning is development-only (REQ-467).\n if (process.env.NODE_ENV !== 'production') diagnose('SP024', 'Palette', { property: field, message: `${JSON.stringify(value)} is dropped.` });\n continue;\n }\n out[field] = colour;\n }\n }\n if (Object.keys(out).length === 0) return undefined;\n if (process.env.NODE_ENV !== 'production') {\n for (const finding of checkPalette(out)) {\n diagnose('SP023', 'Palette', {\n property: finding.pair,\n message: `${finding.foreground} on ${finding.background} is ${finding.ratio.toFixed(2)}:1, below ${finding.threshold}:1.`,\n });\n }\n }\n return out;\n}\n\n/** `--sp-ink:#8A3A24;--sp-text:#4A2216`: a palette's declarations, in PALETTE_PROPERTIES order; '' for none (REQ-461). */\nexport function paletteStyle(palette: Palette | undefined): string {\n if (!palette) return '';\n return FIELDS.filter((field) => typeof palette[field] === 'string' && isColour(palette[field].trim()))\n .map((field) => `${property(field)}:${palette[field]!.trim()}`)\n .join(';');\n}\n\n\n/**\n * A provider inside another (REQ-462): the inner one's set fields win, the rest is the outer's, and\n * the palettes merge field by field, so a nested provider re-colours a section and keeps the rest.\n */\nexport function nestProvider(outer: ProviderConfig | undefined, own: ProviderConfig): ProviderConfig {\n const out: Record<string, unknown> = { ...outer };\n for (const [key, value] of Object.entries(own)) if (value !== undefined) out[key] = value;\n if (outer?.palette && own.palette) out.palette = { ...outer.palette, ...defined(own.palette) };\n return out;\n}\n\nconst defined = (palette: Palette): Palette => Object.fromEntries(Object.entries(palette).filter(([, value]) => value !== undefined));\n"]}
@@ -1,4 +1,6 @@
1
- import { formatValue, diagnose, roundGeometry } from './chunk-OLYKR5PS.js';
1
+ import { formatValue } from './chunk-46QELMCG.js';
2
+ import { roundGeometry } from './chunk-5MP3BLZK.js';
3
+ import { diagnose } from './chunk-WYFRHI4S.js';
2
4
 
3
5
  // src/render/prng.ts
4
6
  function createPrng(seed) {
@@ -166,5 +168,5 @@ function readyModel(base, description, geometry) {
166
168
  }
167
169
 
168
170
  export { addDays, cardLayout, createPrng, emptyModel, isoDate, measure, modelBase, parseIsoDate, readyModel, weekday };
169
- //# sourceMappingURL=chunk-PD4MD7JU.js.map
170
- //# sourceMappingURL=chunk-PD4MD7JU.js.map
171
+ //# sourceMappingURL=chunk-E5CC2NNQ.js.map
172
+ //# sourceMappingURL=chunk-E5CC2NNQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/render/prng.ts","../src/charts/shared/dates.ts","../src/charts/shared/card.ts","../src/charts/shared/shell.ts"],"names":["areaHeight"],"mappings":";;;;;AAKO,SAAS,WAAW,IAAA,EAA4B;AACrD,EAAA,IAAI,QAAQ,IAAA,KAAS,CAAA;AACrB,EAAA,OAAO,MAAM;AACX,IAAA,KAAA,GAAS,QAAQ,UAAA,KAAgB,CAAA;AACjC,IAAA,IAAI,CAAA,GAAI,KAAA;AACR,IAAA,CAAA,GAAI,KAAK,IAAA,CAAK,CAAA,GAAK,CAAA,KAAM,EAAA,EAAK,IAAI,CAAC,CAAA;AACnC,IAAA,CAAA,IAAK,IAAI,IAAA,CAAK,IAAA,CAAK,IAAK,CAAA,KAAM,CAAA,EAAI,IAAI,EAAE,CAAA;AACxC,IAAA,OAAA,CAAA,CAAS,CAAA,GAAK,CAAA,KAAM,EAAA,MAAS,CAAA,IAAK,UAAA;AAAA,EACpC,CAAA;AACF;;;ACVA,IAAM,MAAA,GAAS,KAAA;AACf,IAAM,QAAA,GAAW,2BAAA;AAGV,SAAS,aAAa,GAAA,EAAqB;AAChD,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAC/B,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,MAAA,CAAO,GAAA;AAC1B,EAAA,OAAO,KAAK,GAAA,CAAI,MAAA,CAAO,MAAM,CAAC,CAAC,GAAG,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,IAAI,CAAA,EAAG,MAAA,CAAO,MAAM,CAAC,CAAC,CAAC,CAAA,GAAI,MAAA;AAC9E;AAGO,SAAS,QAAQ,GAAA,EAAqB;AAC3C,EAAA,OAAO,IAAI,KAAK,GAAA,GAAM,MAAM,EAAE,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AACzD;AAEO,SAAS,OAAA,CAAQ,KAAa,IAAA,EAAsB;AACzD,EAAA,OAAO,GAAA,GAAM,IAAA;AACf;AAGO,SAAS,QAAQ,GAAA,EAAqB;AAC3C,EAAA,OAAA,CAAA,CAAU,GAAA,GAAM,CAAA,IAAK,CAAA,GAAK,CAAA,IAAK,CAAA;AACjC;;;ACtBO,IAAM,YAAA,GAAe,EAAA;AAC5B,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,UAAA,GAAa,EAAA;AAeZ,SAAS,UAAA,CACd,OACA,OAAA,EAMY;AACZ,EAAA,MAAM,EAAE,KAAA,EAAO,UAAA,EAAAA,WAAAA,EAAY,MAAA,EAAQ,QAAO,GAAI,OAAA;AAC9C,EAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,IAAA,MAAM,GAAA,GAAM,EAAE,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAG,KAAA,EAAO,QAAQA,WAAAA,EAAW;AACpD,IAAA,OAAO,EAAE,OAAA,EAAS,GAAA,EAAK,IAAA,EAAM,GAAA,EAAK,SAAS,EAAC,EAAG,MAAA,EAAQ,EAAC,EAAE;AAAA,EAC5D;AAEA,EAAA,MAAM,SAAsB,EAAC;AAC7B,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,IAAA,GAAO,YAAA;AACb,EAAA,MAAM,QAAQ,KAAA,GAAQ,YAAA;AACtB,EAAA,IAAI,MAAA,GAAS,YAAA;AAEb,EAAA,IAAI,KAAA,CAAM,KAAA,KAAU,MAAA,IAAa,KAAA,CAAM,UAAU,MAAA,EAAW;AAC1D,IAAA,MAAM,WAAW,MAAA,GAAS,EAAA;AAC1B,IAAA,IAAI,KAAA,CAAM,UAAU,MAAA,EAAW;AAC7B,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,EAAG,IAAA,EAAM,GAAG,QAAA,EAAU,IAAA,EAAM,KAAA,CAAM,KAAA,EAAO,MAAM,OAAA,EAAS,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,SAAS,CAAA;AAAA,IACvG;AACA,IAAA,IAAI,KAAA,CAAM,UAAU,MAAA,EAAW;AAC7B,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,EAAG,KAAA,EAAO,GAAG,QAAA,EAAU,IAAA,EAAM,KAAA,CAAM,KAAA,EAAO,MAAM,OAAA,EAAS,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA;AAAA,IACtG;AACA,IAAA,MAAA,IAAU,SAAA;AAAA,EACZ;AAEA,EAAA,IAAI,KAAA,CAAM,KAAA,KAAU,MAAA,IAAa,KAAA,CAAM,SAAS,MAAA,EAAW;AACzD,IAAA,IAAI,KAAA,CAAM,UAAU,MAAA,EAAW;AAC7B,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,CAAA,EAAG,IAAA;AAAA,QACH,GAAG,MAAA,GAAS,EAAA;AAAA,QACZ,MAAM,WAAA,CAAY,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,MAAM,YAAY,CAAA;AAAA,QACzD,IAAA,EAAM,OAAA;AAAA,QACN,IAAA,EAAM,MAAA;AAAA,QACN,MAAA,EAAQ;AAAA,OACT,CAAA;AAAA,IACH;AACA,IAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAW;AAC5B,MAAA,MAAA,CAAO,KAAK,EAAE,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,SAAS,EAAA,EAAI,IAAA,EAAM,KAAA,CAAM,IAAA,EAAM,MAAM,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,SAAS,CAAA;AAAA,IACxG;AACA,IAAA,MAAA,IAAU,SAAA;AAAA,EACZ;AAEA,EAAA,IAAI,MAAA,GAAS,cAAc,MAAA,IAAU,UAAA;AACrC,EAAA,MAAM,IAAA,GAAO,EAAE,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,QAAQ,KAAA,EAAO,KAAA,GAAQ,IAAA,EAAM,MAAA,EAAQA,WAAAA,EAAW;AAC3E,EAAA,MAAA,IAAUA,WAAAA;AAEV,EAAA,IAAI,KAAA,CAAM,UAAA,KAAe,MAAA,IAAa,KAAA,CAAM,gBAAgB,MAAA,EAAW;AACrE,IAAA,MAAM,QAAQ,MAAA,GAAS,CAAA;AACvB,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,QAAQ,CAAA;AAChF,IAAA,IAAI,KAAA,CAAM,eAAe,MAAA,EAAW;AAClC,MAAA,MAAA,CAAO,KAAK,EAAE,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,QAAQ,EAAA,EAAI,IAAA,EAAM,KAAA,CAAM,UAAA,EAAY,MAAM,QAAA,EAAU,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,SAAS,CAAA;AAAA,IAC/G;AACA,IAAA,IAAI,KAAA,CAAM,gBAAgB,MAAA,EAAW;AACnC,MAAA,MAAA,CAAO,KAAK,EAAE,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,QAAQ,EAAA,EAAI,IAAA,EAAM,KAAA,CAAM,WAAA,EAAa,MAAM,QAAA,EAAU,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA;AAAA,IAC/G;AACA,IAAA,MAAA,IAAU,UAAA;AAAA,EACZ;AAEA,EAAA,MAAM,SAAS,MAAA,GAAS,YAAA;AACxB,EAAA,MAAM,KAAA,GAAQ,GAAA;AACd,EAAA,OAAA,CAAQ,OAAA,CAAQ;AAAA,IACd,CAAA,EAAG,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,KAAA,GAAQ,KAAK,CAAA,CAAA,EAAI,MAAA,GAAS,KAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,CAAA;AAAA,IACjE,IAAA,EAAM,UAAA;AAAA,IACN,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,OAAO,EAAE,OAAA,EAAS,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAA,EAAO,MAAA,EAAO,EAAG,IAAA,EAAM,OAAA,EAAS,MAAA,EAAO;AACzE;;;AC/EO,SAAS,SAAA,CACd,KAAA,EACA,KAAA,EACA,OAAA,EACA,cACA,KAAA,EACW;AACX,EAAA,MAAM,EAAE,IAAG,GAAI,OAAA;AACf,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,IAAS,KAAA,CAAM,KAAA,IAAS,YAAA;AAC3C,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,EAAA;AAAA,IACA,MAAA,EAAQ,MAAM,MAAA,IAAU,MAAA;AAAA,IACxB,IAAA;AAAA,IACA,GAAA,EAAK,EAAE,KAAA,EAAO,CAAA,EAAG,EAAE,CAAA,MAAA,CAAA,EAAU,IAAA,EAAM,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA,EAAS,KAAA,EAAO,CAAA,EAAG,EAAE,CAAA,MAAA,CAAA,EAAS;AAAA,IACtE,KAAA,EAAO,EAAE,OAAA,EAAS,IAAA,EAAM,GAAG,KAAA,EAAM;AAAA,IACjC,SAAA,EAAW,MAAM,SAAA,IAAa;AAAA,GAChC;AACF;AAGO,SAAS,WAAW,KAAA,EAAiC;AAC1D,EAAA,OAAO,MAAM,MAAA,IAAU,GAAA;AACzB;AAMO,SAAS,OAAA,CACd,IAAA,EACA,KAAA,EACA,OAAA,EACyF;AACzF,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,IAAS,OAAA,CAAQ,KAAA;AACrC,EAAA,MAAM,MAAA,GAAS,WAAW,KAAK,CAAA;AAC/B,EAAA,IAAI,KAAA,KAAU,UAAa,KAAA,GAAQ,CAAA,IAAK,SAAS,CAAA,EAAG,OAAO,EAAE,KAAA,EAAO,MAAA,EAAO;AAC3E,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,aAAa,YAAA,EAAc;AAChE,IAAA,QAAA,CAAS,OAAA,EAAS,KAAK,KAAA,EAAO;AAAA,MAC5B,QAAA,EAAU,KAAA,IAAS,CAAA,GAAI,OAAA,GAAU,QAAA;AAAA,MACjC,OAAA,EAAS,CAAA,SAAA,EAAY,KAAK,CAAA,MAAA,EAAM,MAAM,CAAA,IAAA;AAAA,KACvC,CAAA;AAAA,EACH;AACA,EAAA,MAAM,GAAA,GAAM,EAAE,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAE;AAC9C,EAAA,OAAO;AAAA,IACL,QAAA,EAAU;AAAA,MACR,GAAG,IAAA;AAAA,MACH,MAAA,EAAQ,UAAA;AAAA,MACR,UAAU,EAAE,OAAA,EAAS,GAAA,EAAK,IAAA,EAAM,KAAK,OAAA,EAAS,EAAC,EAAG,MAAA,EAAQ,EAAC,EAAG,QAAA,EAAU,EAAC,EAAG,IAAA,EAAM,EAAC,EAAE;AAAA,MACrF,WAAA,EAAa,KAAA,CAAM,WAAA,IAAe,IAAA,CAAK;AAAA;AACzC,GACF;AACF;AAMO,SAAS,UAAA,CACd,IAAA,EACA,KAAA,EACA,OAAA,EACA,OACA,YAAA,EACY;AACZ,EAAA,IAAI,YAAA,IAAgB,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AACzD,IAAA,QAAA,CAAS,SAAS,IAAA,CAAK,KAAA,EAAO,EAAE,QAAA,EAAU,QAAQ,CAAA;AAAA,EACpD;AACA,EAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,EAAA,MAAM,OAAA,GAAoB,CAAC,GAAG,KAAA,CAAM,OAAO,CAAA;AAC3C,EAAA,IAAI,OAAA,CAAQ,WAAW,IAAA,EAAM;AAC3B,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,CAAA,CAAA,EAAI,KAAK,CAAC,CAAA,CAAA,EAAI,KAAK,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,IAAA,CAAK,KAAK,IAAI,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,MAAA,EAAQ,CAAA;AAAA,EACjH;AACA,EAAA,MAAM,MAAA,GAAsB;AAAA,IAC1B,GAAG,KAAA,CAAM,MAAA;AAAA,IACT;AAAA,MACE,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,KAAA,GAAQ,CAAA;AAAA,MACzB,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,MAAA,GAAS,CAAA;AAAA,MAC1B,IAAA,EAAM,QAAQ,UAAA,CAAW,IAAA;AAAA,MACzB,IAAA,EAAM,OAAA;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,MAAA,EAAQ;AAAA;AACV,GACF;AACA,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,MAAA,EAAQ,OAAA;AAAA,IACR,WAAA,EAAa,MAAM,WAAA,IAAe,CAAA,EAAG,KAAK,IAAI,CAAA,EAAA,EAAK,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAA,CAAA,CAAA;AAAA,IAC1E,QAAA,EAAU,aAAA,CAAc,EAAE,OAAA,EAAS,MAAM,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,UAAU,EAAC,EAAG,IAAA,EAAM,IAAI;AAAA,GACnG;AACF;AAGO,SAAS,UAAA,CACd,IAAA,EACA,WAAA,EACA,QAAA,EACY;AACZ,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,SAAS,WAAA,EAAa,QAAA,EAAU,aAAA,CAAc,EAAE,GAAG,QAAA,EAAU,IAAA,EAAM,EAAC,EAAG,CAAA,EAAE;AACrG","file":"chunk-E5CC2NNQ.js","sourcesContent":["/**\n * A seeded 32-bit PRNG (mulberry32), for generated demo data (Data Model §4). Owned here rather\n * than imported, so its sequence is frozen by SemVer like the seed derivation (DD-006): changing\n * it changes demo output, which is never a patch.\n */\nexport function createPrng(seed: number): () => number {\n let state = seed >>> 0;\n return () => {\n state = (state + 0x6d2b79f5) >>> 0;\n let t = state;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4_294_967_296;\n };\n}\n","/**\n * ISO dates as whole days since 1970-01-01, in UTC. Day arithmetic never touches the host's\n * time zone or clock, so server and client agree (REQ-005, REQ-103).\n */\nconst DAY_MS = 86_400_000;\nconst ISO_DATE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** Days since the epoch of an ISO `YYYY-MM-DD` date; `NaN` when it is not one. */\nexport function parseIsoDate(iso: string): number {\n const match = ISO_DATE.exec(iso);\n if (!match) return Number.NaN;\n return Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])) / DAY_MS;\n}\n\n/** The ISO `YYYY-MM-DD` form of a day number. */\nexport function isoDate(day: number): string {\n return new Date(day * DAY_MS).toISOString().slice(0, 10);\n}\n\nexport function addDays(day: number, days: number): number {\n return day + days;\n}\n\n/** Day of the week in UTC, 0 = Sunday. */\nexport function weekday(day: number): number {\n return (((day + 4) % 7) + 7) % 7;\n}\n","import type { CommonChartProps, Rect, Stroke, TextLabel } from '../../types';\nimport { formatValue } from './format';\n\n/** Inner padding of the card frame. */\nexport const CARD_PADDING = 16;\nconst TITLE_ROW = 20;\nconst VALUE_ROW = 52;\nconst HEADER_GAP = 8;\nconst FOOTER_ROW = 30;\n\nexport interface CardLayout {\n readonly viewBox: Rect;\n /** Where the chart draws; the whole viewBox under `chrome: 'bare'`. */\n readonly area: Rect;\n readonly strokes: readonly Stroke[];\n readonly labels: readonly TextLabel[];\n}\n\n/**\n * Lays out the card frame shared by every chart: title and badge, metric and unit, the drawing\n * area and the footer. Under `chrome: 'bare'` it emits the drawing area and nothing else\n * (REQ-095).\n */\nexport function cardLayout(\n props: CommonChartProps,\n options: {\n readonly width: number;\n readonly areaHeight: number;\n readonly chrome: 'card' | 'bare';\n readonly locale: string;\n },\n): CardLayout {\n const { width, areaHeight, chrome, locale } = options;\n if (chrome === 'bare') {\n const box = { x: 0, y: 0, width, height: areaHeight };\n return { viewBox: box, area: box, strokes: [], labels: [] };\n }\n\n const labels: TextLabel[] = [];\n const strokes: Stroke[] = [];\n const left = CARD_PADDING;\n const right = width - CARD_PADDING;\n let cursor = CARD_PADDING;\n\n if (props.title !== undefined || props.badge !== undefined) {\n const baseline = cursor + 11;\n if (props.title !== undefined) {\n labels.push({ x: left, y: baseline, text: props.title, kind: 'title', part: 'text', anchor: 'start' });\n }\n if (props.badge !== undefined) {\n labels.push({ x: right, y: baseline, text: props.badge, kind: 'badge', part: 'axis', anchor: 'end' });\n }\n cursor += TITLE_ROW;\n }\n\n if (props.value !== undefined || props.unit !== undefined) {\n if (props.value !== undefined) {\n labels.push({\n x: left,\n y: cursor + 30,\n text: formatValue(props.value, locale, props.numberFormat),\n kind: 'value',\n part: 'text',\n anchor: 'start',\n });\n }\n if (props.unit !== undefined) {\n labels.push({ x: left, y: cursor + 46, text: props.unit, kind: 'unit', part: 'axis', anchor: 'start' });\n }\n cursor += VALUE_ROW;\n }\n\n if (cursor > CARD_PADDING) cursor += HEADER_GAP;\n const area = { x: left, y: cursor, width: right - left, height: areaHeight };\n cursor += areaHeight;\n\n if (props.footerLeft !== undefined || props.footerRight !== undefined) {\n const ruleY = cursor + 8;\n strokes.push({ d: `M${left},${ruleY}H${right}`, role: 'ornament', part: 'rule' });\n if (props.footerLeft !== undefined) {\n labels.push({ x: left, y: ruleY + 18, text: props.footerLeft, kind: 'footer', part: 'axis', anchor: 'start' });\n }\n if (props.footerRight !== undefined) {\n labels.push({ x: right, y: ruleY + 18, text: props.footerRight, kind: 'footer', part: 'axis', anchor: 'end' });\n }\n cursor += FOOTER_ROW;\n }\n\n const height = cursor + CARD_PADDING;\n const inset = 0.5;\n strokes.unshift({\n d: `M${inset},${inset}H${width - inset}V${height - inset}H${inset}Z`,\n role: 'ornament',\n part: 'rule',\n });\n\n return { viewBox: { x: 0, y: 0, width, height }, area, strokes, labels };\n}\n","import { diagnose } from '../../diagnostics/diagnose';\nimport { roundGeometry } from '../../render/round';\nimport type {\n ChartModel,\n CommonChartProps,\n DataTable,\n Geometry,\n HitArea,\n RecipeContext,\n Rect,\n Stroke,\n TextLabel,\n} from '../../types';\n\n/** What every chart model shares, before any geometry: identity and the accessible layer. */\nexport type ModelBase = Pick<ChartModel, 'chart' | 'id' | 'chrome' | 'name' | 'ids' | 'table' | 'dataTable'>;\n\n/** The accessible name, ids and table of a chart (REQ-120, REQ-121). */\nexport function modelBase(\n chart: string,\n props: CommonChartProps,\n context: RecipeContext,\n fallbackName: string,\n table: Omit<DataTable, 'caption'>,\n): ModelBase {\n const { id } = context;\n const name = props.label ?? props.title ?? fallbackName;\n return {\n chart,\n id,\n chrome: props.chrome ?? 'card',\n name,\n ids: { title: `${id}-title`, desc: `${id}-desc`, table: `${id}-table` },\n table: { caption: name, ...table },\n dataTable: props.dataTable ?? 'hidden',\n };\n}\n\n/** The drawing-area height a chart asks for: the `height` prop or the default of API Spec §5.1. */\nexport function areaHeight(props: CommonChartProps): number {\n return props.height ?? 160;\n}\n\n/**\n * The width the chart draws at, or a deferred model when the container has no usable size yet:\n * the render waits, and no attribute ever carries `NaN` (REQ-009, SP003).\n */\nexport function measure(\n base: ModelBase,\n props: CommonChartProps,\n context: RecipeContext,\n): { readonly width: number; readonly height: number } | { readonly deferred: ChartModel } {\n const width = props.width ?? context.width;\n const height = areaHeight(props);\n if (width !== undefined && width > 0 && height > 0) return { width, height };\n if (width !== undefined && process.env.NODE_ENV !== 'production') {\n diagnose('SP003', base.chart, {\n property: width <= 0 ? 'width' : 'height',\n message: `Measured ${width} × ${height} px.`,\n });\n }\n const box = { x: 0, y: 0, width: 0, height: 0 };\n return {\n deferred: {\n ...base,\n status: 'deferred',\n geometry: { viewBox: box, plot: box, strokes: [], labels: [], hitAreas: [], defs: [] },\n description: props.description ?? base.name,\n },\n };\n}\n\n/**\n * The ground's empty state inside the drawing area, with no spurious axes and no exception\n * (REQ-007). SP001 is reported only when the dataset itself is empty.\n */\nexport function emptyModel(\n base: ModelBase,\n props: CommonChartProps,\n context: RecipeContext,\n frame: { readonly viewBox: Rect; readonly plot: Rect; readonly strokes: readonly Stroke[]; readonly labels: readonly TextLabel[] },\n datasetEmpty: boolean,\n): ChartModel {\n if (datasetEmpty && process.env.NODE_ENV !== 'production') {\n diagnose('SP001', base.chart, { property: 'data' });\n }\n const { plot } = frame;\n const strokes: Stroke[] = [...frame.strokes];\n if (context.emptyState.rule) {\n strokes.push({ d: `M${plot.x},${plot.y + plot.height}H${plot.x + plot.width}`, role: 'ornament', part: 'rule' });\n }\n const labels: TextLabel[] = [\n ...frame.labels,\n {\n x: plot.x + plot.width / 2,\n y: plot.y + plot.height / 2,\n text: context.emptyState.text,\n kind: 'empty',\n part: 'axis',\n anchor: 'middle',\n },\n ];\n return {\n ...base,\n status: 'ready',\n description: props.description ?? `${base.name}. ${context.emptyState.text}.`,\n geometry: roundGeometry({ viewBox: frame.viewBox, plot, strokes, labels, hitAreas: [], defs: [] }),\n };\n}\n\n/** A drawn chart: its geometry rounded to 2 decimals (REQ-002). */\nexport function readyModel(\n base: ModelBase,\n description: string,\n geometry: Omit<Geometry, 'defs' | 'hitAreas'> & { readonly hitAreas: readonly HitArea[] },\n): ChartModel {\n return { ...base, status: 'ready', description, geometry: roundGeometry({ ...geometry, defs: [] }) };\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { diagnose } from './chunk-WYFRHI4S.js';
2
+
3
+ // src/ui/names.ts
4
+ function uiRequireName(component, text, label) {
5
+ if (process.env.NODE_ENV === "production") return;
6
+ if (text?.trim() || label?.trim()) return;
7
+ diagnose("SP018", component, { property: "label" });
8
+ }
9
+
10
+ export { uiRequireName };
11
+ //# sourceMappingURL=chunk-G7N4X5XD.js.map
12
+ //# sourceMappingURL=chunk-G7N4X5XD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/names.ts"],"names":[],"mappings":";;;AAMO,SAAS,aAAA,CAAc,SAAA,EAAmB,IAAA,EAA0B,KAAA,EAAiC;AAC1G,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AAC3C,EAAA,IAAI,IAAA,EAAM,IAAA,EAAK,IAAK,KAAA,EAAO,MAAK,EAAG;AACnC,EAAA,QAAA,CAAS,OAAA,EAAS,SAAA,EAAW,EAAE,QAAA,EAAU,SAAS,CAAA;AACpD","file":"chunk-G7N4X5XD.js","sourcesContent":["import { diagnose } from '../diagnostics/diagnose';\n\n/**\n * A Button or Badge needs an accessible name: its text content or a `label`. Without either it\n * still renders, and warns `SP018` in development (REQ-319).\n */\nexport function uiRequireName(component: string, text: string | undefined, label: string | undefined): void {\n if (process.env.NODE_ENV === 'production') return;\n if (text?.trim() || label?.trim()) return;\n diagnose('SP018', component, { property: 'label' });\n}\n"]}
@@ -0,0 +1,24 @@
1
+ // src/ui/sort.ts
2
+ var sortKey = (value) => typeof value === "number" ? [0, value] : [1, String(value).toLowerCase()];
3
+ function compare(a, b) {
4
+ if (a[0] !== b[0]) return a[0] - b[0];
5
+ if (a[0] === 0) return a[1] - b[1];
6
+ return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0;
7
+ }
8
+ function uiSortRows(rows, key, order = "asc") {
9
+ if (!key) return [...rows];
10
+ const sign = order === "desc" ? -1 : 1;
11
+ const present = [];
12
+ const missing = [];
13
+ for (const row of rows) {
14
+ const value = row[key];
15
+ if (value === null || value === void 0) missing.push(row);
16
+ else present.push({ row, key: sortKey(value) });
17
+ }
18
+ present.sort((a, b) => sign * compare(a.key, b.key));
19
+ return [...present.map((p) => p.row), ...missing];
20
+ }
21
+
22
+ export { uiSortRows };
23
+ //# sourceMappingURL=chunk-NI7B6UEO.js.map
24
+ //# sourceMappingURL=chunk-NI7B6UEO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/sort.ts"],"names":[],"mappings":";AAKA,IAAM,UAAU,CAAC,KAAA,KAA6B,OAAO,KAAA,KAAU,WAAW,CAAC,CAAA,EAAG,KAAK,CAAA,GAAI,CAAC,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA,CAAE,aAAa,CAAA;AAEtH,SAAS,OAAA,CAAQ,GAAY,CAAA,EAAoB;AAC/C,EAAA,IAAI,CAAA,CAAE,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,EAAG,OAAO,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AACpC,EAAA,IAAI,CAAA,CAAE,CAAC,CAAA,KAAM,CAAA,SAAU,CAAA,CAAE,CAAC,CAAA,GAAK,CAAA,CAAE,CAAC,CAAA;AAClC,EAAA,OAAO,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA,GAAK,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,IAAI,CAAA,GAAI,CAAA;AAC9C;AAOO,SAAS,UAAA,CAA4B,IAAA,EAAoB,GAAA,EAAyB,KAAA,GAAwB,KAAA,EAAqB;AACpI,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,CAAC,GAAG,IAAI,CAAA;AACzB,EAAA,MAAM,IAAA,GAAO,KAAA,KAAU,MAAA,GAAS,EAAA,GAAK,CAAA;AACrC,EAAA,MAAM,UAAwD,EAAC;AAC/D,EAAA,MAAM,UAAe,EAAC;AACtB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,MAAM,KAAA,GAAQ,IAAI,GAAG,CAAA;AACrB,IAAA,IAAI,UAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,SACtD,OAAA,CAAQ,KAAK,EAAE,GAAA,EAAK,KAAK,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,EAChD;AAEA,EAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAA,GAAO,QAAQ,CAAA,CAAE,GAAA,EAAK,CAAA,CAAE,GAAG,CAAC,CAAA;AACnD,EAAA,OAAO,CAAC,GAAG,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,GAAG,CAAA,EAAG,GAAG,OAAO,CAAA;AAClD","file":"chunk-NI7B6UEO.js","sourcesContent":["import type { Datum } from '../types';\n\n/** A cell's sort key, computed once per row: numbers before anything else, which compares by code point after lowercasing. */\ntype SortKey = readonly [rank: 0, value: number] | readonly [rank: 1, value: string];\n\nconst sortKey = (value: unknown): SortKey => (typeof value === 'number' ? [0, value] : [1, String(value).toLowerCase()]);\n\nfunction compare(a: SortKey, b: SortKey): number {\n if (a[0] !== b[0]) return a[0] - b[0];\n if (a[0] === 0) return a[1] - (b[1] as number);\n return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0;\n}\n\n/**\n * A table's rows in order of `key` (REQ-474, I-34): stable, `null` and missing values last in input\n * order, `desc` reversing the present rows only. No locale, so the order is the same on every\n * server. Pure: the input is never mutated.\n */\nexport function uiSortRows<T extends Datum>(rows: readonly T[], key: string | undefined, order: 'asc' | 'desc' = 'asc'): readonly T[] {\n if (!key) return [...rows];\n const sign = order === 'desc' ? -1 : 1;\n const present: { readonly row: T; readonly key: SortKey }[] = [];\n const missing: T[] = [];\n for (const row of rows) {\n const value = row[key];\n if (value === null || value === undefined) missing.push(row);\n else present.push({ row, key: sortKey(value) });\n }\n // Array.prototype.sort is stable (ES2019): ties keep input order.\n present.sort((a, b) => sign * compare(a.key, b.key));\n return [...present.map((p) => p.row), ...missing];\n}\n"]}
@@ -0,0 +1,179 @@
1
+ // src/diagnostics/diagnose.ts
2
+ var SilverpointError = class extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.name = "SilverpointError";
7
+ this.code = code;
8
+ }
9
+ };
10
+ var consoleSink = (_code, message) => {
11
+ console.warn(message);
12
+ };
13
+ var sink = consoleSink;
14
+ var reported = /* @__PURE__ */ new Set();
15
+ function __setDiagnosticSink(next) {
16
+ sink = next ?? consoleSink;
17
+ reported.clear();
18
+ return () => {
19
+ sink = consoleSink;
20
+ reported.clear();
21
+ };
22
+ }
23
+ function format(code, chart, detail, template) {
24
+ const specifics = detail.message ? ` ${detail.message}` : "";
25
+ return `[${code}] ${chart}: ${template.what} (\`${detail.property}\`).${specifics} ${template.todo}. (${template.req})`;
26
+ }
27
+ var ERRORS = {
28
+ SP009: {
29
+ req: "REQ-097",
30
+ what: "a scale bound cannot be derived from the data and was not supplied",
31
+ todo: "Pass the named property explicitly"
32
+ },
33
+ SP012: {
34
+ req: "REQ-127",
35
+ what: "the ground does not reach the minimum contrast",
36
+ todo: "Recompute the palette; colours are not chosen by eye"
37
+ }
38
+ };
39
+ function diagnose(code, chart, detail) {
40
+ const error = ERRORS[code];
41
+ if (error) {
42
+ throw new SilverpointError(code, format(code, chart, detail, error));
43
+ }
44
+ if (process.env.NODE_ENV !== "production") {
45
+ developmentDiagnose(code, chart, detail);
46
+ }
47
+ }
48
+ function developmentDiagnose(code, chart, detail) {
49
+ const template = WARNINGS[code];
50
+ if (!template) return;
51
+ const message = format(code, chart, detail, template);
52
+ if (code === "SP005") {
53
+ throw new SilverpointError(code, message);
54
+ }
55
+ if (reported.has(message)) return;
56
+ reported.add(message);
57
+ sink(code, message);
58
+ }
59
+ var WARNINGS = {
60
+ SP001: {
61
+ req: "REQ-007",
62
+ what: "the dataset is empty; the ground's empty state is drawn",
63
+ todo: "Pass at least one row, or omit `data` to see the demo dataset"
64
+ },
65
+ SP002: {
66
+ req: "REQ-008",
67
+ what: "a value cannot be drawn as given (null, not finite, or outside the data contract); it is corrected or omitted",
68
+ todo: "Check the value against the chart's data contract (Data Model \xA72)"
69
+ },
70
+ SP003: {
71
+ req: "REQ-009",
72
+ what: "the container measures 0 px; the render is deferred",
73
+ todo: "Give the container a size, or pin `width` and `height`"
74
+ },
75
+ SP004: {
76
+ req: "REQ-010",
77
+ what: "the scale domain has zero length; it is expanded with the ground's domainPadding",
78
+ todo: "Nothing to do if the data is constant; otherwise check the accessor"
79
+ },
80
+ SP005: {
81
+ req: "REQ-025",
82
+ what: "more than one element is marked with white heightening; only the first is applied",
83
+ todo: "Heighten a single element per chart"
84
+ },
85
+ SP006: {
86
+ req: "REQ-026",
87
+ what: "the inker is not registered; falling back to NullInker",
88
+ todo: "Register the inker or fix the ground's `inker` token"
89
+ },
90
+ SP007: {
91
+ req: "REQ-045",
92
+ what: "the ground is not registered; falling back to silverpoint",
93
+ todo: "Call registerGround() before rendering, or fix the name"
94
+ },
95
+ SP008: {
96
+ req: "REQ-096",
97
+ what: "the data volume is above the family's threshold",
98
+ todo: "Aggregate the data before charting it"
99
+ },
100
+ SP010: {
101
+ req: "REQ-091",
102
+ what: "the chord ring has more than 12 categories",
103
+ todo: "Group the smaller categories"
104
+ },
105
+ SP011: {
106
+ req: "NFR \xA77",
107
+ what: "the path byte budget of 40 KB is exceeded",
108
+ todo: "Use `hatchFill: 'tile'` or a larger hatch gap"
109
+ },
110
+ SP014: {
111
+ req: "REQ-204",
112
+ what: "a dashboard cell spans more columns than the breakpoint has; it is clamped",
113
+ todo: "Lower the span, or give that breakpoint more columns"
114
+ },
115
+ SP015: {
116
+ req: "REQ-205",
117
+ what: "the dashboard layout and its children disagree; unmatched children are placed in source order, span 1",
118
+ todo: "Give every child a `cell` the layout declares, once"
119
+ },
120
+ SP016: {
121
+ req: "REQ-217",
122
+ what: "a chart in a linked dashboard has no field named by `link.key`; it shows no linked mark",
123
+ todo: "Link on a field every linked chart carries, or leave this chart out of the link"
124
+ },
125
+ SP017: {
126
+ req: "REQ-324",
127
+ what: "a value or a range cannot be drawn as given; it is clamped, rounded to its step or defaulted",
128
+ todo: "Keep the value within `min`..`max` and on `step`, with `min < max` and `step > 0`"
129
+ },
130
+ SP018: {
131
+ req: "REQ-319",
132
+ what: "the component has no accessible name: no text content and no `label`",
133
+ todo: "Give it visible text, or a `label` for an icon-only control"
134
+ },
135
+ SP019: {
136
+ req: "REQ-325",
137
+ what: "items share a key, or have none; the first is kept and the later ones are skipped",
138
+ todo: "Give every item a unique, non-empty `key`"
139
+ },
140
+ SP020: {
141
+ req: "REQ-437",
142
+ what: "the hierarchy is invalid (a duplicate or empty `id`, a missing `parent`, a cycle, or several roots); the offending rows are dropped",
143
+ todo: "Give every row a unique `id` and an existing `parent`, under a single root"
144
+ },
145
+ SP021: {
146
+ req: "REQ-433",
147
+ what: "a statistic parameter is invalid; its default is used",
148
+ todo: "Keep the parameter in its documented range"
149
+ },
150
+ SP022: {
151
+ req: "REQ-434",
152
+ what: "a group has too few observations for its statistic; they are drawn as points",
153
+ todo: "Give the group more observations, or expect it drawn as points"
154
+ },
155
+ SP023: {
156
+ req: "REQ-466",
157
+ what: "a palette colour is below its contrast threshold against its substrate; it is drawn as given",
158
+ todo: "Recompute the palette with checkPalette(); colours are not chosen by eye"
159
+ },
160
+ SP024: {
161
+ req: "REQ-467",
162
+ what: "a palette field is unknown, or its value is not a CSS colour; the field is dropped",
163
+ todo: "Use the fields of PALETTE_PROPERTIES with plain CSS colour values"
164
+ },
165
+ SP025: {
166
+ req: "REQ-515",
167
+ what: "@knight-lab/timelinejs could not be loaded; the fallback is rendered",
168
+ todo: "Install the optional peer @knight-lab/timelinejs and import its stylesheet"
169
+ },
170
+ SP013: {
171
+ req: "REQ-032",
172
+ what: "the @silverpoint/fonts face failed to load; rendering fell back to the system stack",
173
+ todo: "Install @silverpoint/fonts and import its stylesheet; golden images will not match until then"
174
+ }
175
+ };
176
+
177
+ export { SilverpointError, __setDiagnosticSink, diagnose };
178
+ //# sourceMappingURL=chunk-WYFRHI4S.js.map
179
+ //# sourceMappingURL=chunk-WYFRHI4S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/diagnostics/diagnose.ts"],"names":[],"mappings":"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","file":"chunk-WYFRHI4S.js","sourcesContent":["/** Stable diagnostic codes, part of the public surface (API Spec §11). */\nexport type SpCode =\n | 'SP001'\n | 'SP002'\n | 'SP003'\n | 'SP004'\n | 'SP005'\n | 'SP006'\n | 'SP007'\n | 'SP008'\n | 'SP009'\n | 'SP010'\n | 'SP011'\n | 'SP012'\n | 'SP013'\n | 'SP014'\n | 'SP015'\n | 'SP016'\n | 'SP017'\n | 'SP018'\n | 'SP019'\n | 'SP020'\n | 'SP021'\n | 'SP022'\n | 'SP023'\n | 'SP024'\n | 'SP025';\n\nexport interface Detail {\n /** The property involved. */\n readonly property: string;\n /** Specifics of this occurrence, appended to what happened. */\n readonly message?: string;\n}\n\ninterface Template {\n readonly req: string;\n readonly what: string;\n readonly todo: string;\n}\n\n/** Thrown by diagnostics of `error` severity. */\nexport class SilverpointError extends Error {\n readonly code: SpCode;\n\n constructor(code: SpCode, message: string) {\n super(message);\n this.name = 'SilverpointError';\n this.code = code;\n }\n}\n\n/** Receives every warning; replaceable so tests and tools can observe diagnostics. */\nexport type DiagnosticSink = (code: SpCode, message: string) => void;\n\nconst consoleSink: DiagnosticSink = (_code, message) => {\n console.warn(message);\n};\n\nlet sink: DiagnosticSink = consoleSink;\nconst reported = new Set<string>();\n\n/**\n * Replaces the warning sink and forgets already reported warnings. Returns a function that\n * restores the console sink.\n * @internal\n */\nexport function __setDiagnosticSink(next: DiagnosticSink | null): () => void {\n sink = next ?? consoleSink;\n reported.clear();\n return () => {\n sink = consoleSink;\n reported.clear();\n };\n}\n\nfunction format(code: SpCode, chart: string, detail: Detail, template: Template): string {\n const specifics = detail.message ? ` ${detail.message}` : '';\n return `[${code}] ${chart}: ${template.what} (\\`${detail.property}\\`).${specifics} ${template.todo}. (${template.req})`;\n}\n\n/** Always shipped: these diagnostics throw in every build (TD §5.4). */\nconst ERRORS: Partial<Record<SpCode, Template>> = {\n SP009: {\n req: 'REQ-097',\n what: 'a scale bound cannot be derived from the data and was not supplied',\n todo: 'Pass the named property explicitly',\n },\n SP012: {\n req: 'REQ-127',\n what: 'the ground does not reach the minimum contrast',\n todo: 'Recompute the palette; colours are not chosen by eye',\n },\n};\n\n/**\n * The single diagnostic channel (TD §5.4). `error` codes always throw; `warn` codes reach\n * the sink only outside production and are stripped from production bundles.\n */\nexport function diagnose(code: SpCode, chart: string, detail: Detail): void {\n const error = ERRORS[code];\n if (error) {\n throw new SilverpointError(code, format(code, chart, detail, error));\n }\n if (process.env.NODE_ENV !== 'production') {\n developmentDiagnose(code, chart, detail);\n }\n}\n\nfunction developmentDiagnose(code: SpCode, chart: string, detail: Detail): void {\n const template = WARNINGS[code];\n if (!template) return;\n const message = format(code, chart, detail, template);\n // SP005 is an error in development and a stripped warning in production (REQ-025).\n if (code === 'SP005') {\n throw new SilverpointError(code, message);\n }\n if (reported.has(message)) return;\n reported.add(message);\n sink(code, message);\n}\n\nconst WARNINGS: Partial<Record<SpCode, Template>> = {\n SP001: {\n req: 'REQ-007',\n what: 'the dataset is empty; the ground\\'s empty state is drawn',\n todo: 'Pass at least one row, or omit `data` to see the demo dataset',\n },\n SP002: {\n req: 'REQ-008',\n what: 'a value cannot be drawn as given (null, not finite, or outside the data contract); it is corrected or omitted',\n todo: 'Check the value against the chart\\'s data contract (Data Model §2)',\n },\n SP003: {\n req: 'REQ-009',\n what: 'the container measures 0 px; the render is deferred',\n todo: 'Give the container a size, or pin `width` and `height`',\n },\n SP004: {\n req: 'REQ-010',\n what: 'the scale domain has zero length; it is expanded with the ground\\'s domainPadding',\n todo: 'Nothing to do if the data is constant; otherwise check the accessor',\n },\n SP005: {\n req: 'REQ-025',\n what: 'more than one element is marked with white heightening; only the first is applied',\n todo: 'Heighten a single element per chart',\n },\n SP006: {\n req: 'REQ-026',\n what: 'the inker is not registered; falling back to NullInker',\n todo: 'Register the inker or fix the ground\\'s `inker` token',\n },\n SP007: {\n req: 'REQ-045',\n what: 'the ground is not registered; falling back to silverpoint',\n todo: 'Call registerGround() before rendering, or fix the name',\n },\n SP008: {\n req: 'REQ-096',\n what: 'the data volume is above the family\\'s threshold',\n todo: 'Aggregate the data before charting it',\n },\n SP010: {\n req: 'REQ-091',\n what: 'the chord ring has more than 12 categories',\n todo: 'Group the smaller categories',\n },\n SP011: {\n req: 'NFR §7',\n what: 'the path byte budget of 40 KB is exceeded',\n todo: \"Use `hatchFill: 'tile'` or a larger hatch gap\",\n },\n SP014: {\n req: 'REQ-204',\n what: 'a dashboard cell spans more columns than the breakpoint has; it is clamped',\n todo: 'Lower the span, or give that breakpoint more columns',\n },\n SP015: {\n req: 'REQ-205',\n what: 'the dashboard layout and its children disagree; unmatched children are placed in source order, span 1',\n todo: 'Give every child a `cell` the layout declares, once',\n },\n SP016: {\n req: 'REQ-217',\n what: 'a chart in a linked dashboard has no field named by `link.key`; it shows no linked mark',\n todo: 'Link on a field every linked chart carries, or leave this chart out of the link',\n },\n SP017: {\n req: 'REQ-324',\n what: 'a value or a range cannot be drawn as given; it is clamped, rounded to its step or defaulted',\n todo: 'Keep the value within `min`..`max` and on `step`, with `min < max` and `step > 0`',\n },\n SP018: {\n req: 'REQ-319',\n what: 'the component has no accessible name: no text content and no `label`',\n todo: 'Give it visible text, or a `label` for an icon-only control',\n },\n SP019: {\n req: 'REQ-325',\n what: 'items share a key, or have none; the first is kept and the later ones are skipped',\n todo: 'Give every item a unique, non-empty `key`',\n },\n SP020: {\n req: 'REQ-437',\n what: 'the hierarchy is invalid (a duplicate or empty `id`, a missing `parent`, a cycle, or several roots); the offending rows are dropped',\n todo: 'Give every row a unique `id` and an existing `parent`, under a single root',\n },\n SP021: {\n req: 'REQ-433',\n what: 'a statistic parameter is invalid; its default is used',\n todo: 'Keep the parameter in its documented range',\n },\n SP022: {\n req: 'REQ-434',\n what: 'a group has too few observations for its statistic; they are drawn as points',\n todo: 'Give the group more observations, or expect it drawn as points',\n },\n SP023: {\n req: 'REQ-466',\n what: 'a palette colour is below its contrast threshold against its substrate; it is drawn as given',\n todo: 'Recompute the palette with checkPalette(); colours are not chosen by eye',\n },\n SP024: {\n req: 'REQ-467',\n what: 'a palette field is unknown, or its value is not a CSS colour; the field is dropped',\n todo: 'Use the fields of PALETTE_PROPERTIES with plain CSS colour values',\n },\n SP025: {\n req: 'REQ-515',\n what: '@knight-lab/timelinejs could not be loaded; the fallback is rendered',\n todo: 'Install the optional peer @knight-lab/timelinejs and import its stylesheet',\n },\n SP013: {\n req: 'REQ-032',\n what: 'the @silverpoint/fonts face failed to load; rendering fell back to the system stack',\n todo: 'Install @silverpoint/fonts and import its stylesheet; golden images will not match until then',\n },\n};\n"]}
@@ -0,0 +1,30 @@
1
+ import { au as Palette } from './props-BZ9CcrGv.js';
2
+
3
+ /** One pair of a palette below its threshold (REQ-465). */
4
+ interface PaletteFinding {
5
+ /** The pair's name in Data Model §3.9. */
6
+ readonly pair: string;
7
+ readonly foreground: string;
8
+ readonly background: string;
9
+ /** 2 decimals. */
10
+ readonly ratio: number;
11
+ readonly threshold: number;
12
+ }
13
+ interface Pair {
14
+ readonly pair: string;
15
+ readonly threshold: number;
16
+ readonly foreground: (p: Palette) => string | undefined;
17
+ /** `undefined` measures against the substrate. */
18
+ readonly background?: (p: Palette) => string | undefined;
19
+ }
20
+ /** The pairs `checkPalette` and the contrast gate measure (Data Model §3.9), in that order. */
21
+ declare const PALETTE_PAIRS: readonly Pair[];
22
+ /** WCAG 2 contrast ratio of two hex colours (`#rgb` or `#rrggbb`), from 1 to 21. */
23
+ declare function contrastRatio(foreground: string, background: string): number;
24
+ /**
25
+ * Every pair of Data Model §3.9 whose two colours are hex and whose ratio is below its threshold.
26
+ * The substrate is the palette's, else `substrate`, else cream (REQ-465).
27
+ */
28
+ declare function checkPalette(palette: Palette, substrate?: string): readonly PaletteFinding[];
29
+
30
+ export { type PaletteFinding as P, PALETTE_PAIRS as a, contrastRatio as b, checkPalette as c };
@@ -1,5 +1,5 @@
1
- import { m as CommonChartProps } from './props-Dq8FC8GG.js';
2
- import { D as DashboardProps } from './types-B81k-s9_.js';
1
+ import { m as CommonChartProps } from './props-BZ9CcrGv.js';
2
+ import { D as DashboardProps } from './types-BT3Xm7fP.js';
3
3
 
4
4
  /** One child of a reference dashboard: the catalog chart it holds, by name, and its props. */
5
5
  interface DashboardDemoChild {
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { G as Geometry, n as Seed, o as Stroke, p as StrokePaint, q as InkMode, r as TextLabel, s as Inker, t as GroundRef, u as SubstrateName, m as CommonChartProps, v as ProviderConfig, w as LineChartProps, x as Datum, A as ActiveItem, y as Rect, z as BulletChartProps, F as PyramidChartProps, J as HeatmapChartProps, K as TreemapChartProps, O as SankeyChartProps, Q as ActivityGridProps, U as StepChartProps, X as SparklineRowsProps, Y as KpiCardProps, Z as BarChartProps, _ as StackedBarChartProps, $ as ComposedChartProps, a0 as WaterfallChartProps, a1 as FunnelChartProps, a2 as DonutChartProps, a3 as RadarChartProps, a4 as PolarBarChartProps, a5 as CoxcombChartProps, a6 as RadialArcGroupProps, a7 as RadialRingsProps, a8 as GaugeArcProps, a9 as MeterChartProps, aa as WindRoseProps, ab as ChordRingProps, ac as OrbitChartProps, ad as VolvelleChartProps, ae as CandlestickChartProps, af as AreaChartProps, ag as RangeBandChartProps, ah as StreamChartProps, ai as ScatterChartProps, aj as BubbleChartProps } from './props-Dq8FC8GG.js';
2
- export { ak as Accessor, a as BeeswarmChartProps, B as BoxPlotChartProps, b as BumpChartProps, al as ChartOrientation, C as ConnectedScatterChartProps, j as ContourChartProps, k as DelaunayChartProps, i as DensityBinChartProps, d as DivergingBarChartProps, D as DumbbellChartProps, E as EcdfChartProps, c as ErrorBarChartProps, am as Ground, an as GroundName, ao as HatchToneSpec, H as HistogramChartProps, ap as HitArea, aq as InkOptions, I as IntervalChartProps, ar as LabelKind, as as LineCurve, L as LollipopChartProps, M as MarimekkoChartProps, N as NetworkChartProps, at as NetworkNode, P as ParallelCoordinatesChartProps, g as PolarLineChartProps, h as PolarScatterChartProps, R as RidgelineChartProps, S as SlopeChartProps, e as SquarifiedTreemapProps, au as StrokePart, av as StrokeRole, f as SunburstChartProps, aw as Tile, ax as TonalRamp, ay as ToneLevel, az as ToneSpec, T as TreeChartProps, aA as UiTokens, l as VectorFieldChartProps, V as ViolinChartProps, W as WaffleChartProps, aB as WeightToneSpec } from './props-Dq8FC8GG.js';
3
- import { a as ChartModel, C as ChartRecipe } from './model-CLhtoG75.js';
4
- export { b as ChartHandle, D as DataTable, R as RecipeContext } from './model-CLhtoG75.js';
5
- import { P as PerBreakpoint, a as DashboardBreakpoint, b as DashboardLayout, R as ResolvedLayout, D as DashboardProps, c as DashboardModel, d as DashboardView, e as DashboardCellContext } from './types-B81k-s9_.js';
6
- export { f as DashboardCellLayout, g as DashboardCellProps, h as DashboardLink, i as ResolvedCell, j as ResolvedSpan } from './types-B81k-s9_.js';
1
+ import { G as Geometry, n as Seed, o as Stroke, p as StrokePaint, q as InkMode, r as TextLabel, s as Inker, t as GroundRef, u as SubstrateName, m as CommonChartProps, v as ProviderConfig, w as LineChartProps, x as Datum, A as ActiveItem, y as Rect, z as BulletChartProps, F as PyramidChartProps, J as HeatmapChartProps, K as TreemapChartProps, O as SankeyChartProps, Q as ActivityGridProps, U as StepChartProps, X as SparklineRowsProps, Y as KpiCardProps, Z as BarChartProps, _ as StackedBarChartProps, $ as ComposedChartProps, a0 as WaterfallChartProps, a1 as FunnelChartProps, a2 as DonutChartProps, a3 as RadarChartProps, a4 as PolarBarChartProps, a5 as CoxcombChartProps, a6 as RadialArcGroupProps, a7 as RadialRingsProps, a8 as GaugeArcProps, a9 as MeterChartProps, aa as WindRoseProps, ab as ChordRingProps, ac as OrbitChartProps, ad as VolvelleChartProps, ae as CandlestickChartProps, af as AreaChartProps, ag as RangeBandChartProps, ah as StreamChartProps, ai as ScatterChartProps, aj as BubbleChartProps } from './props-BZ9CcrGv.js';
2
+ export { ak as Accessor, a as BeeswarmChartProps, B as BoxPlotChartProps, b as BumpChartProps, al as ChartOrientation, C as ConnectedScatterChartProps, j as ContourChartProps, k as DelaunayChartProps, i as DensityBinChartProps, d as DivergingBarChartProps, D as DumbbellChartProps, E as EcdfChartProps, c as ErrorBarChartProps, am as Ground, an as GroundName, ao as HatchToneSpec, H as HistogramChartProps, ap as HitArea, aq as InkOptions, I as IntervalChartProps, ar as LabelKind, as as LineCurve, L as LollipopChartProps, M as MarimekkoChartProps, N as NetworkChartProps, at as NetworkNode, au as Palette, P as ParallelCoordinatesChartProps, g as PolarLineChartProps, h as PolarScatterChartProps, R as RidgelineChartProps, S as SlopeChartProps, e as SquarifiedTreemapProps, av as StrokePart, aw as StrokeRole, f as SunburstChartProps, ax as Tile, ay as TonalRamp, az as ToneLevel, aA as ToneSpec, T as TreeChartProps, aB as UiTokens, l as VectorFieldChartProps, V as ViolinChartProps, W as WaffleChartProps, aC as WeightToneSpec } from './props-BZ9CcrGv.js';
3
+ import { a as ChartModel, C as ChartRecipe } from './model-DVVt59AB.js';
4
+ export { b as ChartHandle, D as DataTable, R as RecipeContext } from './model-DVVt59AB.js';
5
+ import { P as PerBreakpoint, a as DashboardBreakpoint, b as DashboardLayout, R as ResolvedLayout, D as DashboardProps, c as DashboardModel, d as DashboardView, e as DashboardCellContext } from './types-BT3Xm7fP.js';
6
+ export { f as DashboardCellLayout, g as DashboardCellProps, h as DashboardLink, i as ResolvedCell, j as ResolvedSpan } from './types-BT3Xm7fP.js';
7
+ export { P as PaletteFinding } from './contrast-siWF_R5o.js';
7
8
 
8
9
  /** Rounds to 2 decimals, the precision of every emitted coordinate (REQ-002). */
9
10
  declare function round2(value: number): number;
@@ -137,10 +138,10 @@ declare function toSvgView(model: ChartModel, style: ViewStyle): SvgView;
137
138
  * Serialises a view to SVG markup. This is the canonical render stored with each fixture;
138
139
  * user text is always escaped, never interpolated as markup (TD §6).
139
140
  */
140
- declare function svgString(view: SvgView): string;
141
+ declare function svgString(view: SvgView, style?: string): string;
141
142
 
142
143
  /** Stable diagnostic codes, part of the public surface (API Spec §11). */
143
- type SpCode = 'SP001' | 'SP002' | 'SP003' | 'SP004' | 'SP005' | 'SP006' | 'SP007' | 'SP008' | 'SP009' | 'SP010' | 'SP011' | 'SP012' | 'SP013' | 'SP014' | 'SP015' | 'SP016' | 'SP017' | 'SP018' | 'SP019' | 'SP020' | 'SP021' | 'SP022';
144
+ type SpCode = 'SP001' | 'SP002' | 'SP003' | 'SP004' | 'SP005' | 'SP006' | 'SP007' | 'SP008' | 'SP009' | 'SP010' | 'SP011' | 'SP012' | 'SP013' | 'SP014' | 'SP015' | 'SP016' | 'SP017' | 'SP018' | 'SP019' | 'SP020' | 'SP021' | 'SP022' | 'SP023' | 'SP024' | 'SP025';
144
145
  interface Detail {
145
146
  /** The property involved. */
146
147
  readonly property: string;
@@ -541,12 +542,14 @@ declare function cellChartBox<P extends CommonChartProps>(cell: {
541
542
  * The dashboard as an adapter writes it (REQ-200, REQ-214): the section's class, substrate, name
542
543
  * and variables, the heading and description, and per cell its variables, its label and the
543
544
  * context its chart reads. `children` gives, in source order, each child's `cell` and its chart's
544
- * own `id` when the adapter can read it.
545
+ * own `id` when the adapter can read it. `palette` is the section's own palette as declarations
546
+ * (`paletteStyle`, from `@silverpoint/core/palettes`, off this entry's budget), written first in its
547
+ * style; the cells hand the palette on to their charts and components (REQ-461, REQ-462).
545
548
  */
546
549
  declare function dashboardView(props: DashboardProps, children: readonly {
547
550
  readonly cell?: string;
548
551
  readonly id?: string;
549
- }[]): DashboardView;
552
+ }[], palette?: string): DashboardView;
550
553
  /**
551
554
  * A chart's props inside a cell (API Spec §7.1, size precedence; REQ-212 config precedence): its
552
555
  * own `id`, `height` and config win; the cell supplies the rest. `width` is the width to draw at
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  import { DEFAULTS } from './chunk-KFBSQH5G.js';
2
2
  export { DEFAULTS, FORCED_PRECISION_QUERY, instanceId, resolveConfig } from './chunk-KFBSQH5G.js';
3
- import { cardLayout, modelBase, measure, emptyModel, readyModel, parseIsoDate, isoDate, createPrng, weekday } from './chunk-PD4MD7JU.js';
4
- export { addDays, createPrng, isoDate, parseIsoDate, weekday } from './chunk-PD4MD7JU.js';
5
- import { diagnose, circlePath, round2, readSeries, checkVolume, accessorName, read, formatCategory, formatValue, cartesianPlot, extent, seriesValues, valueAxis, categoryAxis, categoryLabels, formatNumber, finite, inset, rectPath, warnValue, toneOf, toneLevel, TONE_SCALE, checkCount, linearScale, legend, AXIS_BAND, PLOT_INSET, horizontalValueAxis, pillPath, checkSectors, readSectors, polarFrame, ringTones, sectorPath, pointAt, sectorLegend, RIM_LABELS, rimLabels, arcPath, ringTone, polarLabel, TICK_CHAR } from './chunk-OLYKR5PS.js';
6
- export { SilverpointError, __setDiagnosticSink, bandScale, circlePath, deriveSeed, diagnose, expandDomain, extent, fnv1a32, linearScale, max, min, resolveSeed, round2, roundGeometry, roundPathData } from './chunk-OLYKR5PS.js';
3
+ import { cardLayout, modelBase, measure, emptyModel, readyModel, parseIsoDate, isoDate, createPrng, weekday } from './chunk-E5CC2NNQ.js';
4
+ export { addDays, createPrng, isoDate, parseIsoDate, weekday } from './chunk-E5CC2NNQ.js';
5
+ import { circlePath, readSeries, checkVolume, accessorName, read, formatCategory, formatValue, cartesianPlot, extent, seriesValues, valueAxis, categoryAxis, categoryLabels, formatNumber, finite, inset, rectPath, warnValue, toneOf, toneLevel, TONE_SCALE, checkCount, linearScale, legend, AXIS_BAND, PLOT_INSET, horizontalValueAxis, pillPath, checkSectors, readSectors, polarFrame, ringTones, sectorPath, pointAt, sectorLegend, RIM_LABELS, rimLabels, arcPath, ringTone, polarLabel, TICK_CHAR } from './chunk-46QELMCG.js';
6
+ export { bandScale, circlePath, deriveSeed, expandDomain, extent, fnv1a32, linearScale, max, min, resolveSeed } from './chunk-46QELMCG.js';
7
+ import { round2 } from './chunk-5MP3BLZK.js';
8
+ export { round2, roundGeometry, roundPathData } from './chunk-5MP3BLZK.js';
9
+ import { diagnose } from './chunk-WYFRHI4S.js';
10
+ export { SilverpointError, __setDiagnosticSink, diagnose } from './chunk-WYFRHI4S.js';
7
11
  import { curveStepAfter, curveNatural, curveLinear, curveMonotoneX, line, curveStep, curveStepBefore, area } from 'd3-shape';
8
12
  import { chordDirected } from 'd3-chord';
9
13
 
@@ -114,7 +118,7 @@ function pathString(path) {
114
118
  ["fill", path.fill]
115
119
  ])}></path>`;
116
120
  }
117
- function svgString(view) {
121
+ function svgString(view, style = "") {
118
122
  const { svg } = view;
119
123
  const open = `<svg${attributes([
120
124
  ["xmlns", "http://www.w3.org/2000/svg"],
@@ -125,7 +129,9 @@ function svgString(view) {
125
129
  ["data-substrate", svg.substrate],
126
130
  ["data-mode", svg.mode],
127
131
  ["role", svg.role],
128
- ["aria-labelledby", svg.labelledby]
132
+ ["aria-labelledby", svg.labelledby],
133
+ // A palette's declarations (REQ-461): the only attribute it changes (REQ-468).
134
+ ["style", style || null]
129
135
  ])}>`;
130
136
  const title = `<title id="${escape(view.title.id)}">${escape(view.title.text)}</title>`;
131
137
  const desc = `<desc id="${escape(view.desc.id)}">${escape(view.desc.text)}</desc>`;
@@ -4193,7 +4199,7 @@ function cellChartBox(cell, chartProps, recipe) {
4193
4199
  }
4194
4200
 
4195
4201
  // src/dashboard/view.ts
4196
- function dashboardView(props, children) {
4202
+ function dashboardView(props, children, palette = "") {
4197
4203
  const model = resolveDashboard(props, children.map((c) => c.cell));
4198
4204
  if (props.title === void 0 && props.label === void 0 && process.env.NODE_ENV !== "production") {
4199
4205
  diagnose("SP002", "Dashboard", { property: "title", message: "Name the region with `title` or `label`." });
@@ -4205,7 +4211,7 @@ function dashboardView(props, children) {
4205
4211
  const heading = titled ? { level: props.headingLevel ?? DASHBOARD_DEFAULTS.headingLevel, id: `${base}-title`, text: props.title } : void 0;
4206
4212
  const description = props.description !== void 0 ? { id: `${base}-desc`, text: props.description } : void 0;
4207
4213
  const config = {};
4208
- for (const key of ["ground", "substrate", "mode", "locale"]) {
4214
+ for (const key of ["ground", "substrate", "mode", "locale", "palette"]) {
4209
4215
  if (props[key] !== void 0) config[key] = props[key];
4210
4216
  }
4211
4217
  return {
@@ -4215,7 +4221,7 @@ function dashboardView(props, children) {
4215
4221
  substrate: props.substrate ?? DEFAULTS.substrate,
4216
4222
  ...heading ? { labelledby: heading.id } : { label: props.label },
4217
4223
  ...description ? { describedby: description.id } : {},
4218
- style: model.style
4224
+ style: { ...Object.fromEntries(palette.split(";").filter(Boolean).map((d) => d.split(":"))), ...model.style }
4219
4225
  },
4220
4226
  ...heading ? { heading } : {},
4221
4227
  ...description ? { description } : {},
@@ -4232,6 +4238,11 @@ function inCell(props, cell, recipe) {
4232
4238
  const box = cellChartBox(cell.box, props, recipe);
4233
4239
  const merged = { ...props };
4234
4240
  for (const [key, value] of Object.entries(cell.config)) merged[key] ??= value;
4241
+ if (props.palette && cell.config.palette) {
4242
+ const palette = { ...cell.config.palette };
4243
+ for (const [field, value] of Object.entries(props.palette)) if (value !== void 0) palette[field] = value;
4244
+ merged.palette = palette;
4245
+ }
4235
4246
  return {
4236
4247
  props: { ...merged, id: props.id ?? cell.chartId, height: props.height ?? box.height },
4237
4248
  width: props.width ?? box.width