@eifi1/ui-kit 0.52.0 → 0.53.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 (193) hide show
  1. package/README.md +47 -54
  2. package/dist/billing/cancel-subscription.d.ts +5 -14
  3. package/dist/billing/cancel-subscription.js +1 -3
  4. package/dist/billing/cancel-subscription.js.map +1 -1
  5. package/dist/billing/plan-card.d.ts +5 -13
  6. package/dist/billing/plan-card.js +3 -11
  7. package/dist/billing/plan-card.js.map +1 -1
  8. package/dist/billing/plan-switch.d.ts +5 -14
  9. package/dist/billing/plan-switch.js +1 -3
  10. package/dist/billing/plan-switch.js.map +1 -1
  11. package/dist/chart.d.ts +3 -14
  12. package/dist/chart.js +64 -11
  13. package/dist/chart.js.map +1 -1
  14. package/dist/components/date-field.d.ts +1 -1
  15. package/dist/components/date-field.js.map +1 -1
  16. package/dist/components/date-picker.d.ts +1 -1
  17. package/dist/components/date-picker.js.map +1 -1
  18. package/dist/components/date-range-picker.d.ts +4 -17
  19. package/dist/components/date-range-picker.js +2 -2
  20. package/dist/components/date-range-picker.js.map +1 -1
  21. package/dist/components/nav-pills.d.ts +1 -1
  22. package/dist/components/nav-pills.js.map +1 -1
  23. package/dist/components/series-chart-axes.d.ts +1 -1
  24. package/dist/components/series-chart-axes.js.map +1 -1
  25. package/dist/components/series-chart.d.ts +64 -19
  26. package/dist/components/series-chart.js +2 -1
  27. package/dist/components/series-chart.js.map +1 -1
  28. package/dist/components/treemap-labels.d.ts +6 -1
  29. package/dist/components/treemap-labels.js +2 -2
  30. package/dist/components/treemap-labels.js.map +1 -1
  31. package/dist/components/treemap.d.ts +29 -4
  32. package/dist/components/treemap.js +22 -9
  33. package/dist/components/treemap.js.map +1 -1
  34. package/dist/data-table.d.ts +1 -6
  35. package/dist/data-table.js +1 -9
  36. package/dist/data-table.js.map +1 -1
  37. package/dist/demo/demo-countdown.d.ts +0 -5
  38. package/dist/demo/demo-countdown.js +0 -4
  39. package/dist/demo/demo-countdown.js.map +1 -1
  40. package/dist/eslint/index.js +1 -1
  41. package/dist/feedback/feedback-mutation.d.ts +11 -23
  42. package/dist/feedback/feedback-mutation.js +1 -9
  43. package/dist/feedback/feedback-mutation.js.map +1 -1
  44. package/dist/feedback/feedback-public-list.d.ts +1 -6
  45. package/dist/feedback/feedback-public-list.js +1 -2
  46. package/dist/feedback/feedback-public-list.js.map +1 -1
  47. package/dist/feedback/feedback-row-detail-labels.js +0 -8
  48. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  49. package/dist/feedback/feedback-row-detail.d.ts +3 -50
  50. package/dist/feedback/feedback-row-detail.js +0 -8
  51. package/dist/feedback/feedback-row-detail.js.map +1 -1
  52. package/dist/feedback/feedback-status-undo.d.ts +3 -19
  53. package/dist/feedback/feedback-status-undo.js.map +1 -1
  54. package/dist/feedback/feedback-thread.d.ts +0 -9
  55. package/dist/feedback/feedback-thread.js.map +1 -1
  56. package/dist/feedback.d.ts +6 -40
  57. package/dist/feedback.js +88 -46
  58. package/dist/feedback.js.map +1 -1
  59. package/dist/i18n/defaults.js +0 -4
  60. package/dist/i18n/defaults.js.map +1 -1
  61. package/dist/i18n/german.js +2 -19
  62. package/dist/i18n/german.js.map +1 -1
  63. package/dist/i18n/kit-labels.d.ts +5 -14
  64. package/dist/i18n/kit-labels.js.map +1 -1
  65. package/dist/i18n/locales/en.js +2 -30
  66. package/dist/i18n/locales/en.js.map +3 -3
  67. package/dist/i18n/locales/es.js +2 -19
  68. package/dist/i18n/locales/es.js.map +1 -1
  69. package/dist/i18n/locales/fr.js +2 -19
  70. package/dist/i18n/locales/fr.js.map +1 -1
  71. package/dist/i18n/locales/hu.js +2 -19
  72. package/dist/i18n/locales/hu.js.map +1 -1
  73. package/dist/i18n/locales/it.js +2 -20
  74. package/dist/i18n/locales/it.js.map +1 -1
  75. package/dist/i18n/locales/zh.js +2 -19
  76. package/dist/i18n/locales/zh.js.map +1 -1
  77. package/dist/i18n/review.js +9 -4
  78. package/dist/i18n/review.js.map +1 -1
  79. package/dist/i18n/shared-labels.js +0 -1
  80. package/dist/i18n/shared-labels.js.map +1 -1
  81. package/dist/index.d.ts +15 -64
  82. package/dist/index.js +22 -102
  83. package/dist/index.js.map +1 -1
  84. package/dist/rhf/fields.d.ts +2 -2
  85. package/dist/rhf/fields.js.map +1 -1
  86. package/dist/search/search-index.d.ts +0 -6
  87. package/dist/search/search-index.js +0 -4
  88. package/dist/search/search-index.js.map +1 -1
  89. package/dist/search.d.ts +1 -8
  90. package/dist/search.js +2 -7
  91. package/dist/search.js.map +1 -1
  92. package/dist/shell/account-menu-language.d.ts +7 -21
  93. package/dist/shell/account-menu-language.js +1 -3
  94. package/dist/shell/account-menu-language.js.map +1 -1
  95. package/dist/shell/account-menu-text-size.d.ts +9 -23
  96. package/dist/shell/account-menu-text-size.js +2 -3
  97. package/dist/shell/account-menu-text-size.js.map +1 -1
  98. package/dist/shell/app-shell.d.ts +0 -10
  99. package/dist/shell/app-shell.js +1 -7
  100. package/dist/shell/app-shell.js.map +1 -1
  101. package/dist/shell/company-switcher.d.ts +1 -1
  102. package/dist/shell/company-switcher.js.map +1 -1
  103. package/dist/shell/dev-menu.d.ts +1 -1
  104. package/dist/shell/dev-menu.js.map +1 -1
  105. package/dist/shell/top-bar-parts-labels.d.ts +1 -1
  106. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  107. package/dist/shell.d.ts +7 -29
  108. package/dist/shell.js +12 -42
  109. package/dist/shell.js.map +1 -1
  110. package/dist/sync.d.ts +2 -6
  111. package/dist/sync.js +2 -15
  112. package/dist/sync.js.map +1 -1
  113. package/dist/theme/chart-palette.d.ts +0 -5
  114. package/dist/theme/chart-palette.js +0 -2
  115. package/dist/theme/chart-palette.js.map +1 -1
  116. package/package.json +1 -1
  117. package/src/billing/cancel-subscription.tsx +5 -16
  118. package/src/billing/plan-card.tsx +7 -24
  119. package/src/billing/plan-switch.tsx +5 -16
  120. package/src/chart.ts +62 -13
  121. package/src/components/date-field.tsx +1 -1
  122. package/src/components/date-picker.tsx +0 -1
  123. package/src/components/date-range-picker.tsx +6 -22
  124. package/src/components/nav-pills.tsx +1 -1
  125. package/src/components/series-chart-axes.ts +6 -1
  126. package/src/components/series-chart.tsx +78 -21
  127. package/src/components/treemap-labels.ts +11 -3
  128. package/src/components/treemap.tsx +65 -12
  129. package/src/data-table.ts +1 -11
  130. package/src/demo/demo-countdown.ts +3 -8
  131. package/src/feedback/feedback-mutation.ts +12 -33
  132. package/src/feedback/feedback-public-list.tsx +1 -7
  133. package/src/feedback/feedback-row-detail-labels.ts +0 -8
  134. package/src/feedback/feedback-row-detail.tsx +8 -58
  135. package/src/feedback/feedback-status-undo.ts +4 -18
  136. package/src/feedback/feedback-thread.tsx +0 -10
  137. package/src/feedback.ts +89 -48
  138. package/src/i18n/defaults.ts +0 -4
  139. package/src/i18n/german.ts +2 -19
  140. package/src/i18n/kit-labels.tsx +5 -14
  141. package/src/i18n/locales/es.ts +2 -19
  142. package/src/i18n/locales/fr.ts +2 -19
  143. package/src/i18n/locales/hu.ts +2 -19
  144. package/src/i18n/locales/it.ts +2 -20
  145. package/src/i18n/locales/zh.ts +2 -19
  146. package/src/i18n/review.ts +9 -4
  147. package/src/i18n/shared-labels.ts +0 -1
  148. package/src/index.ts +30 -112
  149. package/src/rhf/fields.tsx +2 -2
  150. package/src/search/search-index.ts +0 -15
  151. package/src/search.ts +8 -8
  152. package/src/shell/account-menu-language.tsx +7 -27
  153. package/src/shell/account-menu-text-size.tsx +13 -32
  154. package/src/shell/app-shell.tsx +0 -13
  155. package/src/shell/company-switcher.tsx +1 -1
  156. package/src/shell/dev-menu.tsx +1 -1
  157. package/src/shell/top-bar-parts-labels.ts +1 -1
  158. package/src/shell.ts +17 -44
  159. package/src/sync.ts +2 -15
  160. package/src/theme/chart-palette.ts +0 -2
  161. package/tokens.css +4 -4
  162. package/dist/billing/dialog-close.d.ts +0 -29
  163. package/dist/billing/dialog-close.js +0 -8
  164. package/dist/billing/dialog-close.js.map +0 -1
  165. package/dist/components/field-sync-labels.d.ts +0 -3
  166. package/dist/components/field-sync-labels.js +0 -12
  167. package/dist/components/field-sync-labels.js.map +0 -1
  168. package/dist/components/field-sync.d.ts +0 -186
  169. package/dist/components/field-sync.js +0 -269
  170. package/dist/components/field-sync.js.map +0 -1
  171. package/dist/components/section-nav.d.ts +0 -44
  172. package/dist/components/section-nav.js +0 -33
  173. package/dist/components/section-nav.js.map +0 -1
  174. package/dist/components/sign-chip-labels.d.ts +0 -3
  175. package/dist/components/sign-chip-labels.js +0 -11
  176. package/dist/components/sign-chip-labels.js.map +0 -1
  177. package/dist/components/sign-chip.d.ts +0 -77
  178. package/dist/components/sign-chip.js +0 -47
  179. package/dist/components/sign-chip.js.map +0 -1
  180. package/dist/lib/isin.d.ts +0 -38
  181. package/dist/lib/isin.js +0 -36
  182. package/dist/lib/isin.js.map +0 -1
  183. package/dist/shell/role-switcher.d.ts +0 -28
  184. package/dist/shell/role-switcher.js +0 -31
  185. package/dist/shell/role-switcher.js.map +0 -1
  186. package/src/billing/dialog-close.ts +0 -34
  187. package/src/components/field-sync-labels.ts +0 -14
  188. package/src/components/field-sync.tsx +0 -504
  189. package/src/components/section-nav.tsx +0 -72
  190. package/src/components/sign-chip-labels.ts +0 -13
  191. package/src/components/sign-chip.tsx +0 -133
  192. package/src/lib/isin.ts +0 -72
  193. package/src/shell/role-switcher.tsx +0 -53
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/series-chart-axes.ts"],"sourcesContent":["// The series chart's pure half: the axis bands, the padded and anchored domains, the\n// series keys and colours, and the abscissa reduced to a number line. No React, no\n// recharts and no JSX here (chart-zoom-core lends the one name `DEFAULT_Y_AXIS`) —\n// arithmetic over rows and axes, which is why apps import some of it in\n// files that draw no chart (Kurvenschmiede's curve-chart-model.ts builds its series\n// keys with `seriesKey`).\n//\n// Moved out of series-chart.tsx as it was (MOD-9, refactor audit 2026-10). The public\n// names are still exported from series-chart.tsx, so `/chart` and the barrel are\n// unchanged; this module is not an entry of its own. The names below that series-chart\n// does not re-export (the tick-band constants, `xModel`, `finite`, …) stay internal.\nimport { DEFAULT_Y_AXIS } from \"./chart-zoom-core\";\nimport type { TimeTickUnit } from \"./series-chart-ticks\";\nimport { paletteFor } from \"../theme/chart-palette\";\nimport type {\n SeriesChartAxis,\n SeriesChartRow,\n SeriesChartSeries,\n SeriesChartTickValues,\n SeriesChartX,\n SeriesChartXValue,\n} from \"./series-chart\";\n\n/** How much of an axis band the rotated title takes, in px at Normal — × the text size's\n * scale on the chart (§3.2), since the title is text. Reserved rather than shared with\n * the ticks: a title merely offset inside the band prints on top of a five-figure tick,\n * and which gives way depends on the data. */\nexport const AXIS_TITLE_STRIP = 16;\n\n/** Where inside its strip the rotated title sits. */\nexport const AXIS_TITLE_OFFSET = 10;\n\n/** The tallest band tilted x ticks reserve, in px at Normal (× the scale). A category\n * name longer than this at its angle is clipped rather than squeezing the plot down to\n * a strip. */\nconst MAX_TILTED_TICK_BAND = 120;\n\n/** What one character of a tick label is taken to be, in px at Normal, for the tilted\n * band — the shell's `text-xs`. An estimate: the SVG is not laid out yet when the band\n * is decided. Both grow with the text size, as `text-xs` does (§3.2). */\nconst TICK_CHAR_WIDTH = 7;\nconst TICK_LINE_HEIGHT = 12;\n/** recharts' gap between the axis line and a bottom tick's text — px, at every size:\n * recharts draws it, not the type. */\nconst TICK_GAP = 8;\n/** recharts' own band under level x ticks. */\nconst LEVEL_TICK_BAND = 30;\n/** The least room recharts' x ticks keep between labels, in px at Normal. */\nexport const MIN_TICK_GAP = 32;\n\n/**\n * The height the x axis reserves for its ticks at a text `scale`: tilted by `angle`\n * degrees, the rotated box of the longest label, from its length; level, recharts' own\n * 30 px grown with the labels. `undefined` for level ticks at Normal, where recharts'\n * default is exactly that.\n */\nexport function tiltedTickBand(labels: readonly string[], angle: number, scale = 1): number | undefined {\n if (!angle) return scale === 1 ? undefined : Math.ceil(LEVEL_TICK_BAND * scale);\n const rad = (Math.abs(angle) * Math.PI) / 180;\n const longest = Math.max(0, ...labels.map((label) => label.length)) * TICK_CHAR_WIDTH * scale;\n const band = Math.sin(rad) * longest + Math.cos(rad) * TICK_LINE_HEIGHT * scale + TICK_GAP;\n return Math.min(\n Math.round(MAX_TILTED_TICK_BAND * scale),\n Math.max(Math.ceil(LEVEL_TICK_BAND * scale), Math.ceil(band)),\n );\n}\n\n/** The width the ticks of a y axis get when a caller does not say, in px at Normal. */\nexport const AXIS_TICK_WIDTH = 48;\n\n/**\n * How much air a FITTED axis leaves between the data and its frame, as a fraction of\n * the range. Recharts fits `[dataMin, dataMax]`, which draws a peak half a stroke\n * outside the plot and a curve running to its limit indistinguishable from the frame.\n */\nconst AUTO_PAD = 0.04;\n\n/** The band a fitted axis draws, padded — and a real band for constant data, which is\n * a zero-height domain recharts cannot scale into. `undefined` when nothing finite. */\nexport function paddedDomain(values: Iterable<number>): [number, number] | undefined {\n let low = Infinity;\n let high = -Infinity;\n for (const value of values) {\n if (!Number.isFinite(value)) continue;\n if (value < low) low = value;\n if (value > high) high = value;\n }\n return padBand(low, high);\n}\n\n/**\n * {@link paddedDomain} for a caller that has already walked its own data — so a row\n * of charts can share one scale without building an array to find two numbers in, and\n * without a second padding rule. `low > high` means \"nothing was seen\": `undefined`.\n */\nexport function padBand(low: number, high: number): [number, number] | undefined {\n if (!(low <= high)) return undefined;\n const pad = (high - low) * AUTO_PAD || Math.abs(high) * AUTO_PAD || 1;\n return [low - pad, high + pad];\n}\n\n/**\n * The whole band a y axis occupies: its ticks, and its title when it draws one. For\n * lining a heading up over a PLOT rather than over its column.\n *\n * `scale` is the text size's (`useTextSize().scale`, §3.2, §10.10): the chart draws every\n * band — the default 48 px and a caller's own `width` alike (keksdose's\n * `MONEY_AXIS_WIDTH`) — this many times wider, because the ticks in it are `text-xs`\n * and grow with the text. A heading lined up over the plot has to pass the same scale.\n * One factor for both sides of a facing pair, so the mirrored bands stay equal.\n */\nexport function axisBandWidth(tickWidth: number | undefined, titled: boolean, scale = 1): number {\n const band = (tickWidth ?? AXIS_TICK_WIDTH) + (titled ? AXIS_TITLE_STRIP : 0);\n return scale === 1 ? band : Math.round(band * scale);\n}\n\n/**\n * The colour an axis TITLE takes, or `undefined` for the neutral one.\n *\n * An axis measuring exactly one line is that line's, and saying so in the title lets a\n * reader find a channel's scale without counting axes. An axis measuring several is\n * nobody's — a title in the first one's colour would be claiming it. Counted off the\n * series, so toggling a second line onto an axis gives the colour up in the same render.\n */\nexport function soleSeriesColor(\n axis: Pick<SeriesChartAxis, \"id\" | \"color\">,\n series: readonly Pick<SeriesChartSeries, \"axis\">[],\n): string | undefined {\n const mine = series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id);\n return mine.length === 1 ? axis.color : undefined;\n}\n\n/** The single-axis case, which is most charts. `width` is what the TICKS need;\n * `orientation` is which side they stand on. */\nexport function oneAxis(\n format: ((value: number) => string) | undefined,\n title: string,\n width?: number,\n orientation?: \"left\" | \"right\",\n): SeriesChartAxis[] {\n return [{ id: DEFAULT_Y_AXIS, format, title, width, orientation }];\n}\n\n/** One source's samples: an abscissa and the channels measured against it. */\nexport interface SeriesSource {\n x: readonly number[];\n channels: Readonly<Record<string, readonly number[]>>;\n}\n\n/**\n * Merge sources sampled on different grids into rows the chart can draw.\n *\n * Merged ON THE ABSCISSA VALUE ITSELF, never interpolated onto a common grid: a line\n * through invented points looks exactly like one through measured ones. Where a source\n * has no sample the key is absent, and `connectNulls` bridges the hole with the same\n * straight segment an interpolation would have drawn — without claiming a measurement.\n */\nexport function mergeSeries(sources: readonly SeriesSource[]): Record<string, number>[] {\n const byAbscissa = new Map<number, Record<string, number>>();\n for (const source of sources) {\n source.x.forEach((value, index) => {\n const row = byAbscissa.get(value) ?? { x: value };\n for (const [key, channel] of Object.entries(source.channels)) row[key] = channel[index];\n byAbscissa.set(value, row);\n });\n }\n return [...byAbscissa.values()].sort((a, b) => a.x - b.x);\n}\n\n/**\n * A series key built out of parts — as a CSS identifier.\n *\n * The chart shell paints each series through `--color-<key>`, and skips (with a\n * console warning) any key that is not `[A-Za-z_][A-Za-z0-9_-]*`. A line whose colour\n * was skipped has no stroke at all: an axis, a grid and nothing between them. So a key\n * assembled out of DATA — an id, an enum, a side — goes through here: every other\n * character becomes `_`, the parts are joined with `_`, and a key that would start with\n * a digit or a hyphen gets a leading `_`.\n */\nexport function seriesKey(...parts: (string | number)[]): string {\n const key = parts.map((part) => String(part).replace(/[^A-Za-z0-9_-]/g, \"_\")).join(\"_\");\n return /^[A-Za-z_]/.test(key) ? key : `_${key}`;\n}\n\n/**\n * The band an axis carrying bars or areas draws: the data's extent with ZERO in it,\n * padded only on the sides that are not zero — bars standing on a frame's bottom edge,\n * not floating four per cent above it on a band of air nobody asked for.\n * `undefined` when there is nothing to fit.\n *\n * All-zero data (a quiet period, a zoom window over empty months) is `[0, 1]`: one unit\n * on the free side, the unit {@link padBand} pads a zero extent by. d3 maps every value\n * of a zero-height domain to the range's midpoint, so `[0, 0]` stood the bars on a\n * baseline in the middle of the plot, the \"0\" tick beside it (audit 2026-10-30 DSP-10;\n * keksdose's weekday pattern drew seven 4 px stubs mid-card for a period with no\n * spending).\n */\nexport function anchoredBand(extent: readonly [number, number] | undefined): [number, number] | undefined {\n if (!extent) return undefined;\n const low = Math.min(0, extent[0]);\n const high = Math.max(0, extent[1]);\n if (low === 0 && high === 0) return [0, 1];\n const pad = (high - low) * AUTO_PAD || 1;\n return [low < 0 ? low - pad : 0, high > 0 ? high + pad : 0];\n}\n\n/**\n * Series with their colours settled BEFORE any are switched off.\n *\n * A series with no `color` takes `paletteFor(its position)` — and a legend toggle that\n * hands the chart a shorter list moves every later series one position up, repainting\n * it in its neighbour's colour on each click. Resolving the colours on the full list\n * and filtering after keeps each series in the colour its legend entry shows.\n */\nexport function visibleSeries(series: readonly SeriesChartSeries[], hidden: ReadonlySet<string>): SeriesChartSeries[] {\n return series\n .map((entry, index) => ({ ...entry, color: entry.color ?? paletteFor(index) }))\n .filter((entry) => !hidden.has(entry.key));\n}\n\n/** Where a category or time chart keeps each row's plotted position. Not the caller's\n * key: that one still holds their own value, which `format` and a hit hand back. */\nconst PLOTTED_X = \"__seriesChartX\";\n\n/** A finite number, or `undefined` — the only thing a row cell counts as a sample. */\nexport const finite = (value: unknown): number | undefined =>\n typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n\n/** A time value as epoch ms. A date-only ISO string is LOCAL midnight (see\n * `SeriesChartX.type`); anything unreadable is `undefined`, i.e. not plotted. */\nfunction toTime(value: unknown): number | undefined {\n if (value instanceof Date) return finite(value.getTime());\n if (typeof value === \"number\") return finite(value);\n if (typeof value !== \"string\") return undefined;\n const day = /^(\\d{4})-(\\d{2})(?:-(\\d{2}))?$/.exec(value);\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3] ?? 1)).getTime();\n return finite(Date.parse(value));\n}\n\n/** A category's identity, so a Date matches another Date of the same instant. */\nconst categoryId = (value: unknown) =>\n value instanceof Date ? `d:${value.getTime()}` : `${typeof value}:${String(value)}`;\n\n/**\n * The abscissa, reduced to a number line — which is all the plot, the ticks and the\n * zoom ever deal in. A number stays itself; a category becomes its slot index; a time\n * its epoch ms. Everything the caller sees (ticks, tooltip, hits) is turned back.\n */\nexport interface XModel {\n kind: \"number\" | \"category\" | \"time\";\n /** The caller's key, still holding their value. */\n sourceKey: string;\n /** The key the plot reads. The same as `sourceKey` on a number line. */\n plotKey: string;\n /** The rows as plotted. The caller's own on a number line. */\n rows: readonly SeriesChartRow[];\n /** The caller's rows, which dots and hits hand back. */\n source: readonly SeriesChartRow[];\n position: (value: unknown) => number | undefined;\n valueAt: (position: number) => SeriesChartXValue;\n}\n\nexport function xModel(rows: readonly SeriesChartRow[], x: SeriesChartX): XModel {\n const sourceKey = x.key ?? \"x\";\n if (x.type === \"category\") {\n const slots = new Map<string, number>();\n rows.forEach((row, index) => {\n const id = categoryId(row[sourceKey]);\n if (!slots.has(id)) slots.set(id, index);\n });\n return {\n kind: \"category\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row, index) => ({ ...row, [PLOTTED_X]: index })),\n source: rows,\n position: (value) => slots.get(categoryId(value)),\n valueAt: (position) => rows[Math.round(position)]?.[sourceKey] as SeriesChartXValue,\n };\n }\n if (x.type === \"time\") {\n return {\n kind: \"time\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row) => ({ ...row, [PLOTTED_X]: toTime(row[sourceKey]) })),\n source: rows,\n position: toTime,\n valueAt: (position) => new Date(position),\n };\n }\n return {\n kind: \"number\",\n sourceKey,\n plotKey: sourceKey,\n rows,\n source: rows,\n position: finite,\n valueAt: (position) => position,\n };\n}\n\n/** Caller ticks, as positions inside the domain on show. */\nexport function resolveTicks<T>(\n values: SeriesChartTickValues<T> | undefined,\n domain: [number, number] | undefined,\n position: (value: T) => number | undefined,\n): number[] | undefined {\n if (!values || !domain) return undefined;\n const list = typeof values === \"function\" ? values(domain) : values;\n if (!list) return undefined;\n const slack = (domain[1] - domain[0]) * 1e-9;\n return list\n .map(position)\n .filter((at): at is number => at !== undefined && at >= domain[0] - slack && at <= domain[1] + slack);\n}\n\n/** A low/high pair widened by some values, or `undefined` if there is still none. */\nexport function extend(\n span: readonly [number, number] | undefined,\n values: readonly (number | undefined)[],\n): [number, number] | undefined {\n let out: [number, number] | undefined = span ? [span[0], span[1]] : undefined;\n for (const value of values) {\n if (value === undefined || !Number.isFinite(value)) continue;\n out = out ? [Math.min(out[0], value), Math.max(out[1], value)] : [value, value];\n }\n return out;\n}\n\n/** How a time tick is written, by what one step of the ticks is. */\nexport const TIME_TICK_FORMAT: Record<TimeTickUnit, Intl.DateTimeFormatOptions> = {\n hour: { hour: \"2-digit\", minute: \"2-digit\" },\n day: { day: \"numeric\", month: \"short\" },\n month: { month: \"short\", year: \"2-digit\" },\n year: { year: \"numeric\" },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/series-chart-axes.ts"],"sourcesContent":["// The series chart's pure half: the axis bands, the padded and anchored domains, the\n// series keys and colours, and the abscissa reduced to a number line. No React, no\n// recharts and no JSX here (chart-zoom-core lends the one name `DEFAULT_Y_AXIS`) —\n// arithmetic over rows and axes, which is why apps import some of it in\n// files that draw no chart (Kurvenschmiede's curve-chart-model.ts builds its series\n// keys with `seriesKey`).\n//\n// Moved out of series-chart.tsx as it was (MOD-9, refactor audit 2026-10). The public\n// names are still exported from series-chart.tsx, so `/chart` and the barrel are\n// unchanged; this module is not an entry of its own. The names below that series-chart\n// does not re-export (the tick-band constants, `xModel`, `finite`, …) stay internal.\nimport { DEFAULT_Y_AXIS } from \"./chart-zoom-core\";\nimport type { TimeTickUnit } from \"./series-chart-ticks\";\nimport { paletteFor } from \"../theme/chart-palette\";\nimport type {\n SeriesChartAxis,\n SeriesChartRow,\n SeriesChartSeries,\n SeriesChartTickValues,\n SeriesChartX,\n SeriesChartXValue,\n} from \"./series-chart\";\n\n/** How much of an axis band the rotated title takes, in px at Normal — × the text size's\n * scale on the chart (§3.2), since the title is text. Reserved rather than shared with\n * the ticks: a title merely offset inside the band prints on top of a five-figure tick,\n * and which gives way depends on the data. */\nexport const AXIS_TITLE_STRIP = 16;\n\n/** Where inside its strip the rotated title sits. */\nexport const AXIS_TITLE_OFFSET = 10;\n\n/** The tallest band tilted x ticks reserve, in px at Normal (× the scale). A category\n * name longer than this at its angle is clipped rather than squeezing the plot down to\n * a strip. */\nconst MAX_TILTED_TICK_BAND = 120;\n\n/** What one character of a tick label is taken to be, in px at Normal, for the tilted\n * band — the shell's `text-xs`. An estimate: the SVG is not laid out yet when the band\n * is decided. Both grow with the text size, as `text-xs` does (§3.2). */\nconst TICK_CHAR_WIDTH = 7;\nconst TICK_LINE_HEIGHT = 12;\n/** recharts' gap between the axis line and a bottom tick's text — px, at every size:\n * recharts draws it, not the type. */\nconst TICK_GAP = 8;\n/** recharts' own band under level x ticks. */\nconst LEVEL_TICK_BAND = 30;\n/** The least room recharts' x ticks keep between labels, in px at Normal. */\nexport const MIN_TICK_GAP = 32;\n\n/**\n * The height the x axis reserves for its ticks at a text `scale`: tilted by `angle`\n * degrees, the rotated box of the longest label, from its length; level, recharts' own\n * 30 px grown with the labels. `undefined` for level ticks at Normal, where recharts'\n * default is exactly that.\n */\nexport function tiltedTickBand(labels: readonly string[], angle: number, scale = 1): number | undefined {\n if (!angle) return scale === 1 ? undefined : Math.ceil(LEVEL_TICK_BAND * scale);\n const rad = (Math.abs(angle) * Math.PI) / 180;\n const longest = Math.max(0, ...labels.map((label) => label.length)) * TICK_CHAR_WIDTH * scale;\n const band = Math.sin(rad) * longest + Math.cos(rad) * TICK_LINE_HEIGHT * scale + TICK_GAP;\n return Math.min(\n Math.round(MAX_TILTED_TICK_BAND * scale),\n Math.max(Math.ceil(LEVEL_TICK_BAND * scale), Math.ceil(band)),\n );\n}\n\n/** The width the ticks of a y axis get when a caller does not say, in px at Normal. */\nexport const AXIS_TICK_WIDTH = 48;\n\n/**\n * How much air a FITTED axis leaves between the data and its frame, as a fraction of\n * the range. Recharts fits `[dataMin, dataMax]`, which draws a peak half a stroke\n * outside the plot and a curve running to its limit indistinguishable from the frame.\n */\nconst AUTO_PAD = 0.04;\n\n/** The band a fitted axis draws, padded — and a real band for constant data, which is\n * a zero-height domain recharts cannot scale into. `undefined` when nothing finite. */\nexport function paddedDomain(values: Iterable<number>): [number, number] | undefined {\n let low = Infinity;\n let high = -Infinity;\n for (const value of values) {\n if (!Number.isFinite(value)) continue;\n if (value < low) low = value;\n if (value > high) high = value;\n }\n return padBand(low, high);\n}\n\n/**\n * {@link paddedDomain} for a caller that has already walked its own data — so a row\n * of charts can share one scale without building an array to find two numbers in, and\n * without a second padding rule. `low > high` means \"nothing was seen\": `undefined`.\n */\nexport function padBand(low: number, high: number): [number, number] | undefined {\n if (!(low <= high)) return undefined;\n const pad = (high - low) * AUTO_PAD || Math.abs(high) * AUTO_PAD || 1;\n return [low - pad, high + pad];\n}\n\n/**\n * The whole band a y axis occupies: its ticks, and its title when it draws one. For\n * lining a heading up over a PLOT rather than over its column.\n *\n * `scale` is the text size's (`useTextSize().scale`, §3.2, §10.10): the chart draws every\n * band — the default 48 px and a caller's own `width` alike (keksdose's\n * `MONEY_AXIS_WIDTH`) — this many times wider, because the ticks in it are `text-xs`\n * and grow with the text. A heading lined up over the plot has to pass the same scale.\n * One factor for both sides of a facing pair, so the mirrored bands stay equal.\n */\nexport function axisBandWidth(tickWidth: number | undefined, titled: boolean, scale = 1): number {\n const band = (tickWidth ?? AXIS_TICK_WIDTH) + (titled ? AXIS_TITLE_STRIP : 0);\n return scale === 1 ? band : Math.round(band * scale);\n}\n\n/**\n * The colour an axis TITLE takes, or `undefined` for the neutral one.\n *\n * An axis measuring exactly one line is that line's, and saying so in the title lets a\n * reader find a channel's scale without counting axes. An axis measuring several is\n * nobody's — a title in the first one's colour would be claiming it. Counted off the\n * series, so toggling a second line onto an axis gives the colour up in the same render.\n */\nexport function soleSeriesColor(\n axis: Pick<SeriesChartAxis, \"id\" | \"color\">,\n series: readonly Pick<SeriesChartSeries, \"axis\">[],\n): string | undefined {\n const mine = series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id);\n return mine.length === 1 ? axis.color : undefined;\n}\n\n/** The single-axis case, which is most charts. `width` is what the TICKS need;\n * `orientation` is which side they stand on. */\nexport function oneAxis(\n format: ((value: number) => string) | undefined,\n title: string,\n width?: number,\n orientation?: \"left\" | \"right\",\n): SeriesChartAxis[] {\n return [{ id: DEFAULT_Y_AXIS, format, title, width, orientation }];\n}\n\n/** One source's samples: an abscissa and the channels measured against it. */\nexport interface SeriesSource {\n x: readonly number[];\n channels: Readonly<Record<string, readonly number[]>>;\n}\n\n/**\n * Merge sources sampled on different grids into rows the chart can draw.\n *\n * Merged ON THE ABSCISSA VALUE ITSELF, never interpolated onto a common grid: a line\n * through invented points looks exactly like one through measured ones. Where a source\n * has no sample the key is absent, and `connectNulls` bridges the hole with the same\n * straight segment an interpolation would have drawn — without claiming a measurement.\n */\nexport function mergeSeries(sources: readonly SeriesSource[]): Record<string, number>[] {\n const byAbscissa = new Map<number, Record<string, number>>();\n for (const source of sources) {\n source.x.forEach((value, index) => {\n const row = byAbscissa.get(value) ?? { x: value };\n for (const [key, channel] of Object.entries(source.channels)) row[key] = channel[index];\n byAbscissa.set(value, row);\n });\n }\n return [...byAbscissa.values()].sort((a, b) => a.x - b.x);\n}\n\n/**\n * A series key built out of parts — as a CSS identifier.\n *\n * The chart shell paints each series through `--color-<key>`, and skips (with a\n * console warning) any key that is not `[A-Za-z_][A-Za-z0-9_-]*`. A line whose colour\n * was skipped has no stroke at all: an axis, a grid and nothing between them. So a key\n * assembled out of DATA — an id, an enum, a side — goes through here: every other\n * character becomes `_`, the parts are joined with `_`, and a key that would start with\n * a digit or a hyphen gets a leading `_`.\n */\nexport function seriesKey(...parts: (string | number)[]): string {\n const key = parts.map((part) => String(part).replace(/[^A-Za-z0-9_-]/g, \"_\")).join(\"_\");\n return /^[A-Za-z_]/.test(key) ? key : `_${key}`;\n}\n\n/**\n * The band an axis carrying bars or areas draws: the data's extent with ZERO in it,\n * padded only on the sides that are not zero — bars standing on a frame's bottom edge,\n * not floating four per cent above it on a band of air nobody asked for.\n * `undefined` when there is nothing to fit.\n *\n * All-zero data (a quiet period, a zoom window over empty months) is `[0, 1]`: one unit\n * on the free side, the unit {@link padBand} pads a zero extent by. d3 maps every value\n * of a zero-height domain to the range's midpoint, so `[0, 0]` stood the bars on a\n * baseline in the middle of the plot, the \"0\" tick beside it (audit 2026-10-30 DSP-10;\n * keksdose's weekday pattern drew seven 4 px stubs mid-card for a period with no\n * spending).\n */\nexport function anchoredBand(extent: readonly [number, number] | undefined): [number, number] | undefined {\n if (!extent) return undefined;\n const low = Math.min(0, extent[0]);\n const high = Math.max(0, extent[1]);\n if (low === 0 && high === 0) return [0, 1];\n const pad = (high - low) * AUTO_PAD || 1;\n return [low < 0 ? low - pad : 0, high > 0 ? high + pad : 0];\n}\n\n/**\n * Series with their colours settled BEFORE any are switched off.\n *\n * A series with no `color` takes `paletteFor(its position)` — and a legend toggle that\n * hands the chart a shorter list moves every later series one position up, repainting\n * it in its neighbour's colour on each click. Resolving the colours on the full list\n * and filtering after keeps each series in the colour its legend entry shows.\n */\n// Generic so a typed list comes back typed (0.53): a chart of `Month` rows takes it, and\n// its `dot`s still read `point.row` as a `Month`.\nexport function visibleSeries<TRow extends object>(\n series: readonly SeriesChartSeries<TRow>[],\n hidden: ReadonlySet<string>,\n): SeriesChartSeries<TRow>[] {\n return series\n .map((entry, index) => ({ ...entry, color: entry.color ?? paletteFor(index) }))\n .filter((entry) => !hidden.has(entry.key));\n}\n\n/** Where a category or time chart keeps each row's plotted position. Not the caller's\n * key: that one still holds their own value, which `format` and a hit hand back. */\nconst PLOTTED_X = \"__seriesChartX\";\n\n/** A finite number, or `undefined` — the only thing a row cell counts as a sample. */\nexport const finite = (value: unknown): number | undefined =>\n typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n\n/** A time value as epoch ms. A date-only ISO string is LOCAL midnight (see\n * `SeriesChartX.type`); anything unreadable is `undefined`, i.e. not plotted. */\nfunction toTime(value: unknown): number | undefined {\n if (value instanceof Date) return finite(value.getTime());\n if (typeof value === \"number\") return finite(value);\n if (typeof value !== \"string\") return undefined;\n const day = /^(\\d{4})-(\\d{2})(?:-(\\d{2}))?$/.exec(value);\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3] ?? 1)).getTime();\n return finite(Date.parse(value));\n}\n\n/** A category's identity, so a Date matches another Date of the same instant. */\nconst categoryId = (value: unknown) =>\n value instanceof Date ? `d:${value.getTime()}` : `${typeof value}:${String(value)}`;\n\n/**\n * The abscissa, reduced to a number line — which is all the plot, the ticks and the\n * zoom ever deal in. A number stays itself; a category becomes its slot index; a time\n * its epoch ms. Everything the caller sees (ticks, tooltip, hits) is turned back.\n */\nexport interface XModel {\n kind: \"number\" | \"category\" | \"time\";\n /** The caller's key, still holding their value. */\n sourceKey: string;\n /** The key the plot reads. The same as `sourceKey` on a number line. */\n plotKey: string;\n /** The rows as plotted. The caller's own on a number line. */\n rows: readonly SeriesChartRow[];\n /** The caller's rows, which dots and hits hand back. */\n source: readonly SeriesChartRow[];\n position: (value: unknown) => number | undefined;\n valueAt: (position: number) => SeriesChartXValue;\n}\n\nexport function xModel(rows: readonly SeriesChartRow[], x: SeriesChartX): XModel {\n const sourceKey = x.key ?? \"x\";\n if (x.type === \"category\") {\n const slots = new Map<string, number>();\n rows.forEach((row, index) => {\n const id = categoryId(row[sourceKey]);\n if (!slots.has(id)) slots.set(id, index);\n });\n return {\n kind: \"category\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row, index) => ({ ...row, [PLOTTED_X]: index })),\n source: rows,\n position: (value) => slots.get(categoryId(value)),\n valueAt: (position) => rows[Math.round(position)]?.[sourceKey] as SeriesChartXValue,\n };\n }\n if (x.type === \"time\") {\n return {\n kind: \"time\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row) => ({ ...row, [PLOTTED_X]: toTime(row[sourceKey]) })),\n source: rows,\n position: toTime,\n valueAt: (position) => new Date(position),\n };\n }\n return {\n kind: \"number\",\n sourceKey,\n plotKey: sourceKey,\n rows,\n source: rows,\n position: finite,\n valueAt: (position) => position,\n };\n}\n\n/** Caller ticks, as positions inside the domain on show. */\nexport function resolveTicks<T>(\n values: SeriesChartTickValues<T> | undefined,\n domain: [number, number] | undefined,\n position: (value: T) => number | undefined,\n): number[] | undefined {\n if (!values || !domain) return undefined;\n const list = typeof values === \"function\" ? values(domain) : values;\n if (!list) return undefined;\n const slack = (domain[1] - domain[0]) * 1e-9;\n return list\n .map(position)\n .filter((at): at is number => at !== undefined && at >= domain[0] - slack && at <= domain[1] + slack);\n}\n\n/** A low/high pair widened by some values, or `undefined` if there is still none. */\nexport function extend(\n span: readonly [number, number] | undefined,\n values: readonly (number | undefined)[],\n): [number, number] | undefined {\n let out: [number, number] | undefined = span ? [span[0], span[1]] : undefined;\n for (const value of values) {\n if (value === undefined || !Number.isFinite(value)) continue;\n out = out ? [Math.min(out[0], value), Math.max(out[1], value)] : [value, value];\n }\n return out;\n}\n\n/** How a time tick is written, by what one step of the ticks is. */\nexport const TIME_TICK_FORMAT: Record<TimeTickUnit, Intl.DateTimeFormatOptions> = {\n hour: { hour: \"2-digit\", minute: \"2-digit\" },\n day: { day: \"numeric\", month: \"short\" },\n month: { month: \"short\", year: \"2-digit\" },\n year: { year: \"numeric\" },\n};\n"],"mappings":"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","names":[]}
@@ -10,7 +10,14 @@ export { AXIS_TICK_WIDTH, AXIS_TITLE_STRIP, anchoredBand, axisBandWidth, mergeSe
10
10
  export type { SeriesSource } from "./series-chart-axes.js";
11
11
  import { type ChartTooltipPlacement, type LabelOverride } from "../i18n/kit-labels.js";
12
12
  import { type ChartHeight } from "./chart-height.js";
13
- export interface SeriesChartSeries {
13
+ /**
14
+ * One line, area or bar run of a {@link SeriesChart}.
15
+ *
16
+ * `TRow` is the chart's row type (0.53, keksdose after 0.52), and only `dot` reads it: its
17
+ * `point.row` is that type. Without a type argument a series is what it was, and a chart
18
+ * of typed rows still takes it — see {@link SeriesChartProps}.
19
+ */
20
+ export interface SeriesChartSeries<TRow extends object = object> {
14
21
  /** The row key this line reads — and the `--color-<key>` it is painted with, so it
15
22
  * must be a CSS identifier. Build keys out of data with {@link seriesKey}. */
16
23
  key: string;
@@ -58,8 +65,9 @@ export interface SeriesChartSeries {
58
65
  * point: `true` for the default dot, `false`/`null` for none, or any SVG node drawn
59
66
  * as-is at `point.cx`/`point.cy` — a buy/sell marker on keksdose's paper price.
60
67
  * Never called for a point with no value. Bars have no points, and ignore it.
68
+ * `point.row` is the caller's own row, typed as the chart's rows are (0.53).
61
69
  */
62
- dot?: boolean | ((point: SeriesChartPoint) => ReactNode);
70
+ dot?: boolean | ((point: SeriesChartPoint<TRow>) => ReactNode);
63
71
  /** Line (or area outline) weight in px. Default 2, or 1.5 for a `step`. keksdose
64
72
  * draws the subject of a chart at 2.5 and the reference it is read against at 1.5. */
65
73
  strokeWidth?: number;
@@ -94,14 +102,16 @@ export interface SeriesChartSeries {
94
102
  }
95
103
  /** What a series draws. See {@link SeriesChartSeries.type}. */
96
104
  export type SeriesChartType = "line" | "bar" | "area";
97
- /** One point of a series, as a `dot` function is handed it. */
98
- export interface SeriesChartPoint {
105
+ /** One point of a series, as a `dot` function is handed it. `TRow` is the chart's row
106
+ * type (0.53); without one, `row` is a {@link SeriesChartRow}, as before. */
107
+ export interface SeriesChartPoint<TRow extends object = object> {
99
108
  /** The series' key. */
100
109
  key: string;
101
110
  /** The row's position in `rows`. */
102
111
  index: number;
103
- /** The caller's own row, with everything the chart did not plot still in it. */
104
- row: SeriesChartRow;
112
+ /** The caller's own row, with everything the chart did not plot still in it: the very
113
+ * object in `rows`, typed as `rows` is. */
114
+ row: SeriesChartRowOf<TRow>;
105
115
  /** The abscissa in the caller's terms: the number, the category, or (time) a Date. */
106
116
  x: SeriesChartXValue;
107
117
  value: number;
@@ -113,8 +123,26 @@ export interface SeriesChartPoint {
113
123
  }
114
124
  /** A row of a series chart: one abscissa value and the series' values at it. Anything
115
125
  * else in it (a raw ISO period for a drilldown) rides along untouched and is handed
116
- * back in {@link SeriesChartPoint.row} and {@link SeriesChartHit.row}. */
126
+ * back in {@link SeriesChartPoint.row} and {@link SeriesChartHit.row} — typed as the
127
+ * caller's rows are since 0.53, and as this where their type names no keys. */
117
128
  export type SeriesChartRow = Readonly<Record<string, unknown>>;
129
+ /**
130
+ * The row a hit or a point hands back, for a chart whose rows are `TRow[]` (0.53, keksdose
131
+ * after 0.52): `TRow` itself, so a drilldown reads `hit.row.rawPeriod` as the string it
132
+ * is. A {@link SeriesChartRow} where `TRow` names no keys — `object`, the default, which
133
+ * keeps `SeriesChartHit` and `SeriesChartPoint` without a type argument what they were, and
134
+ * the `object[]` rows an app passes today; `{}`; and `any` or `never` (`rows={[]}`), which
135
+ * are both assignable to `null` while no object type is.
136
+ *
137
+ * Both tests take `TRow` in the CHECKED position, never in the `extends` one, so TypeScript
138
+ * measures every type below as covariant in it (`SeriesChartSeries`, through `dot`'s
139
+ * parameter, contravariant) and relates two of them by their type arguments alone: a
140
+ * `SeriesChartHit<Month>` is a `SeriesChartHit`, and a handler or a series typed without an
141
+ * argument fits a chart of `Month` rows, though an interface has no index signature and is
142
+ * not, field by field, a `SeriesChartRow`. Written `object extends TRow ?`, the type is
143
+ * invariant and both of those stop type-checking.
144
+ */
145
+ type SeriesChartRowOf<TRow> = [TRow] extends [null] ? SeriesChartRow : [keyof TRow] extends [never] ? SeriesChartRow : TRow;
118
146
  /** An abscissa value: a number (`x.type: "number"`), a category (a string, a number or
119
147
  * a Date standing for a period), or a time (a Date, epoch ms or an ISO string). */
120
148
  export type SeriesChartXValue = number | string | Date;
@@ -406,28 +434,41 @@ export interface SeriesChartMarker {
406
434
  /** Radius in px. Default 4.5. */
407
435
  r?: number;
408
436
  }
409
- /** What a click on the plot picked. */
410
- export interface SeriesChartHit {
437
+ /** What a click on the plot picked. `TRow` is the chart's row type (0.53); without one,
438
+ * `row` is a {@link SeriesChartRow}, as before. */
439
+ export interface SeriesChartHit<TRow extends object = object> {
411
440
  /** The row's position in `rows`. */
412
441
  index: number;
413
- /** The caller's own row — with its `rawPeriod`, id or whatever the drilldown needs. */
414
- row: SeriesChartRow;
442
+ /** The caller's own row — with its `rawPeriod`, id or whatever the drilldown needs: the
443
+ * very object in `rows`, typed as `rows` is, so it is read without a cast. */
444
+ row: SeriesChartRowOf<TRow>;
415
445
  x: SeriesChartXValue;
416
446
  /** The series, when the click landed ON a bar. A click anywhere else picks the slot
417
447
  * (the period), not a series. */
418
448
  key?: string;
419
449
  }
420
- export interface SeriesChartProps {
450
+ /**
451
+ * The props of {@link SeriesChart} and {@link StaticSeriesChart}, for rows of type `TRow`.
452
+ *
453
+ * `TRow` is inferred from `rows` (0.53, keksdose after 0.52), and what the chart hands back
454
+ * — `hit.row` in `onPointClick`, `point.row` in a series' `dot` — is that type, so a
455
+ * drilldown reads its own fields without narrowing an `unknown`. Without a type argument,
456
+ * `SeriesChartProps` is what it was: any object is a row, and a row comes back as a
457
+ * {@link SeriesChartRow}. So is `ComponentProps<typeof SeriesChart>`, which reads the
458
+ * constraint, `object`. A series, a handler or a `dot` typed without an argument fits a
459
+ * chart of typed rows too.
460
+ */
461
+ export interface SeriesChartProps<TRow extends object = object> {
421
462
  /**
422
463
  * One row per abscissa value. A missing key is a hole (see `connectNulls`).
423
464
  *
424
465
  * Any object (0.52, refactor audit 2026-10-30, API-2): an `interface` has no index
425
466
  * signature, so a typed sweep did not fit `SeriesChartRow` and Kurvenschmiede cast its
426
467
  * Ackermann rows `as unknown as Record<string, number>[]`. The chart reads the keys
427
- * `series` and `x` name, and hands the row back as {@link SeriesChartRow}.
468
+ * `series` and `x` name, and hands the row back typed as these are (0.53).
428
469
  */
429
- rows: readonly object[];
430
- series: readonly SeriesChartSeries[];
470
+ rows: readonly TRow[];
471
+ series: readonly SeriesChartSeries<TRow>[];
431
472
  /** Default: one untitled axis, `"y"`. */
432
473
  axes?: readonly SeriesChartAxis[];
433
474
  x?: SeriesChartX;
@@ -482,7 +523,7 @@ export interface SeriesChartProps {
482
523
  * a chart without bars, named "period — series: value", behind ONE tab stop. With this
483
524
  * they are buttons that Enter and Space activate; without, images to read.
484
525
  */
485
- onPointClick?: (hit: SeriesChartHit) => void;
526
+ onPointClick?: (hit: SeriesChartHit<TRow>) => void;
486
527
  /** Where the tooltip may go: for a chart inside a scroll wrapper. See
487
528
  * {@link SeriesChartTooltip}. */
488
529
  tooltip?: SeriesChartTooltip;
@@ -595,17 +636,21 @@ export interface SeriesLegendAxes {
595
636
  * series whose axis is not drawn says the unit that axis would have: "Velocity (mm/s)"
596
637
  * — see {@link SeriesChartAxis.unit}. Without them, the labels are as given.
597
638
  */
598
- export declare function seriesLegendEntries(series: readonly SeriesChartSeries[], { axes, budgeted }?: SeriesLegendAxes): LegendEntry[];
639
+ export declare function seriesLegendEntries<TRow extends object>(series: readonly SeriesChartSeries<TRow>[], { axes, budgeted }?: SeriesLegendAxes): LegendEntry[];
599
640
  /**
600
641
  * {@link SeriesChart} without the zoom: the same picture, no drag layer, no reset
601
642
  * button. For a thumbnail, a print view, or a chart the consumer wraps in its own
602
643
  * interaction.
603
644
  */
604
- export declare function StaticSeriesChart(props: SeriesChartProps): import("react").JSX.Element;
645
+ export declare function StaticSeriesChart<TRow extends object = object>(props: SeriesChartProps<TRow>): import("react").JSX.Element;
605
646
  /**
606
647
  * The series chart, zoomable. Drag across the plot to zoom (the drag's shape picks the
607
648
  * axes), double-click or press the reset button to go back; wrap several in
608
649
  * `SharedXZoom` to move their x windows together. Which axes zoom depends on the marks
609
650
  * — see {@link SeriesChartProps.zoomAxes}.
651
+ *
652
+ * Generic in its rows (0.53): `hit.row` and a `dot`'s `point.row` are typed as `rows` is —
653
+ * see {@link SeriesChartProps}. A plain function, so the generic survives: a `memo` or a
654
+ * `forwardRef` around it would read `TRow` as its constraint.
610
655
  */
611
- export declare function SeriesChart(props: SeriesChartProps): import("react").JSX.Element;
656
+ export declare function SeriesChart<TRow extends object = object>(props: SeriesChartProps<TRow>): import("react").JSX.Element;
@@ -822,7 +822,8 @@ function SeriesPlot({
822
822
  ] });
823
823
  }
824
824
  const ZoomablePlot = withChartZoom(SeriesPlot);
825
- function usePlotProps(props) {
825
+ function usePlotProps(typed) {
826
+ const props = typed;
826
827
  const x = props.x ?? {};
827
828
  const { rows } = props;
828
829
  const { type, key } = x;