@krizaka/charts 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/actions-5VG352VZ.js +53 -0
- package/dist/actions-5VG352VZ.js.map +1 -0
- package/dist/bar.d.ts +3 -3
- package/dist/bar.js +7 -6
- package/dist/candlestick.d.ts +2 -2
- package/dist/candlestick.js +6 -5
- package/dist/card.d.ts +52 -0
- package/dist/card.js +19 -0
- package/dist/card.js.map +1 -0
- package/dist/{cartesian-BRhNQ3ib.d.ts → cartesian-CEY_wwe_.d.ts} +12 -2
- package/dist/chart.d.ts +2 -2
- package/dist/chart.js +5 -4
- package/dist/{chunk-BV4DBGN7.js → chunk-7W4T255Q.js} +4 -4
- package/dist/{chunk-W5ILLSPK.js → chunk-AGSSNMK5.js} +5 -5
- package/dist/{chunk-VKZZY2QD.js → chunk-FE4LUGAE.js} +5 -5
- package/dist/{chunk-ARARFMNE.js → chunk-FIQHMJZK.js} +5 -5
- package/dist/chunk-FIQHMJZK.js.map +1 -0
- package/dist/{chunk-ANUCSRUN.js → chunk-GD7TWEN3.js} +3 -3
- package/dist/chunk-GRRFPI27.js +89 -0
- package/dist/chunk-GRRFPI27.js.map +1 -0
- package/dist/{chunk-SLEJDQ3A.js → chunk-HH65IEUV.js} +3 -3
- package/dist/{chunk-OIRHLJBC.js → chunk-IJTI6VJD.js} +3 -3
- package/dist/{chunk-WVTIKOII.js → chunk-IURCLBUQ.js} +2 -2
- package/dist/{chunk-CVWSMUUB.js → chunk-JST4HJC3.js} +33 -15
- package/dist/chunk-JST4HJC3.js.map +1 -0
- package/dist/{chunk-IKQV3NSL.js → chunk-KERGFVSN.js} +3 -3
- package/dist/{chunk-XDDALY4C.js → chunk-KMQ7RANJ.js} +5 -5
- package/dist/{chunk-NCIQMRV3.js → chunk-LLUQEK5J.js} +5 -5
- package/dist/{chunk-AA5EWWYV.js → chunk-LZPZWBBY.js} +2 -2
- package/dist/{chunk-PBQV3B6O.js → chunk-MK2ZFUWM.js} +31 -16
- package/dist/chunk-MK2ZFUWM.js.map +1 -0
- package/dist/{chunk-CSSZLFLO.js → chunk-MRGMLDNS.js} +5 -5
- package/dist/{chunk-I3D7KUGN.js → chunk-NLTZWJLV.js} +3 -3
- package/dist/{chunk-PWMMXRMC.js → chunk-NV52AKHG.js} +3 -3
- package/dist/{chunk-MXLITIGU.js → chunk-NWJ5VDN7.js} +5 -5
- package/dist/{chunk-3CJHBJXA.js → chunk-OVASCEGF.js} +12 -73
- package/dist/chunk-OVASCEGF.js.map +1 -0
- package/dist/{chunk-EQLC2QVN.js → chunk-OZOAKP5F.js} +4 -4
- package/dist/chunk-OZOAKP5F.js.map +1 -0
- package/dist/{chunk-KNDHO67X.js → chunk-P2NK5L3B.js} +3 -3
- package/dist/{chunk-JTKR7ZWP.js → chunk-P6RS2L23.js} +140 -36
- package/dist/chunk-P6RS2L23.js.map +1 -0
- package/dist/{chunk-W5FX4TU3.js → chunk-PGD6SH5I.js} +30 -2
- package/dist/chunk-PGD6SH5I.js.map +1 -0
- package/dist/{chunk-4LBXEAGC.js → chunk-PWZHIGPO.js} +5 -5
- package/dist/{chunk-L2EKYWVI.js → chunk-VEOJNMPF.js} +3 -3
- package/dist/chunk-YHQFW2PR.js +71 -0
- package/dist/chunk-YHQFW2PR.js.map +1 -0
- package/dist/{chunk-C4MFZLJM.js → chunk-Z4T3JFNU.js} +2 -2
- package/dist/{chunk-EEP7PS2L.js → chunk-ZF7LVQTR.js} +3 -3
- package/dist/{context-BgYUymEO.d.ts → context-DNW7bJYw.d.ts} +19 -0
- package/dist/credits.d.ts +1 -1
- package/dist/credits.js +7 -6
- package/dist/earnings.d.ts +3 -3
- package/dist/earnings.js +8 -7
- package/dist/{frame-I7_xYGy5.d.ts → frame-B1HDNm7c.d.ts} +9 -5
- package/dist/funnel.d.ts +2 -2
- package/dist/funnel.js +6 -5
- package/dist/gauge.d.ts +2 -2
- package/dist/gauge.js +4 -3
- package/dist/geo.d.ts +2 -2
- package/dist/geo.js +5 -4
- package/dist/globe.d.ts +2 -2
- package/dist/globe.js +4 -3
- package/dist/goal.d.ts +2 -2
- package/dist/goal.js +5 -4
- package/dist/heatmap.d.ts +2 -2
- package/dist/heatmap.js +6 -5
- package/dist/index.d.ts +5 -3
- package/dist/index.js +45 -37
- package/dist/latency.d.ts +3 -3
- package/dist/latency.js +8 -7
- package/dist/line.d.ts +3 -3
- package/dist/line.js +7 -6
- package/dist/native.d.ts +19 -0
- package/dist/native.js +13 -1
- package/dist/native.js.map +1 -1
- package/dist/pie.d.ts +2 -2
- package/dist/pie.js +6 -5
- package/dist/provider.d.ts +2 -2
- package/dist/provider.js +4 -2
- package/dist/radar.d.ts +2 -2
- package/dist/radar.js +6 -5
- package/dist/sankey.d.ts +2 -2
- package/dist/sankey.js +6 -5
- package/dist/scatter.d.ts +2 -2
- package/dist/scatter.js +6 -5
- package/dist/sparkline.d.ts +2 -2
- package/dist/sparkline.js +6 -5
- package/dist/table-sheet-CQBIAV5N.js +36 -0
- package/dist/table-sheet-CQBIAV5N.js.map +1 -0
- package/dist/throughput.d.ts +3 -3
- package/dist/throughput.js +8 -7
- package/dist/ticker.d.ts +3 -3
- package/dist/ticker.js +8 -7
- package/dist/treemap.d.ts +2 -2
- package/dist/treemap.js +7 -6
- package/package.json +295 -53
- package/registry/area-chart.json +82 -12
- package/registry/bar-chart.json +82 -12
- package/registry/calendar-heatmap.json +46 -18
- package/registry/candlestick.json +46 -18
- package/registry/chart-card.json +235 -0
- package/registry/chart.json +40 -12
- package/registry/charts-provider.json +2 -2
- package/registry/earnings-chart.json +82 -12
- package/registry/examples/chart-card/before-after.d.ts +4 -0
- package/registry/examples/chart-card/before-after.js +22 -0
- package/registry/examples/chart-card/before-after.tsx +22 -0
- package/registry/examples/chart-card/jobs-activity.d.ts +4 -0
- package/registry/examples/chart-card/jobs-activity.js +20 -0
- package/registry/examples/chart-card/jobs-activity.tsx +20 -0
- package/registry/examples/chart-card/sparse-and-empty.d.ts +4 -0
- package/registry/examples/chart-card/sparse-and-empty.js +16 -0
- package/registry/examples/chart-card/sparse-and-empty.tsx +18 -0
- package/registry/examples/chart-card/usage-donut.d.ts +4 -0
- package/registry/examples/chart-card/usage-donut.js +18 -0
- package/registry/examples/chart-card/usage-donut.tsx +18 -0
- package/registry/examples/charts-provider/french-orazaka.js +1 -1
- package/registry/examples/charts-provider/french-orazaka.tsx +1 -1
- package/registry/examples/kpi-stat/dashboard-row.d.ts +4 -0
- package/registry/examples/kpi-stat/dashboard-row.js +19 -0
- package/registry/examples/kpi-stat/dashboard-row.tsx +17 -0
- package/registry/examples/kpi-stat/single.d.ts +4 -0
- package/registry/examples/kpi-stat/single.js +11 -0
- package/registry/examples/kpi-stat/single.tsx +6 -0
- package/registry/funnel.json +46 -18
- package/registry/gauge.json +42 -14
- package/registry/geo-map.json +46 -18
- package/registry/globe.json +40 -12
- package/registry/goal-progress.json +36 -8
- package/registry/heatmap.json +46 -18
- package/registry/index.json +49 -1
- package/registry/job-throughput.json +82 -12
- package/registry/kpi-stat.json +296 -0
- package/registry/latency-chart.json +82 -12
- package/registry/line-chart.json +82 -12
- package/registry/pie-chart.json +92 -36
- package/registry/price-ticker.json +82 -12
- package/registry/radar-chart.json +46 -18
- package/registry/sankey.json +46 -18
- package/registry/scatter-chart.json +46 -18
- package/registry/sparkline.json +38 -10
- package/registry/treemap.json +40 -12
- package/dist/chunk-3CJHBJXA.js.map +0 -1
- package/dist/chunk-ARARFMNE.js.map +0 -1
- package/dist/chunk-CVWSMUUB.js.map +0 -1
- package/dist/chunk-EQLC2QVN.js.map +0 -1
- package/dist/chunk-JTKR7ZWP.js.map +0 -1
- package/dist/chunk-PBQV3B6O.js.map +0 -1
- package/dist/chunk-W5FX4TU3.js.map +0 -1
- /package/dist/{chunk-BV4DBGN7.js.map → chunk-7W4T255Q.js.map} +0 -0
- /package/dist/{chunk-W5ILLSPK.js.map → chunk-AGSSNMK5.js.map} +0 -0
- /package/dist/{chunk-VKZZY2QD.js.map → chunk-FE4LUGAE.js.map} +0 -0
- /package/dist/{chunk-ANUCSRUN.js.map → chunk-GD7TWEN3.js.map} +0 -0
- /package/dist/{chunk-SLEJDQ3A.js.map → chunk-HH65IEUV.js.map} +0 -0
- /package/dist/{chunk-OIRHLJBC.js.map → chunk-IJTI6VJD.js.map} +0 -0
- /package/dist/{chunk-WVTIKOII.js.map → chunk-IURCLBUQ.js.map} +0 -0
- /package/dist/{chunk-IKQV3NSL.js.map → chunk-KERGFVSN.js.map} +0 -0
- /package/dist/{chunk-XDDALY4C.js.map → chunk-KMQ7RANJ.js.map} +0 -0
- /package/dist/{chunk-NCIQMRV3.js.map → chunk-LLUQEK5J.js.map} +0 -0
- /package/dist/{chunk-AA5EWWYV.js.map → chunk-LZPZWBBY.js.map} +0 -0
- /package/dist/{chunk-CSSZLFLO.js.map → chunk-MRGMLDNS.js.map} +0 -0
- /package/dist/{chunk-I3D7KUGN.js.map → chunk-NLTZWJLV.js.map} +0 -0
- /package/dist/{chunk-PWMMXRMC.js.map → chunk-NV52AKHG.js.map} +0 -0
- /package/dist/{chunk-MXLITIGU.js.map → chunk-NWJ5VDN7.js.map} +0 -0
- /package/dist/{chunk-KNDHO67X.js.map → chunk-P2NK5L3B.js.map} +0 -0
- /package/dist/{chunk-4LBXEAGC.js.map → chunk-PWZHIGPO.js.map} +0 -0
- /package/dist/{chunk-L2EKYWVI.js.map → chunk-VEOJNMPF.js.map} +0 -0
- /package/dist/{chunk-C4MFZLJM.js.map → chunk-Z4T3JFNU.js.map} +0 -0
- /package/dist/{chunk-EEP7PS2L.js.map → chunk-ZF7LVQTR.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/web/hooks.ts","../src/web/parts.tsx","../src/web/styles.tsx","../src/web/frame.tsx","../src/web/export.ts"],"sourcesContent":["\"use client\";\n// The browser facts a chart reacts to: its width (ResizeObserver), whether it is on screen (IntersectionObserver),\n// the reader's motion preference, the theme, and whether it runs in the browser at all (SSR renders a placeholder).\nimport { type RefObject, useEffect, useState, useSyncExternalStore } from \"react\";\n\n/** The element's content width, rounded; 0 until measured (on the server, before the first layout). */\nexport function useWidth(ref: RefObject<HTMLElement | null>): number {\n const [width, setWidth] = useState(0);\n useEffect(() => {\n const el = ref.current;\n if (!el) return undefined;\n const measure = () => setWidth(Math.round(el.getBoundingClientRect().width));\n measure();\n if (typeof ResizeObserver === \"undefined\") return undefined;\n // Coalesced to one frame: a drag of a window does not redraw the chart a hundred times.\n let frame = 0;\n const observer = new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(measure);\n });\n observer.observe(el);\n return () => {\n cancelAnimationFrame(frame);\n observer.disconnect();\n };\n }, [ref]);\n return width;\n}\n\n/**\n * Whether the element is on screen (with a margin): an entrance waits for it, a loop pauses outside it. `once` keeps\n * `true` after the first sight (entrances); otherwise it follows the element (loops). True where it cannot be known.\n */\nexport function useInView(ref: RefObject<HTMLElement | null>, { once = false, margin = \"120px\" } = {}): boolean {\n // Without IntersectionObserver (an old runtime, a test DOM), everything counts as on screen.\n const [inView, setInView] = useState(() => typeof window !== \"undefined\" && typeof IntersectionObserver === \"undefined\");\n useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === \"undefined\") return undefined;\n const observer = new IntersectionObserver(\n ([entry]) => {\n const visible = Boolean(entry?.isIntersecting);\n setInView(visible);\n if (visible && once) observer.disconnect();\n },\n { rootMargin: margin },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref, once, margin]);\n return inView;\n}\n\nconst REDUCE = \"(prefers-reduced-motion: reduce)\";\nconst subscribeMotion = (notify: () => void) => {\n if (typeof matchMedia === \"undefined\") return () => {};\n const query = matchMedia(REDUCE);\n query.addEventListener(\"change\", notify);\n return () => query.removeEventListener(\"change\", notify);\n};\n\n/** Whether the reader asked for reduced motion (false on the server: the CSS guards the entrances anyway). */\nexport function useReducedMotion(): boolean {\n return useSyncExternalStore(\n subscribeMotion,\n () => typeof matchMedia !== \"undefined\" && matchMedia(REDUCE).matches,\n () => false,\n );\n}\n\n/** Increments on every theme change (`html` class, style or `data-theme`, and the OS scheme): canvas charts re-read their colours. */\nexport function useThemeVersion(): number {\n const [version, setVersion] = useState(0);\n useEffect(() => {\n const bump = () => setVersion((v) => v + 1);\n const observer = new MutationObserver(bump);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\", \"style\", \"data-theme\"] });\n observer.observe(document.body, { attributes: true, attributeFilter: [\"class\", \"style\", \"data-theme\"] });\n const query = typeof matchMedia === \"undefined\" ? null : matchMedia(\"(prefers-color-scheme: dark)\");\n query?.addEventListener(\"change\", bump);\n return () => {\n observer.disconnect();\n query?.removeEventListener(\"change\", bump);\n };\n }, []);\n return version;\n}\n\nconst noop = () => () => {};\n/** False during the server render and the hydration pass, true after: what only the browser can draw waits for it. */\nexport function useMounted(): boolean {\n return useSyncExternalStore(\n noop,\n () => true,\n () => false,\n );\n}\n","// The small pieces every chart shares: a series' colour, the legend and the tooltip (the surface of @krizaka/ui's\n// floating elements: raised surface, border, large shadow; text in the text roles, the colour on a key beside it).\nimport { type ReactNode, useCallback, useState } from \"react\";\n\nimport type { SeriesColor, Tone } from \"../core/types\";\n\n/** Joins class names, skipping the empty ones. */\nexport const cx = (...names: (string | false | null | undefined)[]) => names.filter(Boolean).join(\" \");\n\nconst TONES: Record<Tone, string> = {\n neutral: \"var(--kz-text-secondary)\",\n accent: \"var(--kz-accent)\",\n success: \"var(--kz-success)\",\n warning: \"var(--kz-warning)\",\n // A failure is stated, not shouted: the danger hue eased toward the muted text so a block of it stays calm.\n danger: \"color-mix(in oklab, var(--kz-danger) 78%, var(--kz-text-muted))\",\n info: \"var(--kz-info)\",\n};\n\n/** The CSS colour of a series: its own (`color`), else its palette slot, `var(--kzc-<slot>)`. */\nexport function colorOf(color: SeriesColor | undefined, slot: number): string {\n if (color === undefined) return `var(--kzc-${((slot - 1) % 8) + 1})`;\n if (typeof color === \"number\") return `var(--kzc-${color})`;\n if (color in TONES) return TONES[color as Tone];\n return color;\n}\n\nexport interface LegendItem {\n readonly label: string;\n readonly color: string;\n readonly shape?: \"square\" | \"line\";\n readonly dashed?: boolean;\n /** Written after the name, muted: a value or a share (`42 %`). */\n readonly detail?: string;\n}\n\nexport interface LegendProps {\n readonly items: readonly LegendItem[];\n /** Labels that are switched off (their chip reads as off). */\n readonly off?: ReadonlySet<string>;\n /** Makes the chips buttons that switch a series on and off. */\n readonly onToggle?: (label: string) => void;\n /** The chip's accessible name when it is a button: `Show or hide {label}`. */\n readonly toggleName?: (label: string) => string;\n /** Show it even for a single item (a donut's parts). Default: from two items. */\n readonly always?: boolean;\n}\n\n/**\n * The legend: a key in the series' colour beside its name in the text colour. Shown from two series. With `onToggle`\n * the chips are buttons that filter the chart (`aria-pressed`); the last visible one cannot be switched off.\n */\nexport function Legend({ items, off, onToggle, toggleName, always }: LegendProps) {\n if (items.length < 2 && !always) return null;\n const live = items.filter((item) => !off?.has(item.label)).length;\n return (\n <ul className=\"kzc-legend\" aria-hidden={onToggle ? undefined : true}>\n {items.map((item) => {\n const isOff = off?.has(item.label) ?? false;\n const key = (\n <span\n className=\"kzc-key\"\n data-shape={item.shape}\n style={{ background: item.dashed ? `repeating-linear-gradient(90deg, ${item.color} 0 4px, transparent 4px 7px)` : item.color }}\n />\n );\n const text = (\n <>\n {item.label}\n {item.detail && <span className=\"kzc-legend-detail\">{item.detail}</span>}\n </>\n );\n return (\n <li key={item.label}>\n {onToggle ? (\n <button\n type=\"button\"\n className=\"kzc-chip\"\n aria-pressed={!isOff}\n title={toggleName?.(item.label)}\n disabled={!isOff && live <= 1}\n onClick={() => onToggle(item.label)}\n >\n {key}\n {text}\n </button>\n ) : (\n <>\n {key}\n {text}\n </>\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n\n/** The switched-off labels of a legend: `off` and `toggle`. */\nexport function useToggles(): { off: ReadonlySet<string>; toggle: (label: string) => void } {\n const [off, setOff] = useState<ReadonlySet<string>>(() => new Set());\n const toggle = useCallback((label: string) => {\n setOff((current) => {\n const next = new Set(current);\n if (next.has(label)) next.delete(label);\n else next.add(label);\n return next;\n });\n }, []);\n return { off, toggle };\n}\n\nexport interface TooltipRow {\n readonly label: string;\n readonly value: string;\n readonly color?: string;\n readonly shape?: \"square\" | \"line\";\n}\n\nexport interface TooltipProps {\n /** Where the pointer or the active point is, in the plot's pixels. */\n readonly x: number;\n readonly y: number;\n /** The plot's width: the tooltip flips to the left of the point past the middle. */\n readonly width: number;\n readonly title?: string;\n readonly rows: readonly TooltipRow[];\n readonly note?: ReactNode;\n}\n\n/** The rich tooltip: a title (the category), one row per series (key, name, value), an optional note. */\nexport function Tooltip({ x, y, width, title, rows, note }: TooltipProps) {\n const flip = x > width / 2;\n return (\n <div className=\"kzc-tip\" aria-hidden style={{ left: flip ? x - 12 : x + 12, top: Math.max(0, y - 12), transform: flip ? \"translateX(-100%)\" : undefined }}>\n {title && <p className=\"kzc-tip-title\">{title}</p>}\n {rows.map((row, i) => (\n <p key={i} className=\"kzc-tip-row\">\n {row.color ? <span className=\"kzc-key\" data-shape={row.shape} style={{ background: row.color }} /> : <span />}\n <span>{row.label}</span>\n <b>{row.value}</b>\n </p>\n ))}\n {note && <p className=\"kzc-tip-note\">{note}</p>}\n </div>\n );\n}\n\n/**\n * The colour of step `i` of `n` of a sequential scale: the brand hue (slot 1) mixed into the surface in OKLab, from\n * 22 % (still distinct from the surface) to 100 % — the same steps as `sequential()` for the canvas engine.\n */\nexport const stepColor = (i: number, n: number) => `color-mix(in oklab, var(--kzc-1) ${Math.round(22 + (78 * i) / Math.max(1, n - 1))}%, var(--kz-surface-1))`;\n\n/** The legend of a sequential scale: its lowest value, the steps from near the surface to the full hue, its highest. */\nexport function RampLegend({ min, max, steps, write }: { min: number; max: number; steps: number; write: (v: number) => string }) {\n return (\n <div className=\"kzc-legend\" aria-hidden>\n <span>{write(min)}</span>\n <span style={{ display: \"inline-flex\", gap: 2 }}>\n {Array.from({ length: steps }, (_, i) => (\n <span key={i} className=\"kzc-key\" style={{ background: stepColor(i, steps), width: 14 }} />\n ))}\n </span>\n <span>{write(max)}</span>\n </div>\n );\n}\n","// The charts' own stylesheet: plain CSS with `kzc-` classes on the --kz-* roles, so a chart needs nothing but the\n// tokens an app already loads (no Tailwind source to declare, no CSS import). Rendered once per document through\n// React 19's stylesheet hoisting (`<style href precedence>`, deduplicated, server-rendered in <head>).\n//\n// The palette is `light-dark()`: it follows the `color-scheme` the tokens set (`:root`/`.theme-dark` dark,\n// `html.light`/`.theme-light` light) — a theme switch repaints every chart with no JavaScript. The brand's order comes\n// from a `.brand-<id>` ancestor or the chart's own `data-brand`.\nimport { HUES, ORDERS } from \"../core/palette\";\nimport type { BrandId } from \"../core/types\";\n\nconst slots = (brand: BrandId) =>\n ORDERS[brand].map((hue, i) => `--kzc-${i + 1}:light-dark(${HUES[hue].light},${HUES[hue].dark});`).join(\"\");\n\nconst PALETTE = [\n `[data-kzc]{${slots(\"krizaka\")}--kzc-low:light-dark(${HUES.blue.light},${HUES.blue.dark});--kzc-high:light-dark(${HUES.red.light},${HUES.red.dark});}`,\n ...([\"orazaka\", \"orochia\", \"krizaka\"] as const).map((brand) => `:where(.brand-${brand}) [data-kzc]{${slots(brand)}}`),\n ...([\"orazaka\", \"orochia\", \"krizaka\"] as const).map((brand) => `[data-kzc][data-brand=${brand}]{${slots(brand)}}`),\n].join(\"\");\n\nconst tone = (name: string, value: string) => `.kzc [data-tone=${name}]{--kzc-tone:${value}}`;\n\nexport const CSS = `${PALETTE}\n.kzc{--kzc-text:var(--kz-text-primary);--kzc-text-2:var(--kz-text-secondary);--kzc-text-3:var(--kz-text-muted);--kzc-grid:var(--kz-border-subtle);--kzc-axis:var(--kz-border-default);--kzc-surface:var(--kz-surface-1);--kzc-tone:var(--kz-text-secondary);margin:0;min-width:0;display:flex;flex-direction:column;gap:8px;color:var(--kzc-text);font-family:var(--kz-font-sans,system-ui,sans-serif);font-variant-numeric:tabular-nums}\n${tone(\"neutral\", \"var(--kz-text-secondary)\")}${tone(\"accent\", \"var(--kz-accent)\")}${tone(\"success\", \"var(--kz-success)\")}${tone(\"warning\", \"var(--kz-warning)\")}${tone(\"danger\", \"var(--kz-danger)\")}${tone(\"info\", \"var(--kz-info)\")}\n.kzc-head{display:flex;align-items:flex-start;justify-content:space-between;gap:4px 12px}\n.kzc-heading{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}\n.kzc-title{margin:0;font-family:var(--kz-font-display,inherit);font-size:14px;font-weight:600;line-height:20px;color:var(--kzc-text)}\n.kzc-heading[data-insight] .kzc-title{font-family:var(--kz-font-sans,inherit);font-size:12px;line-height:16px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--kzc-text-2)}\n.kzc-insight{margin:2px 0 0;font-family:var(--kz-font-display,inherit);font-size:20px;line-height:26px;font-weight:700;letter-spacing:-.01em;color:var(--kzc-text);font-variant-numeric:tabular-nums}\n.kzc-note{margin:0;font-size:12px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-desc{margin:0;font-size:13px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-tools{display:flex;flex-wrap:wrap;flex:none;align-items:center;justify-content:flex-end;gap:4px;max-width:100%}\n.kzc-more{appearance:none;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin:-4px -4px 0 0;padding:0;border:0;border-radius:var(--kz-radius-md,8px);background:transparent;color:var(--kzc-text-2);cursor:pointer;transition:background-color .15s,color .15s}\n.kzc-more:hover:not(:disabled){background:var(--kz-surface-2);color:var(--kzc-text)}\n.kzc-more:disabled{cursor:default;opacity:.7}\n.kzc-more:focus-visible{outline:2px solid var(--kz-ring);outline-offset:2px}\n.kzc-more svg{width:18px;height:18px}\n.kzc-btn{appearance:none;display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 10px;border:1px solid var(--kz-border-default);border-radius:var(--kz-radius-md,8px);background:transparent;color:var(--kzc-text-2);font:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:background-color .15s,color .15s}\n.kzc-btn:hover{background:var(--kz-surface-2);color:var(--kzc-text)}\n.kzc-btn:focus-visible,.kzc-plot:focus-visible{outline:2px solid var(--kz-ring);outline-offset:2px}\n.kzc-btn[aria-pressed=true]{background:var(--kz-surface-3);color:var(--kzc-text)}\n.kzc-plot{position:relative;width:100%;border-radius:var(--kz-radius-md,8px);outline:none}\n.kzc-plot svg{display:block;overflow:visible}\n.kzc-svg text{fill:var(--kzc-text-2);font-size:11px;font-family:inherit}\n.kzc-svg .kzc-strong{fill:var(--kzc-text);font-weight:600}\n.kzc-grid{stroke:var(--kzc-grid);stroke-width:1;shape-rendering:crispEdges}\n.kzc-axis{stroke:var(--kzc-axis);stroke-width:1;shape-rendering:crispEdges}\n.kzc-threshold{stroke:var(--kzc-tone);stroke-width:1.5;stroke-dasharray:6 4}\n.kzc-threshold-label{fill:var(--kzc-text)!important;font-weight:600;paint-order:stroke;stroke:var(--kzc-surface);stroke-width:3px;stroke-linejoin:round}\n.kzc-cursor{stroke:var(--kzc-axis);stroke-width:1}\n.kzc-line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}\n.kzc-area{stroke:none;opacity:.14}\n.kzc-dot{stroke:var(--kzc-surface);stroke-width:2}\n.kzc-mark{transition:opacity .15s}\n.kzc[data-active] .kzc-mark[data-dim]{opacity:.35}\n.kzc-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:0;padding:0;list-style:none;font-size:12px;color:var(--kzc-text-2)}\n.kzc-legend li{display:inline-flex;align-items:center;gap:6px}\n.kzc-legend-detail{margin-left:2px;color:var(--kzc-text-2)}\n.kzc-chip{appearance:none;display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 10px;border:1px solid var(--kz-border-default);border-radius:999px;background:transparent;color:var(--kzc-text);font:inherit;font-size:12px;cursor:pointer;transition:background-color .15s,color .15s,border-color .15s,opacity .15s}\n.kzc-chip:hover:not(:disabled){background:var(--kz-surface-2)}\n.kzc-chip[aria-pressed=false]{color:var(--kzc-text-2);border-style:dashed}\n.kzc-chip[aria-pressed=false] .kzc-key{opacity:.35}\n.kzc-chip:disabled{cursor:default}\n.kzc-chip:focus-visible{outline:2px solid var(--kz-ring);outline-offset:2px}\n.kzc-key{width:10px;height:10px;border-radius:3px;flex:none}\n.kzc-key[data-shape=line]{height:3px;border-radius:2px;width:14px}\n.kzc-tip{animation:none;position:absolute;z-index:2;pointer-events:none;min-width:140px;max-width:260px;padding:8px 10px;border:1px solid var(--kz-border-default);border-radius:var(--kz-radius-lg,10px);background:var(--kz-surface-2);color:var(--kzc-text);box-shadow:var(--kz-shadow-lg);font-size:12px;line-height:18px}\n.kzc-tip-title{margin:0 0 4px;font-weight:600;color:var(--kzc-text)}\n.kzc-tip-row{display:flex;align-items:center;gap:8px;margin:0}\n.kzc-tip-row span:nth-child(2){flex:1;color:var(--kzc-text-2)}\n.kzc-tip-row b{font-weight:600}\n.kzc-tip-note{margin:4px 0 0;color:var(--kzc-text-3)}\n.kzc-summary{margin:0;font-size:12px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-sr{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}\n.kzc-table-wrap{max-height:320px;overflow:auto;border:1px solid var(--kz-border-subtle);border-radius:var(--kz-radius-md,8px)}\n.kzc-table{width:100%;border-collapse:collapse;font-size:12px}\n.kzc-table caption{padding:8px 10px;text-align:left;font-weight:600;color:var(--kzc-text)}\n.kzc-table th,.kzc-table td{padding:6px 10px;border-top:1px solid var(--kz-border-subtle);text-align:right;white-space:nowrap}\n.kzc-table th[scope=row],.kzc-table thead th:first-child{text-align:left;font-weight:500;color:var(--kzc-text)}\n.kzc-table thead th{position:sticky;top:0;background:var(--kz-surface-1);color:var(--kzc-text-2);font-weight:500}\n.kzc-state{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:16px;text-align:center;font-size:13px;line-height:18px;color:var(--kzc-text-2);background:color-mix(in oklab,var(--kz-surface-2) 55%,transparent);border-radius:var(--kz-radius-lg,10px)}\n.kzc-state svg{width:28px;height:28px;color:var(--kzc-text-3)}\n.kzc-state[data-state=error]{color:var(--kz-danger-text,var(--kzc-text))}\n.kzc-skeleton{position:absolute;inset:0;display:flex;align-items:flex-end;gap:6%;padding:12px 4% 24px;border-radius:var(--kz-radius-lg,10px);overflow:hidden}\n.kzc-skeleton i{flex:1;border-radius:4px 4px 0 0;background:var(--kz-surface-2)}\n.kzc-live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}\n.kzc-host{position:absolute;inset:0}\n.kzc-host>div{border-radius:inherit}\n.kzc-kpi{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;margin-top:4px}\n.kzc-kpi-value{font-family:var(--kz-font-display,inherit);font-size:24px;line-height:30px;font-weight:800;letter-spacing:-.01em;color:var(--kzc-text)}\n.kzc-kpi-label{font-size:13px;color:var(--kzc-text-2)}\n.kzc-kpi-delta{display:inline-flex;align-items:center;gap:4px;font-size:13px;font-weight:600;color:var(--kzc-text)}\n.kzc-kpi-delta svg{width:12px;height:12px;flex:none;color:var(--kzc-tone)}\n.kzc-kpistat{min-width:0}\n.kzc-kpistat[data-good=down] [data-trend=up] svg{color:var(--kz-danger)}\n.kzc-kpistat[data-good=down] [data-trend=down] svg{color:var(--kz-success)}\n.kzc-card{min-width:0}\n.kzc-card-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:4px 12px;margin:12px 0 0;padding-top:10px;border-top:1px solid var(--kz-border-subtle);font-size:12px;line-height:18px;color:var(--kzc-text-3)}\n.kzc-meter{position:relative;height:10px;border-radius:999px;background:var(--kz-surface-3);overflow:hidden;--kzc-tone:var(--kz-accent)}\n.kzc-meter>i{position:absolute;inset:0 auto 0 0;border-radius:inherit;background:var(--kzc-tone);transition:width .6s var(--kz-ease,ease-out)}\n.kzc-meter[data-tone=warning]{--kzc-tone:var(--kz-warning)}.kzc-meter[data-tone=danger]{--kzc-tone:var(--kz-danger)}\n.kzc-row{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px;margin:0;font-size:12px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-row b{font-weight:600;color:var(--kzc-text)}\n@media (prefers-reduced-motion:no-preference){\n.kzc-skeleton i{animation:kzc-pulse 1.6s ease-in-out infinite}\n.kzc[data-inview] .kzc-enter-line{stroke-dasharray:1;stroke-dashoffset:1;animation:kzc-draw .9s var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-fade{opacity:0;animation:kzc-fade .6s .3s var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-grow{transform:scaleY(0);transform-box:fill-box;transform-origin:bottom;animation:kzc-grow .6s calc(min(var(--kzc-i,0),24)*22ms) var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-grow[data-negative]{transform-origin:top}\n.kzc[data-inview] .kzc-enter-growx{transform:scaleX(0);transform-box:fill-box;transform-origin:left;animation:kzc-growx .6s calc(min(var(--kzc-i,0),24)*22ms) var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-growx[data-negative]{transform-origin:right}\n.kzc[data-inview] .kzc-enter-pop{opacity:0;transform:scale(.92);transform-box:view-box;transform-origin:center;animation:kzc-pop .6s var(--kz-ease,ease-out) forwards}\n.kzc:not([data-inview]) .kzc-enter-line,.kzc:not([data-inview]) .kzc-enter-fade,.kzc:not([data-inview]) .kzc-enter-grow,.kzc:not([data-inview]) .kzc-enter-growx,.kzc:not([data-inview]) .kzc-enter-pop{visibility:hidden}\n.kzc[data-live] *{animation:none!important}\n.kzc[data-live] .kzc-enter-line{stroke-dasharray:none;stroke-dashoffset:0}\n.kzc[data-live] :is(.kzc-enter-fade,.kzc-enter-grow,.kzc-enter-growx,.kzc-enter-pop){opacity:1;transform:none;visibility:visible}\n}\n@keyframes kzc-draw{to{stroke-dashoffset:0}}\n@keyframes kzc-fade{to{opacity:1}}\n@keyframes kzc-grow{to{transform:scaleY(1)}}\n@keyframes kzc-growx{to{transform:scaleX(1)}}\n@keyframes kzc-pop{to{opacity:1;transform:none}}\n@keyframes kzc-pulse{50%{opacity:.5}}\n@media (forced-colors:active){.kzc-line{stroke:CanvasText}.kzc-key{forced-color-adjust:none}}\n`.replace(/\\n/g, \"\");\n\n/** The stylesheet, once per document (React 19 hoists and deduplicates it, on the server too). */\nexport function ChartStyles() {\n return (\n <style href=\"krizaka-charts\" precedence=\"default\">\n {CSS}\n </style>\n );\n}\n","\"use client\";\n// The frame every web chart is drawn in — where the \"better than the industry\" promises live, once for all of them:\n// - a title (the accessible name) and a description; a written summary (min, max, trend) read by screen readers, or\n// shown (`summary=\"visible\"`);\n// - the data table, always in the page for assistive technology (visually hidden), shown by \"Show data\";\n// - one tab stop on the plot (`role=\"group\"`, roledescription \"chart\"), the arrow keys walking its points, each one\n// announced in a polite live region;\n// - loading (a chart skeleton), empty and error states, at the chart's own height;\n// - responsive (ResizeObserver) and SSR without layout shift: the server renders the frame, the summary, the table and\n// a placeholder of the exact height; the browser draws once it knows the width;\n// - an entrance once on screen, none under reduced motion, none for live data;\n// - an actions menu (⋯, the kit's DropdownMenu): view as table (the kit DataTable in a Sheet), download CSV / PNG / SVG,\n// copy the data.\nimport { type CSSProperties, type KeyboardEvent, lazy, type PointerEvent, type ReactNode, type RefObject, Suspense, useCallback, useId, useMemo, useRef, useState } from \"react\";\n\nimport type { ChartKind, ChartLabels } from \"../core/labels\";\nimport { fill } from \"../core/labels\";\nimport type { BrandId, Locale } from \"../core/types\";\nimport { type ChartsSettings, useChartCard, useChartSettings } from \"./context\";\nimport { download, fileName, serializeSvg, svgToPng, toCsv } from \"./export\";\nimport { useInView, useMounted, useWidth } from \"./hooks\";\nimport { cx } from \"./parts\";\nimport { ChartStyles } from \"./styles\";\n\nconst ChartActions = lazy(() => import(\"./actions\"));\n\nexport type ExportFormat = \"png\" | \"svg\" | \"csv\";\n\n/** The props every web chart takes, on top of its data. */\nexport interface ChartFrameProps extends ChartsSettings {\n /** What the chart shows, in a few words: its accessible name, and its heading unless `hideTitle`. Inside a `ChartCard`, the card's title is the default. */\n title?: string;\n /** One line that says what the chart shows, between the title and the chart: “100 jobs · +100 % vs last week”. */\n insight?: ReactNode;\n /** A sentence under the title: the period, the unit, the source. */\n description?: ReactNode;\n /** Visually hide the title (it stays the chart's accessible name): a card that already has its heading. */\n hideTitle?: boolean;\n /** The height of the plot in pixels. Default 280 (a sparkline: 32). */\n height?: number;\n /** The data is on its way: a skeleton of the chart, announced once. */\n loading?: boolean;\n /** The data could not be loaded: `true` says the default words, a node says yours (a retry button…). */\n error?: boolean | ReactNode;\n /** What to show when there is nothing to draw (default: the `empty` label). An `EmptyState` of @krizaka/ui fits. */\n empty?: ReactNode;\n /** The written summary: read by screen readers only (`\"hidden\"`, default), or shown under the chart (`\"visible\"`). */\n summary?: \"hidden\" | \"visible\";\n /** Your own summary instead of the generated one (still read first by screen readers). */\n summaryText?: string;\n /** “View as table” in the actions menu (the table is in the page for screen readers either way). Default true. */\n dataTable?: boolean;\n /** The downloads of the actions menu: all three by default, or the formats you want, or `false` for none. */\n exportable?: boolean | readonly ExportFormat[];\n /** The ⋯ actions menu of the kit. `false`: the former “Show data” and export buttons, drawn in line. Default true. */\n actionsMenu?: boolean;\n /** Streaming data (a job queue, an auction): no entrance on updates, no announcement of every new point. */\n live?: boolean;\n /** The id of the figure. */\n id?: string;\n /** A class on the figure (layout: margins, grid placement). */\n className?: string;\n /** Inline style on the figure (layout only: colours come from the tokens). */\n style?: CSSProperties;\n}\n\nexport interface TableModel {\n /** The header of each column; the first one names the categories. */\n readonly columns: readonly string[];\n /** The rows, already written (formatted values). The first cell is the row's header. */\n readonly rows: readonly (readonly string[])[];\n}\n\nexport interface PlotHandlers {\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;\n onPointerMove?: (event: PointerEvent<HTMLDivElement>) => void;\n onPointerLeave?: () => void;\n onBlur?: () => void;\n}\n\ninterface FrameInternals {\n readonly kind: ChartKind;\n readonly frame: ChartFrameProps;\n readonly defaultHeight?: number;\n readonly table: TableModel;\n readonly summary: string;\n readonly isEmpty: boolean;\n /** Draws the plot at the measured width (browser only). */\n readonly children: (width: number, height: number) => ReactNode;\n readonly legend?: ReactNode;\n /** A calm line under the plot: sparse data, a caveat. */\n readonly note?: ReactNode;\n readonly tooltip?: ReactNode;\n readonly announcement?: string;\n readonly handlers?: PlotHandlers;\n /** Whether the plot has points to walk with the keyboard. */\n readonly navigable?: boolean;\n /** A canvas engine exports its own image; the SVG charts are serialised. */\n readonly exportImage?: (format: \"png\" | \"svg\") => Promise<string | null> | string | null;\n /** Draw on the server too (a sparkline of a known width). */\n readonly ssrWidth?: number;\n /** Whether something is drawn on top of the plot (an active point): dims the other marks. */\n readonly active?: boolean;\n readonly plotRef?: RefObject<HTMLDivElement | null>;\n readonly compact?: boolean;\n /** Something the chart needs is still loading (the world's countries): `data-pending` until it is there. */\n readonly pending?: boolean;\n}\n\n/** The settings of a chart (`useChartSettings` re-exported for the charts). */\nexport function useSettings(frame: ChartFrameProps): { locale: Locale; brand?: BrandId; labels: ChartLabels } {\n return useChartSettings(frame);\n}\n\nexport function ChartFrame({\n kind,\n frame,\n defaultHeight = 280,\n table,\n summary,\n isEmpty,\n children,\n legend,\n note,\n tooltip,\n announcement,\n handlers,\n navigable = true,\n exportImage,\n ssrWidth,\n active,\n plotRef,\n compact,\n pending,\n}: FrameInternals) {\n const card = useChartCard();\n const { hideTitle, height = defaultHeight, loading, error, empty, summaryText, dataTable = true, exportable, actionsMenu = true, live, id, className, style } = frame;\n const { brand, labels } = useChartSettings(frame);\n const title = frame.title ?? card?.title ?? labels.kinds[kind];\n const insight = frame.insight ?? card?.insight;\n const description = frame.description ?? card?.description;\n const uid = useId();\n const ids = { title: `${uid}-t`, summary: `${uid}-s`, hint: `${uid}-h`, table: `${uid}-d` };\n const ownRef = useRef<HTMLDivElement | null>(null);\n const ref = plotRef ?? ownRef;\n const figureRef = useRef<HTMLElement | null>(null);\n const mounted = useMounted();\n const measured = useWidth(ref);\n const width = mounted ? measured : 0;\n const inView = useInView(figureRef, { once: true });\n const [showTable, setShowTable] = useState(false);\n\n const [copied, setCopied] = useState(false);\n // The menu offers every download unless told otherwise; the legacy inline buttons only the ones asked for.\n const formats = useMemo<readonly ExportFormat[]>(() => {\n const all: readonly ExportFormat[] = actionsMenu ? [\"csv\", \"png\", \"svg\"] : [\"png\", \"svg\", \"csv\"];\n if (exportable === undefined) return actionsMenu ? all : [];\n return exportable === true ? all : exportable || [];\n }, [exportable, actionsMenu]);\n const state = error ? \"error\" : loading ? \"loading\" : isEmpty ? \"empty\" : \"ready\";\n\n const doExport = useCallback(\n async (format: ExportFormat) => {\n if (format === \"csv\") {\n download(fileName(title, \"csv\"), new Blob([`\\uFEFF${toCsv([table.columns, ...table.rows])}`], { type: \"text/csv;charset=utf-8\" }));\n return;\n }\n if (exportImage) {\n const url = await exportImage(format);\n if (url) download(fileName(title, format), url);\n return;\n }\n const svg = ref.current?.querySelector<SVGSVGElement>(\"svg.kzc-svg\");\n if (!svg) return;\n const background = getComputedStyle(figureRef.current ?? document.body).getPropertyValue(\"--kz-surface-1\").trim() || \"#fff\";\n const surface = resolveColor(background, figureRef.current);\n const markup = serializeSvg(svg, surface);\n if (format === \"svg\") download(fileName(title, \"svg\"), new Blob([markup], { type: \"image/svg+xml\" }));\n else {\n const box = svg.getBoundingClientRect();\n download(fileName(title, \"png\"), await svgToPng(markup, box.width, box.height, surface));\n }\n },\n [exportImage, ref, table, title],\n );\n\n const doCopy = useCallback(async () => {\n const text = [table.columns, ...table.rows].map((row) => row.join(\"\\t\")).join(\"\\n\");\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2500);\n } catch {\n setCopied(false);\n }\n }, [table]);\n\n const drawWidth = width || ssrWidth || 0;\n let plot: ReactNode;\n if (state === \"loading\") {\n plot = (\n <div className=\"kzc-skeleton\" role=\"status\">\n <span className=\"kzc-sr\">{labels.loading}</span>\n {!compact && [0.55, 0.8, 0.45, 0.95, 0.7, 0.6].map((h, i) => <i key={i} aria-hidden style={{ height: `${h * 100}%` }} />)}\n </div>\n );\n } else if (state === \"error\") {\n plot = (\n <div className=\"kzc-state\" data-state=\"error\" role=\"alert\">\n {error === true ? labels.error : error}\n </div>\n );\n } else if (state === \"empty\") {\n plot = empty ?? (\n <div className=\"kzc-state\" data-state=\"empty\" role=\"status\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M4 20V10M10 20V4M16 20v-7M22 20H2\" />\n </svg>\n {labels.empty}\n </div>\n );\n } else if (drawWidth > 0) {\n plot = children(drawWidth, height);\n } else {\n // SSR and the first browser pass: a placeholder of the exact height (no layout shift), the data already in the table.\n plot = !compact && (\n <div className=\"kzc-skeleton\" aria-hidden>\n {[0.55, 0.8, 0.45, 0.95, 0.7, 0.6].map((h, i) => (\n <i key={i} style={{ height: `${h * 100}%` }} />\n ))}\n </div>\n );\n }\n\n const ready = state === \"ready\" && drawWidth > 0;\n return (\n <figure\n ref={figureRef}\n id={id}\n className={cx(\"kzc\", className)}\n style={style}\n data-kzc=\"\"\n data-kind={kind}\n data-state={state}\n data-brand={brand}\n data-inview={inView || undefined}\n data-live={live || undefined}\n data-active={active || undefined}\n data-pending={pending || (state === \"ready\" && drawWidth === 0) || undefined}\n aria-labelledby={ids.title}\n >\n <ChartStyles />\n {(() => {\n const tools = !compact && state !== \"loading\" && state !== \"error\";\n const menu = actionsMenu && tools && !isEmpty && (dataTable || formats.length > 0);\n const legacy = !actionsMenu && tools && (dataTable || formats.length > 0);\n const visible = !hideTitle || description || insight || menu || legacy || card?.extra;\n return (\n <div className={visible ? \"kzc-head\" : \"kzc-sr\"}>\n <div className=\"kzc-heading\" data-insight={insight ? \"\" : undefined}>\n <p id={ids.title} className={hideTitle ? \"kzc-sr\" : \"kzc-title\"}>\n {title}\n </p>\n {insight && <p className=\"kzc-insight\">{insight}</p>}\n {description && <p className=\"kzc-desc\">{description}</p>}\n </div>\n {(menu || legacy || card?.extra) && (\n <div className=\"kzc-tools\">\n {card?.extra}\n {menu && mounted && (\n <Suspense fallback={<MoreButton label={labels.actions} />}>\n <ChartActions title={title} table={table} labels={labels} formats={formats} viewTable={dataTable} onExport={(format) => void doExport(format)} onCopy={() => void doCopy()} />\n </Suspense>\n )}\n {menu && !mounted && <MoreButton label={labels.actions} />}\n {legacy && !isEmpty && dataTable && (\n <button type=\"button\" className=\"kzc-btn\" aria-expanded={showTable} aria-controls={ids.table} onClick={() => setShowTable((v) => !v)}>\n {showTable ? labels.hideData : labels.showData}\n </button>\n )}\n {legacy &&\n !isEmpty &&\n formats.map((format) => (\n <button key={format} type=\"button\" className=\"kzc-btn\" onClick={() => void doExport(format)} aria-label={`${title} — ${format.toUpperCase()}`}>\n {format === \"png\" ? labels.exportPng : format === \"svg\" ? labels.exportSvg : labels.exportCsv}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n })()}\n {legend}\n <div\n ref={ref}\n className=\"kzc-plot\"\n style={{ height }}\n {...(ready\n ? {\n role: \"group\",\n \"aria-roledescription\": labels.roleDescription,\n \"aria-labelledby\": ids.title,\n \"aria-describedby\": navigable ? `${ids.summary} ${ids.hint}` : ids.summary,\n tabIndex: navigable ? 0 : undefined,\n ...handlers,\n }\n : {})}\n >\n {plot}\n {ready && tooltip}\n </div>\n {ready && note && <p className=\"kzc-note\">{note}</p>}\n <p id={ids.summary} className={frame.summary === \"visible\" ? \"kzc-summary\" : \"kzc-sr\"}>\n {summaryText ?? summary}\n </p>\n {ready && navigable && (\n <span id={ids.hint} className=\"kzc-sr\">\n {labels.keyboardHint}\n </span>\n )}\n <div className=\"kzc-live\" aria-live=\"polite\" aria-atomic=\"true\">\n {copied ? labels.copied : live ? \"\" : announcement}\n </div>\n {!isEmpty && (\n <div id={ids.table} className={showTable ? \"kzc-table-wrap\" : \"kzc-sr\"}>\n <table className=\"kzc-table\">\n <caption>{fill(labels.tableCaption, { title })}</caption>\n <thead>\n <tr>\n {table.columns.map((column, i) => (\n <th key={i} scope=\"col\">\n {column}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {table.rows.map((row, r) => (\n <tr key={r}>\n {row.map((cell, c) =>\n c === 0 ? (\n <th key={c} scope=\"row\">\n {cell}\n </th>\n ) : (\n <td key={c}>{cell}</td>\n ),\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </figure>\n );\n}\n\n/** The ⋯ button as the server and the first browser pass draw it, until the kit's menu has loaded. */\nfunction MoreButton({ label }: { label: string }) {\n return (\n <button type=\"button\" className=\"kzc-more\" aria-label={label} disabled>\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden width=\"16\" height=\"16\">\n <circle cx=\"5\" cy=\"12\" r=\"1.8\" />\n <circle cx=\"12\" cy=\"12\" r=\"1.8\" />\n <circle cx=\"19\" cy=\"12\" r=\"1.8\" />\n </svg>\n </button>\n );\n}\n\n/** A CSS colour (a `var(--…)`, `light-dark()`, `hsl()`…) as the browser resolves it on `scope`: `rgb(r, g, b)`. */\nexport function resolveColor(color: string, scope: Element | null): string {\n if (typeof document === \"undefined\") return color;\n const probe = document.createElement(\"span\");\n probe.style.color = color;\n probe.style.display = \"none\";\n (scope ?? document.body).appendChild(probe);\n const resolved = getComputedStyle(probe).color;\n probe.remove();\n return resolved || color;\n}\n","// Export a chart as a file: CSV (the data table, as the reader sees it), SVG (the drawing, its colours resolved — a\n// file has no --kz-* variables) and PNG (the SVG rasterised at twice the size).\n\n/** One CSV line per row; cells quoted when they hold a separator, a quote or a line break. */\nexport function toCsv(rows: readonly (readonly string[])[]): string {\n const cell = (value: string) => (/[\",\\n;]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value);\n return rows.map((row) => row.map(cell).join(\",\")).join(\"\\n\");\n}\n\n/** A file name from a title: `Earnings, last 6 months` → `earnings-last-6-months`. */\nexport function fileName(title: string | undefined, extension: string): string {\n const base =\n (title ?? \"chart\")\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\") || \"chart\";\n return `${base}.${extension}`;\n}\n\nexport function download(name: string, content: Blob | string): void {\n const url = typeof content === \"string\" ? content : URL.createObjectURL(content);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = name;\n link.click();\n if (typeof content !== \"string\") setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nconst PROPS = [\"fill\", \"stroke\", \"stroke-width\", \"stroke-dasharray\", \"opacity\", \"fill-opacity\", \"font-size\", \"font-weight\", \"font-family\"] as const;\n\n/** A standalone copy of a drawn SVG: every colour and text style the CSS gave it, written on the element. */\nexport function serializeSvg(svg: SVGSVGElement, background?: string): string {\n const clone = svg.cloneNode(true) as SVGSVGElement;\n const source = [svg, ...svg.querySelectorAll(\"*\")];\n const target = [clone, ...clone.querySelectorAll(\"*\")];\n source.forEach((el, i) => {\n const style = getComputedStyle(el);\n const out = target[i] as SVGElement;\n for (const prop of PROPS) {\n const value = style.getPropertyValue(prop);\n if (value) out.style.setProperty(prop, value);\n }\n // The entrance animation's dash would export a line half drawn.\n out.style.removeProperty(\"stroke-dasharray\");\n if (el.getAttribute(\"stroke-dasharray\")) out.style.setProperty(\"stroke-dasharray\", el.getAttribute(\"stroke-dasharray\")!);\n });\n clone.setAttribute(\"xmlns\", \"http://www.w3.org/2000/svg\");\n if (background) clone.style.setProperty(\"background\", background);\n return new XMLSerializer().serializeToString(clone);\n}\n\n/** The SVG drawn on a canvas at `scale` × its size, as a PNG data URL. */\nexport function svgToPng(markup: string, width: number, height: number, background: string, scale = 2): Promise<string> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.onload = () => {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width * scale;\n canvas.height = height * scale;\n const context = canvas.getContext(\"2d\");\n if (!context) return reject(new Error(\"No 2D canvas\"));\n context.fillStyle = background;\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n resolve(canvas.toDataURL(\"image/png\"));\n return undefined;\n };\n image.onerror = () => reject(new Error(\"The SVG could not be rasterised\"));\n image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;\n });\n}\n"],"mappings":"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","names":["useState","jsx","useCallback","useState","jsx","jsxs","useState","useCallback"]}
|
|
@@ -90,6 +90,33 @@ function summarize(series, categories, writeCategory) {
|
|
|
90
90
|
const trend = count < 2 || change === null ? count < 2 ? "none" : last > first ? "up" : last < first ? "down" : "flat" : Math.abs(change) < 0.01 ? "flat" : change > 0 ? "up" : "down";
|
|
91
91
|
return { label: series.label, count, min, max, first, last, total, change, trend };
|
|
92
92
|
}
|
|
93
|
+
function trimToActivity(table, min = 7) {
|
|
94
|
+
const total = table.categories.length;
|
|
95
|
+
const has = (i) => table.series.some((s) => {
|
|
96
|
+
const v = s.values[i];
|
|
97
|
+
return v != null && v !== 0;
|
|
98
|
+
});
|
|
99
|
+
let first = -1;
|
|
100
|
+
let last = -1;
|
|
101
|
+
let active = 0;
|
|
102
|
+
for (let i = 0; i < total; i += 1) {
|
|
103
|
+
if (!has(i)) continue;
|
|
104
|
+
active += 1;
|
|
105
|
+
if (first < 0) first = i;
|
|
106
|
+
last = i;
|
|
107
|
+
}
|
|
108
|
+
if (first < 0) return { table, start: 0, active: 0, total };
|
|
109
|
+
let from = first;
|
|
110
|
+
let to = last;
|
|
111
|
+
const want = Math.min(total, Math.max(1, min));
|
|
112
|
+
while (to - from + 1 < want) {
|
|
113
|
+
if (from > 0) from -= 1;
|
|
114
|
+
else if (to < total - 1) to += 1;
|
|
115
|
+
else break;
|
|
116
|
+
}
|
|
117
|
+
if (from === 0 && to === total - 1) return { table, start: 0, active, total };
|
|
118
|
+
return { table: { categories: table.categories.slice(from, to + 1), series: table.series.map((s) => ({ ...s, values: s.values.slice(from, to + 1) })) }, start: from, active, total };
|
|
119
|
+
}
|
|
93
120
|
|
|
94
121
|
export {
|
|
95
122
|
read,
|
|
@@ -97,6 +124,7 @@ export {
|
|
|
97
124
|
tabulate,
|
|
98
125
|
extent,
|
|
99
126
|
stack,
|
|
100
|
-
summarize
|
|
127
|
+
summarize,
|
|
128
|
+
trimToActivity
|
|
101
129
|
};
|
|
102
|
-
//# sourceMappingURL=chunk-
|
|
130
|
+
//# sourceMappingURL=chunk-PGD6SH5I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/data.ts"],"sourcesContent":["// From the app's rows to what a chart draws: the categories (x) and, per series, one value per category. Missing\n// values stay `null` (a gap), never a zero.\nimport type { Accessor, Datum, SeriesColor, SeriesSpec, SeriesSummary } from \"./types\";\n\n/** Reads a field or calls the accessor. */\nexport function read<T, V>(accessor: Accessor<T, V>, datum: T, index: number): V {\n return typeof accessor === \"function\" ? accessor(datum, index) : (datum[accessor as keyof T] as V);\n}\n\nexport interface Series {\n readonly id: string;\n readonly label: string;\n readonly values: readonly (number | null)[];\n readonly color?: SeriesColor;\n readonly dashed?: boolean;\n /** Its palette slot (1–8), in the order the series were given: a series keeps its colour whatever is filtered. */\n readonly slot: number;\n}\n\nexport interface Table {\n readonly categories: readonly unknown[];\n readonly series: readonly Series[];\n}\n\nconst toNumber = (value: unknown): number | null => (typeof value === \"number\" && Number.isFinite(value) ? value : null);\n\n/** `series`, or a single series from `y` and `label`. */\nexport function normalizeSeries<T extends Datum>(series: readonly SeriesSpec<T>[] | undefined, y: Accessor<T, number | null | undefined> | undefined, label: string | undefined): readonly SeriesSpec<T>[] {\n if (series?.length) return series;\n if (y !== undefined) return [{ key: y, label: label ?? (typeof y === \"string\" ? y : \"\") }];\n return [];\n}\n\n/** The categories and the series' values, row by row. */\nexport function tabulate<T extends Datum>(data: readonly T[], x: Accessor<T, unknown> | undefined, series: readonly SeriesSpec<T>[]): Table {\n return {\n categories: data.map((datum, i) => (x === undefined ? i + 1 : read(x, datum, i))),\n series: series.map((spec, s) => ({\n id: typeof spec.key === \"string\" ? spec.key : `series-${s}`,\n label: spec.label,\n values: data.map((datum, i) => toNumber(read(spec.key, datum, i))),\n color: spec.color,\n dashed: spec.dashed,\n slot: (s % 8) + 1,\n })),\n };\n}\n\n/** The smallest and largest value of the series, `stacked` summing them per category (positives and negatives apart). */\nexport function extent(series: readonly Series[], stacked = false): [number, number] {\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n const count = series[0]?.values.length ?? 0;\n if (stacked) {\n for (let i = 0; i < count; i += 1) {\n let pos = 0;\n let neg = 0;\n for (const s of series) {\n const v = s.values[i] ?? 0;\n if (v >= 0) pos += v;\n else neg += v;\n }\n min = Math.min(min, neg);\n max = Math.max(max, pos);\n }\n } else {\n for (const s of series) {\n for (const v of s.values) {\n if (v == null) continue;\n min = Math.min(min, v);\n max = Math.max(max, v);\n }\n }\n }\n if (min === Number.POSITIVE_INFINITY) return [0, 0];\n return [min, max];\n}\n\n/** Per category and series, the base and top of a stacked mark (positives up, negatives down). */\nexport function stack(series: readonly Series[]): { base: number; top: number }[][] {\n const count = series[0]?.values.length ?? 0;\n const out = series.map(() => [] as { base: number; top: number }[]);\n for (let i = 0; i < count; i += 1) {\n let pos = 0;\n let neg = 0;\n series.forEach((s, k) => {\n const v = s.values[i] ?? 0;\n if (v >= 0) {\n out[k]!.push({ base: pos, top: pos + v });\n pos += v;\n } else {\n out[k]!.push({ base: neg, top: neg + v });\n neg += v;\n }\n });\n }\n return out;\n}\n\n/** What a series says: its extremes, its first and last values, its total and its trend (±1 % is flat). */\nexport function summarize(series: Series, categories: readonly unknown[], writeCategory: (c: unknown) => string): SeriesSummary {\n let min: SeriesSummary[\"min\"] = null;\n let max: SeriesSummary[\"max\"] = null;\n let first: number | null = null;\n let last: number | null = null;\n let total = 0;\n let count = 0;\n series.values.forEach((v, i) => {\n if (v == null) return;\n count += 1;\n total += v;\n if (first === null) first = v;\n last = v;\n if (!min || v < min.value) min = { value: v, category: writeCategory(categories[i]) };\n if (!max || v > max.value) max = { value: v, category: writeCategory(categories[i]) };\n });\n const change = first !== null && last !== null && first !== 0 && count > 1 ? (last as number) / first - 1 : null;\n const trend = count < 2 || change === null ? (count < 2 ? \"none\" : last! > first! ? \"up\" : last! < first! ? \"down\" : \"flat\") : Math.abs(change) < 0.01 ? \"flat\" : change > 0 ? \"up\" : \"down\";\n return { label: series.label, count, min, max, first, last, total, change, trend };\n}\n\n/**\n * The period that has data: the categories before the first and after the last value other than 0 or null are\n * dropped, but never below `min` categories (the window grows backwards first — the recent past gives a short burst\n * its scale — then forwards). `start` is the index of the first kept category in the table given; `active` the number\n * of categories with a value; `total` the number given. Nothing to trim, or no activity at all: the table as is.\n */\nexport function trimToActivity(table: Table, min = 7): { table: Table; start: number; active: number; total: number } {\n const total = table.categories.length;\n const has = (i: number) => table.series.some((s) => {\n const v = s.values[i];\n return v != null && v !== 0;\n });\n let first = -1;\n let last = -1;\n let active = 0;\n for (let i = 0; i < total; i += 1) {\n if (!has(i)) continue;\n active += 1;\n if (first < 0) first = i;\n last = i;\n }\n if (first < 0) return { table, start: 0, active: 0, total };\n let from = first;\n let to = last;\n const want = Math.min(total, Math.max(1, min));\n while (to - from + 1 < want) {\n if (from > 0) from -= 1;\n else if (to < total - 1) to += 1;\n else break;\n }\n if (from === 0 && to === total - 1) return { table, start: 0, active, total };\n return { table: { categories: table.categories.slice(from, to + 1), series: table.series.map((s) => ({ ...s, values: s.values.slice(from, to + 1) })) }, start: from, active, total };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,20 +4,20 @@ import {
|
|
|
4
4
|
baseOption,
|
|
5
5
|
tooltipHtml,
|
|
6
6
|
valueAxis
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NV52AKHG.js";
|
|
8
8
|
import {
|
|
9
9
|
read
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PGD6SH5I.js";
|
|
11
11
|
import {
|
|
12
12
|
valueFormatter
|
|
13
13
|
} from "./chunk-XLLYNNC6.js";
|
|
14
14
|
import {
|
|
15
15
|
Legend,
|
|
16
16
|
useSettings
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-P6RS2L23.js";
|
|
18
18
|
import {
|
|
19
19
|
fill
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-GRRFPI27.js";
|
|
21
21
|
|
|
22
22
|
// src/scatter/scatter-chart.tsx
|
|
23
23
|
import { formatNumber } from "@krizaka/intl";
|
|
@@ -130,4 +130,4 @@ export {
|
|
|
130
130
|
correlation,
|
|
131
131
|
ScatterChart
|
|
132
132
|
};
|
|
133
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-PWZHIGPO.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
Sparkline
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FIQHMJZK.js";
|
|
5
5
|
import {
|
|
6
6
|
Kpi
|
|
7
7
|
} from "./chunk-WBHFVBSK.js";
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
ChartStyles,
|
|
21
21
|
cx,
|
|
22
22
|
useSettings
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-P6RS2L23.js";
|
|
24
24
|
|
|
25
25
|
// src/credits/credit-usage.tsx
|
|
26
26
|
import { useId } from "react";
|
|
@@ -91,4 +91,4 @@ function CreditUsage({
|
|
|
91
91
|
export {
|
|
92
92
|
CreditUsage
|
|
93
93
|
};
|
|
94
|
-
//# sourceMappingURL=chunk-
|
|
94
|
+
//# sourceMappingURL=chunk-VEOJNMPF.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Sparkline
|
|
4
|
+
} from "./chunk-FIQHMJZK.js";
|
|
5
|
+
import {
|
|
6
|
+
valueFormatter
|
|
7
|
+
} from "./chunk-XLLYNNC6.js";
|
|
8
|
+
import {
|
|
9
|
+
ChartStyles,
|
|
10
|
+
cx
|
|
11
|
+
} from "./chunk-P6RS2L23.js";
|
|
12
|
+
import {
|
|
13
|
+
ChartCardProvider,
|
|
14
|
+
useChartSettings
|
|
15
|
+
} from "./chunk-OVASCEGF.js";
|
|
16
|
+
import {
|
|
17
|
+
fill
|
|
18
|
+
} from "./chunk-GRRFPI27.js";
|
|
19
|
+
|
|
20
|
+
// src/card/chart-card.tsx
|
|
21
|
+
import { Card } from "@krizaka/ui/card";
|
|
22
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
23
|
+
function ChartCard({ title, insight, description, actions, footer, children, className, id }) {
|
|
24
|
+
return /* @__PURE__ */ jsx(ChartCardProvider, { value: { title, insight, description, extra: actions }, children: /* @__PURE__ */ jsxs(Card.Root, { id, className: cx("kzc-card", className), children: [
|
|
25
|
+
/* @__PURE__ */ jsx(ChartStyles, {}),
|
|
26
|
+
/* @__PURE__ */ jsxs(Card.Body, { padding: "lg", children: [
|
|
27
|
+
children,
|
|
28
|
+
footer ? /* @__PURE__ */ jsx("p", { className: "kzc-card-foot", children: footer }) : null
|
|
29
|
+
] })
|
|
30
|
+
] }) });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/card/kpi-stat.tsx
|
|
34
|
+
import { getNumberFormat } from "@krizaka/intl";
|
|
35
|
+
import { NumberTicker } from "@krizaka/ui/number-ticker";
|
|
36
|
+
import { Stat } from "@krizaka/ui/stat";
|
|
37
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
38
|
+
var FLAT = 5e-3;
|
|
39
|
+
function KpiStat({ label, value, format, previous, good = "up", data, categories, variant = "area", color, trendLabel, hint, locale, brand, labels, className, ...rest }) {
|
|
40
|
+
const settings = useChartSettings({ locale, brand, labels });
|
|
41
|
+
const write = valueFormatter(format, settings.locale, settings.labels.noValue);
|
|
42
|
+
const change = previous === void 0 ? null : previous === 0 ? value === 0 ? 0 : null : value / previous - 1;
|
|
43
|
+
const direction = change === null ? void 0 : Math.abs(change) < FLAT ? "flat" : change > 0 ? "up" : "down";
|
|
44
|
+
const tag = Array.isArray(settings.locale) ? settings.locale[0] : settings.locale;
|
|
45
|
+
const pct = change === null ? null : getNumberFormat(settings.locale, { style: "percent", maximumFractionDigits: 0, signDisplay: "exceptZero" }).format(change);
|
|
46
|
+
const words = trendLabel ?? (pct !== null ? fill(settings.labels.trendVsPrevious, { change: pct }) : void 0);
|
|
47
|
+
const plain = format === void 0 || format === "number" || format === "integer";
|
|
48
|
+
const figure = plain ? /* @__PURE__ */ jsx2(NumberTicker, { value, locale: tag, format: { maximumFractionDigits: format === "number" || format === void 0 ? 2 : 0 } }) : write(value);
|
|
49
|
+
return /* @__PURE__ */ jsxs2("div", { className: "kzc-kpistat", "data-good": good, "data-brand": settings.brand, children: [
|
|
50
|
+
/* @__PURE__ */ jsx2(ChartStyles, {}),
|
|
51
|
+
/* @__PURE__ */ jsx2(
|
|
52
|
+
Stat,
|
|
53
|
+
{
|
|
54
|
+
className,
|
|
55
|
+
label,
|
|
56
|
+
value: figure,
|
|
57
|
+
hint,
|
|
58
|
+
trend: direction,
|
|
59
|
+
trendLabel: direction && words ? words : void 0,
|
|
60
|
+
chart: data && data.length > 1 ? /* @__PURE__ */ jsx2(Sparkline, { title: label, data, categories, variant, color, format, height: 40, locale: settings.locale, brand: settings.brand, labels }) : void 0,
|
|
61
|
+
...rest
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
] });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
ChartCard,
|
|
69
|
+
KpiStat
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=chunk-YHQFW2PR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/card/chart-card.tsx","../src/card/kpi-stat.tsx"],"sourcesContent":["\"use client\";\n// One frame for every chart of a screen: the kit's Card with the Krizaka hierarchy — title, one line that says what the\n// chart shows (the insight), the chart, a footer — and the chart's actions menu (⋯) at the top right, beside the\n// controls you pass (a period switch). The chart inside needs no title of its own: the card hands it its heading.\nimport { Card } from \"@krizaka/ui/card\";\nimport type { ReactNode } from \"react\";\n\nimport { ChartCardProvider } from \"../web/context\";\nimport { cx } from \"../web/parts\";\nimport { ChartStyles } from \"../web/styles\";\n\nexport interface ChartCardProps {\n /** What the chart shows, in a few words (a heading and the chart's accessible name). */\n title: string;\n /** One line that says what the chart shows: “100 jobs · +100 % vs last week”. Written by the app, from its data. */\n insight?: ReactNode;\n /** The period, the unit, the source — under the insight. */\n description?: ReactNode;\n /** Controls beside the actions menu: a period switch, a filter. */\n actions?: ReactNode;\n /** A line under the chart: the source, the freshness, a link. */\n footer?: ReactNode;\n /** The chart (`LineChart`, `BarChart`, `DonutChart`…), without its own title. */\n children: ReactNode;\n /** A class on the card (layout: grid placement). */\n className?: string;\n /** The id of the card. */\n id?: string;\n}\n\n/** The frame of a chart: title, insight, actions, chart, footer — used everywhere a chart is shown. */\nexport function ChartCard({ title, insight, description, actions, footer, children, className, id }: ChartCardProps) {\n return (\n <ChartCardProvider value={{ title, insight, description, extra: actions }}>\n <Card.Root id={id} className={cx(\"kzc-card\", className)}>\n <ChartStyles />\n <Card.Body padding=\"lg\">\n {children}\n {footer ? <p className=\"kzc-card-foot\">{footer}</p> : null}\n </Card.Body>\n </Card.Root>\n </ChartCardProvider>\n );\n}\n","\"use client\";\n// A key figure with its trend and, under it, the shape of the period: the kit's Stat with a Sparkline in its chart\n// slot. The change against the previous period is computed here and written in words (the arrow is decoration);\n// `good=\"down\"` for a figure that is better when it falls (latency, failures): the arrow's colour follows.\nimport { getNumberFormat } from \"@krizaka/intl\";\nimport { NumberTicker } from \"@krizaka/ui/number-ticker\";\nimport { Stat, type StatProps } from \"@krizaka/ui/stat\";\nimport type { ReactNode } from \"react\";\n\nimport { valueFormatter } from \"../core/format\";\nimport { fill } from \"../core/labels\";\nimport type { SeriesColor, ValueFormat } from \"../core/types\";\nimport { Sparkline } from \"../sparkline/sparkline\";\nimport type { ChartsSettings } from \"../web/context\";\nimport { useChartSettings } from \"../web/context\";\nimport { ChartStyles } from \"../web/styles\";\n\nexport interface KpiStatProps extends ChartsSettings, Omit<StatProps, \"value\" | \"trend\" | \"trendLabel\" | \"chart\" | \"label\" | \"color\"> {\n /** What the figure is (“Jobs”). */\n label: string;\n /** The figure for the period. */\n value: number;\n /** How it is written. Default `\"number\"`. */\n format?: ValueFormat;\n /** The same figure for the previous period: the trend is computed from it. */\n previous?: number;\n /** Which direction is good news. Default `\"up\"`; `\"down\"` for latency, failures, spend. */\n good?: \"up\" | \"down\";\n /** The shape of the period, oldest first (`null` for a gap). Without it, no sparkline. */\n data?: readonly (number | null)[];\n /** The labels of `data` (dates), for the sparkline's summary and table. */\n categories?: readonly unknown[];\n /** `bar` for discrete counts (jobs per day), `area` (default) or `line`. */\n variant?: \"line\" | \"area\" | \"bar\";\n /** The sparkline's colour. Default: the brand's. */\n color?: SeriesColor;\n /** Your own words for the change instead of “+12 % vs previous period”. */\n trendLabel?: ReactNode;\n}\n\nconst FLAT = 0.005;\n\n/** A key figure, its change against the previous period and the shape of the period. */\nexport function KpiStat({ label, value, format, previous, good = \"up\", data, categories, variant = \"area\", color, trendLabel, hint, locale, brand, labels, className, ...rest }: KpiStatProps) {\n const settings = useChartSettings({ locale, brand, labels });\n const write = valueFormatter(format, settings.locale, settings.labels.noValue);\n const change = previous === undefined ? null : previous === 0 ? (value === 0 ? 0 : null) : value / previous - 1;\n const direction = change === null ? undefined : Math.abs(change) < FLAT ? \"flat\" : change > 0 ? \"up\" : \"down\";\n const tag = Array.isArray(settings.locale) ? settings.locale[0] : (settings.locale as string);\n const pct = change === null ? null : getNumberFormat(settings.locale, { style: \"percent\", maximumFractionDigits: 0, signDisplay: \"exceptZero\" }).format(change);\n const words = trendLabel ?? (pct !== null ? fill(settings.labels.trendVsPrevious, { change: pct }) : undefined);\n const plain = format === undefined || format === \"number\" || format === \"integer\";\n const figure = plain ? <NumberTicker value={value} locale={tag} format={{ maximumFractionDigits: format === \"number\" || format === undefined ? 2 : 0 }} /> : write(value);\n\n return (\n <div className=\"kzc-kpistat\" data-good={good} data-brand={settings.brand}>\n <ChartStyles />\n <Stat\n className={className}\n label={label}\n value={figure}\n hint={hint}\n trend={direction}\n trendLabel={direction && words ? words : undefined}\n chart={data && data.length > 1 ? <Sparkline title={label} data={data} categories={categories} variant={variant} color={color} format={format} height={40} locale={settings.locale} brand={settings.brand} labels={labels} /> : undefined}\n {...rest}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAIA,SAAS,YAAY;AA+Bb,cACA,YADA;AAJD,SAAS,UAAU,EAAE,OAAO,SAAS,aAAa,SAAS,QAAQ,UAAU,WAAW,GAAG,GAAmB;AACnH,SACE,oBAAC,qBAAkB,OAAO,EAAE,OAAO,SAAS,aAAa,OAAO,QAAQ,GACtE,+BAAC,KAAK,MAAL,EAAU,IAAQ,WAAW,GAAG,YAAY,SAAS,GACpD;AAAA,wBAAC,eAAY;AAAA,IACb,qBAAC,KAAK,MAAL,EAAU,SAAQ,MAChB;AAAA;AAAA,MACA,SAAS,oBAAC,OAAE,WAAU,iBAAiB,kBAAO,IAAO;AAAA,OACxD;AAAA,KACF,GACF;AAEJ;;;ACvCA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,YAA4B;AA8CZ,gBAAAA,MAGrB,QAAAC,aAHqB;AAZzB,IAAM,OAAO;AAGN,SAAS,QAAQ,EAAE,OAAO,OAAO,QAAQ,UAAU,OAAO,MAAM,MAAM,YAAY,UAAU,QAAQ,OAAO,YAAY,MAAM,QAAQ,OAAO,QAAQ,WAAW,GAAG,KAAK,GAAiB;AAC7L,QAAM,WAAW,iBAAiB,EAAE,QAAQ,OAAO,OAAO,CAAC;AAC3D,QAAM,QAAQ,eAAe,QAAQ,SAAS,QAAQ,SAAS,OAAO,OAAO;AAC7E,QAAM,SAAS,aAAa,SAAY,OAAO,aAAa,IAAK,UAAU,IAAI,IAAI,OAAQ,QAAQ,WAAW;AAC9G,QAAM,YAAY,WAAW,OAAO,SAAY,KAAK,IAAI,MAAM,IAAI,OAAO,SAAS,SAAS,IAAI,OAAO;AACvG,QAAM,MAAM,MAAM,QAAQ,SAAS,MAAM,IAAI,SAAS,OAAO,CAAC,IAAK,SAAS;AAC5E,QAAM,MAAM,WAAW,OAAO,OAAO,gBAAgB,SAAS,QAAQ,EAAE,OAAO,WAAW,uBAAuB,GAAG,aAAa,aAAa,CAAC,EAAE,OAAO,MAAM;AAC9J,QAAM,QAAQ,eAAe,QAAQ,OAAO,KAAK,SAAS,OAAO,iBAAiB,EAAE,QAAQ,IAAI,CAAC,IAAI;AACrG,QAAM,QAAQ,WAAW,UAAa,WAAW,YAAY,WAAW;AACxE,QAAM,SAAS,QAAQ,gBAAAD,KAAC,gBAAa,OAAc,QAAQ,KAAK,QAAQ,EAAE,uBAAuB,WAAW,YAAY,WAAW,SAAY,IAAI,EAAE,GAAG,IAAK,MAAM,KAAK;AAExK,SACE,gBAAAC,MAAC,SAAI,WAAU,eAAc,aAAW,MAAM,cAAY,SAAS,OACjE;AAAA,oBAAAD,KAAC,eAAY;AAAA,IACb,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA,OAAO;AAAA,QACP,YAAY,aAAa,QAAQ,QAAQ;AAAA,QACzC,OAAO,QAAQ,KAAK,SAAS,IAAI,gBAAAA,KAAC,aAAU,OAAO,OAAO,MAAY,YAAwB,SAAkB,OAAc,QAAgB,QAAQ,IAAI,QAAQ,SAAS,QAAQ,OAAO,SAAS,OAAO,QAAgB,IAAK;AAAA,QAC9N,GAAG;AAAA;AAAA,IACN;AAAA,KACF;AAEJ;","names":["jsx","jsxs"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
Cartesian
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JST4HJC3.js";
|
|
5
5
|
|
|
6
6
|
// src/line/line-chart.tsx
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -16,4 +16,4 @@ export {
|
|
|
16
16
|
LineChart,
|
|
17
17
|
AreaChart
|
|
18
18
|
};
|
|
19
|
-
//# sourceMappingURL=chunk-
|
|
19
|
+
//# sourceMappingURL=chunk-Z4T3JFNU.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
Gauge
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OZOAKP5F.js";
|
|
5
5
|
import {
|
|
6
6
|
GOAL_LABELS,
|
|
7
7
|
fillIn,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-XLLYNNC6.js";
|
|
13
13
|
import {
|
|
14
14
|
useSettings
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-P6RS2L23.js";
|
|
16
16
|
|
|
17
17
|
// src/goal/goal-progress.tsx
|
|
18
18
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -51,4 +51,4 @@ function GoalProgress({ raised, goal, currency, supporters, timeLeft, labels: gi
|
|
|
51
51
|
export {
|
|
52
52
|
GoalProgress
|
|
53
53
|
};
|
|
54
|
-
//# sourceMappingURL=chunk-
|
|
54
|
+
//# sourceMappingURL=chunk-ZF7LVQTR.js.map
|
|
@@ -12,6 +12,25 @@ interface ChartLabels {
|
|
|
12
12
|
exportPng: string;
|
|
13
13
|
exportSvg: string;
|
|
14
14
|
exportCsv: string;
|
|
15
|
+
/** The actions menu (⋯) of a chart: its accessible name, and its entries. */
|
|
16
|
+
actions: string;
|
|
17
|
+
viewTable: string;
|
|
18
|
+
downloadCsv: string;
|
|
19
|
+
downloadPng: string;
|
|
20
|
+
downloadSvg: string;
|
|
21
|
+
copyData: string;
|
|
22
|
+
/** Announced once the data is on the clipboard. */
|
|
23
|
+
copied: string;
|
|
24
|
+
/** The close button of the table sheet. */
|
|
25
|
+
close: string;
|
|
26
|
+
/** The sheet's description: `{count}` rows. */
|
|
27
|
+
tableRows: string;
|
|
28
|
+
/** Legend chips filter: the chip's accessible name, `{label}`. */
|
|
29
|
+
toggleSeries: string;
|
|
30
|
+
/** Sparse data: under the chart, `{count}` periods with data out of `{total}`. */
|
|
31
|
+
sparse: string;
|
|
32
|
+
/** A KPI's change: `{change}` (`+12 %`) against the previous period. */
|
|
33
|
+
trendVsPrevious: string;
|
|
15
34
|
/** Announced while the data loads. */
|
|
16
35
|
loading: string;
|
|
17
36
|
/** Shown when there is nothing to draw. */
|
package/dist/credits.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { a as CreditLabels } from './labels-DE_743fQ.js';
|
|
|
2
2
|
export { C as CREDIT_LABELS } from './labels-DE_743fQ.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ReactNode, CSSProperties } from 'react';
|
|
5
|
-
import { f as ChartsSettings, V as ValueFormat } from './context-
|
|
5
|
+
import { f as ChartsSettings, V as ValueFormat } from './context-DNW7bJYw.js';
|
|
6
6
|
|
|
7
7
|
interface CreditUsageProps extends Omit<ChartsSettings, "labels"> {
|
|
8
8
|
/** What the allowance is (“Credits this month”): the heading and the meter's name. */
|
package/dist/credits.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
CreditUsage
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-VEOJNMPF.js";
|
|
5
|
+
import "./chunk-FIQHMJZK.js";
|
|
6
6
|
import "./chunk-WBHFVBSK.js";
|
|
7
7
|
import "./chunk-BISL7DYW.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-GD7TWEN3.js";
|
|
9
|
+
import "./chunk-PGD6SH5I.js";
|
|
10
10
|
import {
|
|
11
11
|
CREDIT_LABELS
|
|
12
12
|
} from "./chunk-WNUFGMS7.js";
|
|
13
13
|
import "./chunk-OB5EFDDH.js";
|
|
14
14
|
import "./chunk-XLLYNNC6.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-P6RS2L23.js";
|
|
16
|
+
import "./chunk-OVASCEGF.js";
|
|
17
|
+
import "./chunk-GRRFPI27.js";
|
|
17
18
|
export {
|
|
18
19
|
CREDIT_LABELS,
|
|
19
20
|
CreditUsage
|
package/dist/earnings.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { b as EarningsLabels } from './labels-DE_743fQ.js';
|
|
2
2
|
export { E as EARNINGS_LABELS } from './labels-DE_743fQ.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
|
-
import { C as CartesianProps } from './cartesian-
|
|
5
|
-
import { g as Datum, A as Accessor, C as CategoryFormat, T as Threshold } from './context-
|
|
6
|
-
import './frame-
|
|
4
|
+
import { C as CartesianProps } from './cartesian-CEY_wwe_.js';
|
|
5
|
+
import { g as Datum, A as Accessor, C as CategoryFormat, T as Threshold } from './context-DNW7bJYw.js';
|
|
6
|
+
import './frame-B1HDNm7c.js';
|
|
7
7
|
|
|
8
8
|
interface EarningsChartProps<T extends Datum> extends Omit<CartesianProps<T>, "y" | "yLabel" | "series" | "format" | "x" | "xFormat" | "thresholds" | "labels"> {
|
|
9
9
|
/** The field (or function) of the period: an ISO month (`"2026-04"`), a day. Default `"month"`. */
|
package/dist/earnings.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
EarningsChart
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-IJTI6VJD.js";
|
|
5
|
+
import "./chunk-IURCLBUQ.js";
|
|
6
|
+
import "./chunk-JST4HJC3.js";
|
|
7
7
|
import "./chunk-WBHFVBSK.js";
|
|
8
8
|
import "./chunk-BISL7DYW.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-GD7TWEN3.js";
|
|
10
|
+
import "./chunk-PGD6SH5I.js";
|
|
11
11
|
import {
|
|
12
12
|
EARNINGS_LABELS
|
|
13
13
|
} from "./chunk-WNUFGMS7.js";
|
|
14
14
|
import "./chunk-OB5EFDDH.js";
|
|
15
15
|
import "./chunk-XLLYNNC6.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-P6RS2L23.js";
|
|
17
|
+
import "./chunk-OVASCEGF.js";
|
|
18
|
+
import "./chunk-GRRFPI27.js";
|
|
18
19
|
export {
|
|
19
20
|
EARNINGS_LABELS,
|
|
20
21
|
EarningsChart
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ReactNode, CSSProperties } from 'react';
|
|
2
|
-
import { f as ChartsSettings } from './context-
|
|
2
|
+
import { f as ChartsSettings } from './context-DNW7bJYw.js';
|
|
3
3
|
|
|
4
4
|
type ExportFormat = "png" | "svg" | "csv";
|
|
5
5
|
/** The props every web chart takes, on top of its data. */
|
|
6
6
|
interface ChartFrameProps extends ChartsSettings {
|
|
7
|
-
/** What the chart shows, in a few words: its accessible name, and its heading unless `hideTitle`. */
|
|
8
|
-
title
|
|
7
|
+
/** What the chart shows, in a few words: its accessible name, and its heading unless `hideTitle`. Inside a `ChartCard`, the card's title is the default. */
|
|
8
|
+
title?: string;
|
|
9
|
+
/** One line that says what the chart shows, between the title and the chart: “100 jobs · +100 % vs last week”. */
|
|
10
|
+
insight?: ReactNode;
|
|
9
11
|
/** A sentence under the title: the period, the unit, the source. */
|
|
10
12
|
description?: ReactNode;
|
|
11
13
|
/** Visually hide the title (it stays the chart's accessible name): a card that already has its heading. */
|
|
@@ -22,10 +24,12 @@ interface ChartFrameProps extends ChartsSettings {
|
|
|
22
24
|
summary?: "hidden" | "visible";
|
|
23
25
|
/** Your own summary instead of the generated one (still read first by screen readers). */
|
|
24
26
|
summaryText?: string;
|
|
25
|
-
/**
|
|
27
|
+
/** “View as table” in the actions menu (the table is in the page for screen readers either way). Default true. */
|
|
26
28
|
dataTable?: boolean;
|
|
27
|
-
/**
|
|
29
|
+
/** The downloads of the actions menu: all three by default, or the formats you want, or `false` for none. */
|
|
28
30
|
exportable?: boolean | readonly ExportFormat[];
|
|
31
|
+
/** The ⋯ actions menu of the kit. `false`: the former “Show data” and export buttons, drawn in line. Default true. */
|
|
32
|
+
actionsMenu?: boolean;
|
|
29
33
|
/** Streaming data (a job queue, an auction): no entrance on updates, no announcement of every new point. */
|
|
30
34
|
live?: boolean;
|
|
31
35
|
/** The id of the figure. */
|
package/dist/funnel.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { g as Datum, A as Accessor, V as ValueFormat } from './context-
|
|
2
|
+
import { g as Datum, A as Accessor, V as ValueFormat } from './context-DNW7bJYw.js';
|
|
3
3
|
import { E as EngineProps } from './host-_F8RgiIz.js';
|
|
4
|
-
import { C as ChartFrameProps } from './frame-
|
|
4
|
+
import { C as ChartFrameProps } from './frame-B1HDNm7c.js';
|
|
5
5
|
|
|
6
6
|
interface FunnelProps<T extends Datum> extends ChartFrameProps, EngineProps {
|
|
7
7
|
/** One row per stage, first stage first. */
|
package/dist/funnel.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
Funnel
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-MRGMLDNS.js";
|
|
5
|
+
import "./chunk-NV52AKHG.js";
|
|
6
|
+
import "./chunk-PGD6SH5I.js";
|
|
7
7
|
import "./chunk-XLLYNNC6.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-P6RS2L23.js";
|
|
9
|
+
import "./chunk-OVASCEGF.js";
|
|
10
|
+
import "./chunk-GRRFPI27.js";
|
|
10
11
|
export {
|
|
11
12
|
Funnel
|
|
12
13
|
};
|
package/dist/gauge.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { V as ValueFormat, T as Threshold, j as Tone } from './context-
|
|
3
|
-
import { C as ChartFrameProps } from './frame-
|
|
2
|
+
import { V as ValueFormat, T as Threshold, j as Tone } from './context-DNW7bJYw.js';
|
|
3
|
+
import { C as ChartFrameProps } from './frame-B1HDNm7c.js';
|
|
4
4
|
|
|
5
5
|
interface GaugeZone {
|
|
6
6
|
/** The zone runs from the previous one's end (or `min`) to this value. */
|
package/dist/gauge.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import "./chunk-G2KF2WL4.js";
|
|
3
3
|
import {
|
|
4
4
|
Gauge
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OZOAKP5F.js";
|
|
6
6
|
import "./chunk-OB5EFDDH.js";
|
|
7
7
|
import "./chunk-XLLYNNC6.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-P6RS2L23.js";
|
|
9
|
+
import "./chunk-OVASCEGF.js";
|
|
10
|
+
import "./chunk-GRRFPI27.js";
|
|
10
11
|
export {
|
|
11
12
|
Gauge
|
|
12
13
|
};
|
package/dist/geo.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { g as Datum, A as Accessor, V as ValueFormat } from './context-
|
|
3
|
-
import { C as ChartFrameProps } from './frame-
|
|
2
|
+
import { g as Datum, A as Accessor, V as ValueFormat } from './context-DNW7bJYw.js';
|
|
3
|
+
import { C as ChartFrameProps } from './frame-B1HDNm7c.js';
|
|
4
4
|
|
|
5
5
|
/** A place on the map or the globe. */
|
|
6
6
|
interface GeoPoint {
|