@eifi1/ui-kit 0.14.2 → 0.15.1

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 (118) hide show
  1. package/dist/chart.d.ts +2 -1
  2. package/dist/components/alert-banner.js +5 -2
  3. package/dist/components/alert-banner.js.map +1 -1
  4. package/dist/components/amount-input.d.ts +1 -1
  5. package/dist/components/autocomplete.js +9 -2
  6. package/dist/components/autocomplete.js.map +1 -1
  7. package/dist/components/bulk-action-bar.js +6 -3
  8. package/dist/components/bulk-action-bar.js.map +1 -1
  9. package/dist/components/button-group.d.ts +1 -1
  10. package/dist/components/calculator.d.ts +1 -1
  11. package/dist/components/calendar-heatmap.js +5 -5
  12. package/dist/components/calendar-heatmap.js.map +1 -1
  13. package/dist/components/copy-button.d.ts +1 -1
  14. package/dist/components/data-table-cells.d.ts +1 -1
  15. package/dist/components/data-table-filter-popover.d.ts +1 -1
  16. package/dist/components/data-table-filter-popover.js +3 -3
  17. package/dist/components/data-table-filter-popover.js.map +1 -1
  18. package/dist/components/data-table-filters.d.ts +1 -1
  19. package/dist/components/data-table.d.ts +1 -1
  20. package/dist/components/data-table.js +12 -4
  21. package/dist/components/data-table.js.map +1 -1
  22. package/dist/components/facing-pair.d.ts +1 -0
  23. package/dist/components/field.js +4 -1
  24. package/dist/components/field.js.map +1 -1
  25. package/dist/components/file-button.d.ts +1 -1
  26. package/dist/components/file-dropzone.d.ts +1 -1
  27. package/dist/components/form-actions.d.ts +1 -1
  28. package/dist/components/image-grid.d.ts +8 -1
  29. package/dist/components/image-grid.js +16 -3
  30. package/dist/components/image-grid.js.map +1 -1
  31. package/dist/components/measured-grid.js +2 -2
  32. package/dist/components/measured-grid.js.map +1 -1
  33. package/dist/components/money-field.d.ts +1 -1
  34. package/dist/components/multi-select.js +3 -0
  35. package/dist/components/multi-select.js.map +1 -1
  36. package/dist/components/number-field.d.ts +1 -1
  37. package/dist/components/number-input.d.ts +5 -2
  38. package/dist/components/number-input.js +11 -3
  39. package/dist/components/number-input.js.map +1 -1
  40. package/dist/components/numpad-sheet.d.ts +1 -1
  41. package/dist/components/series-chart-budget.d.ts +60 -0
  42. package/dist/components/series-chart-budget.js +56 -0
  43. package/dist/components/series-chart-budget.js.map +1 -0
  44. package/dist/components/series-chart.d.ts +54 -2
  45. package/dist/components/series-chart.js +104 -20
  46. package/dist/components/series-chart.js.map +1 -1
  47. package/dist/components/settings-fields.d.ts +1 -1
  48. package/dist/components/slider.js +6 -2
  49. package/dist/components/slider.js.map +1 -1
  50. package/dist/components/stat-tile.js +3 -3
  51. package/dist/components/stat-tile.js.map +1 -1
  52. package/dist/components/text-link.d.ts +1 -1
  53. package/dist/components/time-input.d.ts +1 -1
  54. package/dist/components/treemap.d.ts +3 -2
  55. package/dist/components/treemap.js +14 -3
  56. package/dist/components/treemap.js.map +1 -1
  57. package/dist/components/ui.d.ts +1 -1
  58. package/dist/components/ui.js +44 -10
  59. package/dist/components/ui.js.map +1 -1
  60. package/dist/components/use-table-state.d.ts +1 -1
  61. package/dist/{data-table-Drun8Fk9.d.ts → data-table-CfVXtCeG.d.ts} +4 -3
  62. package/dist/data-table.d.ts +1 -1
  63. package/dist/feedback/feedback-thread.js +31 -12
  64. package/dist/feedback/feedback-thread.js.map +1 -1
  65. package/dist/hooks/use-file-drop.d.ts +1 -1
  66. package/dist/i18n/defaults.d.ts +1 -1
  67. package/dist/i18n/kit-labels.d.ts +1 -1
  68. package/dist/i18n/locales/de-CH-informal.d.ts +1 -1
  69. package/dist/i18n/locales/de-CH.d.ts +1 -1
  70. package/dist/i18n/locales/de-informal.d.ts +1 -1
  71. package/dist/i18n/locales/de.d.ts +1 -1
  72. package/dist/i18n/locales/es.d.ts +1 -1
  73. package/dist/i18n/locales/fr.d.ts +1 -1
  74. package/dist/i18n/locales/hu.d.ts +1 -1
  75. package/dist/i18n/locales/it.d.ts +1 -1
  76. package/dist/i18n/locales/zh.d.ts +1 -1
  77. package/dist/index.d.ts +5 -4
  78. package/dist/{kit-labels-Mz8zZHIF.d.ts → kit-labels-BHfRBbHs.d.ts} +5 -1
  79. package/dist/lib/strip-fade.d.ts +31 -0
  80. package/dist/lib/strip-fade.js +54 -0
  81. package/dist/lib/strip-fade.js.map +1 -0
  82. package/dist/rhf/fields.d.ts +1 -1
  83. package/dist/rhf/form.d.ts +1 -1
  84. package/dist/rhf/form.js +1 -1
  85. package/dist/rhf/form.js.map +1 -1
  86. package/dist/rhf.d.ts +1 -1
  87. package/dist/shell/app-shell.d.ts +11 -2
  88. package/dist/shell/app-shell.js +20 -4
  89. package/dist/shell/app-shell.js.map +1 -1
  90. package/dist/shell/top-bar-brand.d.ts +1 -1
  91. package/dist/shell.d.ts +1 -1
  92. package/dist/wizard/stepper-nav.d.ts +1 -1
  93. package/dist/wizard/stepper-nav.js +14 -2
  94. package/dist/wizard/stepper-nav.js.map +1 -1
  95. package/dist/wizard.d.ts +1 -1
  96. package/package.json +1 -1
  97. package/src/components/alert-banner.tsx +10 -2
  98. package/src/components/autocomplete.tsx +10 -1
  99. package/src/components/bulk-action-bar.tsx +12 -3
  100. package/src/components/calendar-heatmap.tsx +10 -5
  101. package/src/components/data-table-filter-popover.tsx +6 -3
  102. package/src/components/data-table.tsx +21 -7
  103. package/src/components/field.tsx +4 -1
  104. package/src/components/image-grid.tsx +30 -2
  105. package/src/components/measured-grid.tsx +3 -2
  106. package/src/components/multi-select.tsx +3 -0
  107. package/src/components/number-input.tsx +23 -4
  108. package/src/components/series-chart-budget.ts +121 -0
  109. package/src/components/series-chart.tsx +201 -15
  110. package/src/components/slider.tsx +6 -2
  111. package/src/components/stat-tile.tsx +8 -3
  112. package/src/components/treemap.tsx +30 -5
  113. package/src/components/ui.tsx +91 -11
  114. package/src/feedback/feedback-thread.tsx +36 -13
  115. package/src/lib/strip-fade.ts +82 -0
  116. package/src/rhf/form.tsx +3 -1
  117. package/src/shell/app-shell.tsx +34 -7
  118. package/src/wizard/stepper-nav.tsx +23 -2
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useMemo, useRef, useState } from "react";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
4
4
  import {
5
5
  Area,
6
6
  Bar,
@@ -25,6 +25,7 @@ import {
25
25
  import { STEP_DASH, strokeDash } from "./toggle-legend.js";
26
26
  import { DEFAULT_SERIES_CHART_LABELS } from "./series-chart-labels.js";
27
27
  import { categoryTicks, integerTicks, niceTicks, timeTicksWithUnit } from "./series-chart-ticks.js";
28
+ import { autoAxisBudget, axisUnit, budgetedAxes } from "./series-chart-budget.js";
28
29
  import { paletteFor } from "../theme/chart-palette.js";
29
30
  import { useKitLabels, useKitLocale } from "../i18n/kit-labels.js";
30
31
  import { cn } from "../lib/cn.js";
@@ -104,14 +105,28 @@ function anchoredBand(extent) {
104
105
  function visibleSeries(series, hidden) {
105
106
  return series.map((entry, index) => ({ ...entry, color: entry.color ?? paletteFor(index) })).filter((entry) => !hidden.has(entry.key));
106
107
  }
107
- function seriesLegendEntries(series) {
108
+ function withUnit(label, unit) {
109
+ if (!unit) return label;
110
+ if (typeof label === "string" || typeof label === "number") return `${label} (${unit})`;
111
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
112
+ label,
113
+ " (",
114
+ unit,
115
+ ")"
116
+ ] });
117
+ }
118
+ function seriesLegendEntries(series, { axes, budgeted } = {}) {
119
+ const undrawn = /* @__PURE__ */ new Map();
120
+ for (const axis of axes ?? []) {
121
+ if (axis.hide || budgeted?.includes(axis.id)) undrawn.set(axis.id, axisUnit(axis));
122
+ }
108
123
  return series.map((entry, index) => {
109
124
  const own = entry.dash ?? (entry.dashed ? 1 : 0);
110
125
  const dash = entry.step ? STEP_DASH : own;
111
126
  const line = (entry.type ?? "line") === "line";
112
127
  return {
113
128
  key: entry.key,
114
- label: entry.label,
129
+ label: withUnit(entry.label, undrawn.get(entry.axis ?? DEFAULT_Y_AXIS)),
115
130
  color: entry.color ?? paletteFor(index),
116
131
  ...line && dash !== 0 ? { marker: "stroke", dash } : {}
117
132
  };
@@ -205,6 +220,40 @@ function focusedBarShape(index) {
205
220
  return /* @__PURE__ */ jsx(Rectangle, { ...props, ...focused ? { stroke: "var(--text-primary)", strokeWidth: 2 } : {} });
206
221
  };
207
222
  }
223
+ const MARKER_LABEL_SIZE = 11;
224
+ function MarkerLabel({
225
+ viewBox,
226
+ value
227
+ }) {
228
+ const plot = usePlotArea();
229
+ const ref = useRef(null);
230
+ const [measured, setMeasured] = useState();
231
+ const text = value == null ? "" : String(value);
232
+ useLayoutEffect(() => {
233
+ const el = ref.current;
234
+ if (!el || typeof el.getComputedTextLength !== "function") return;
235
+ const w = el.getComputedTextLength();
236
+ if (w > 0 && w !== measured) setMeasured(w);
237
+ }, [text, measured]);
238
+ if (!viewBox || viewBox.x == null || viewBox.y == null || text === "") return null;
239
+ const cx = viewBox.x + (viewBox.width ?? 0) / 2;
240
+ const half = (measured ?? text.length * MARKER_LABEL_SIZE * 0.6) / 2;
241
+ const x = plot ? Math.max(plot.x + half, Math.min(cx, plot.x + plot.width - half)) : cx;
242
+ return /* @__PURE__ */ jsx(
243
+ "text",
244
+ {
245
+ ref,
246
+ x,
247
+ y: viewBox.y - 5,
248
+ textAnchor: "middle",
249
+ fontSize: MARKER_LABEL_SIZE,
250
+ fontWeight: 600,
251
+ fill: "var(--text-primary)",
252
+ className: "recharts-label",
253
+ children: text
254
+ }
255
+ );
256
+ }
208
257
  function PointKeys({
209
258
  stops,
210
259
  current,
@@ -289,13 +338,44 @@ function SeriesPlot({
289
338
  labels: labelsProp,
290
339
  locale: localeProp,
291
340
  className,
292
- minBarLength
341
+ minBarLength,
342
+ maxVisibleAxes,
343
+ axisBudget = "auto",
344
+ onAxisBudget
293
345
  }) {
294
346
  const labels = useKitLabels("seriesChart", DEFAULT_SERIES_CHART_LABELS, labelsProp);
295
347
  const locale = useKitLocale(localeProp);
296
348
  const number = useDefaultFormat(localeProp);
297
349
  const [keyStop, setKeyStop] = useState(0);
298
350
  const [keyFocus, setKeyFocus] = useState(void 0);
351
+ const [box, setBox] = useState(null);
352
+ const [width, setWidth] = useState(void 0);
353
+ useLayoutEffect(() => {
354
+ if (!box || axisBudget === "off" || typeof ResizeObserver === "undefined") return;
355
+ const measure = () => setWidth(box.getBoundingClientRect().width || void 0);
356
+ measure();
357
+ const observer = new ResizeObserver(measure);
358
+ observer.observe(box);
359
+ return () => observer.disconnect();
360
+ }, [box, axisBudget]);
361
+ const capped = budgetedAxes(axes, maxVisibleAxes);
362
+ const afterCap = capped.length ? axes.map((axis) => capped.includes(axis.id) ? { ...axis, hide: true } : axis) : axes;
363
+ const auto = axisBudget === "off" ? [] : budgetedAxes(
364
+ afterCap,
365
+ autoAxisBudget(
366
+ afterCap,
367
+ width,
368
+ (axis) => axisBandWidth(axis.width, Boolean(axis.title))
369
+ )
370
+ );
371
+ const budgeted = [...capped, ...auto];
372
+ const budgetKey = budgeted.join("\n");
373
+ const reported = useRef("");
374
+ useEffect(() => {
375
+ if (budgetKey === reported.current) return;
376
+ reported.current = budgetKey;
377
+ onAxisBudget?.(budgetKey ? budgetKey.split("\n") : []);
378
+ }, [budgetKey, onAxisBudget]);
299
379
  const heightClass = typeof height === "string" ? height : void 0;
300
380
  const heightStyle = typeof height === "number" ? { height } : void 0;
301
381
  if (!model.source.length || !series.length) {
@@ -312,14 +392,21 @@ function SeriesPlot({
312
392
  const xKey = model.plotKey;
313
393
  const plotted = model.rows;
314
394
  const rows = model.source;
395
+ const drawnAxes = budgeted.length ? axes.map((axis) => budgeted.includes(axis.id) ? { ...axis, hide: true } : axis) : axes;
396
+ const lostUnit = new Map(
397
+ axes.filter((axis) => budgeted.includes(axis.id)).map((axis) => [axis.id, axisUnit(axis)])
398
+ );
315
399
  const config = Object.fromEntries(
316
400
  series.map((entry, index) => [
317
401
  entry.key,
318
- { label: entry.label, color: entry.color ?? paletteFor(index) }
402
+ {
403
+ label: withUnit(entry.label, lostUnit.get(entry.axis ?? DEFAULT_Y_AXIS)),
404
+ color: entry.color ?? paletteFor(index)
405
+ }
319
406
  ])
320
407
  );
321
- const visible = axes.filter((axis) => !axis.hide);
322
- const gridAxis = (visible[0] ?? axes[0])?.id ?? DEFAULT_Y_AXIS;
408
+ const visible = drawnAxes.filter((axis) => !axis.hide);
409
+ const gridAxis = (visible[0] ?? drawnAxes[0])?.id ?? DEFAULT_Y_AXIS;
323
410
  const onLeft = visible.some((axis) => (axis.orientation ?? "left") === "left");
324
411
  const onRight = visible.some((axis) => axis.orientation === "right");
325
412
  const margin = {
@@ -477,6 +564,8 @@ function SeriesPlot({
477
564
  return /* @__PURE__ */ jsx(
478
565
  ChartContainer,
479
566
  {
567
+ ref: setBox,
568
+ "data-axis-budget": budgeted.length ? budgetKey.replace(/\n/g, " ") : void 0,
480
569
  config,
481
570
  className: cn("w-full", heightClass, className, onPointClick && "cursor-pointer"),
482
571
  style: heightStyle,
@@ -505,6 +594,7 @@ function SeriesPlot({
505
594
  tickLine: false,
506
595
  axisLine: false,
507
596
  minTickGap: 32,
597
+ interval: "equidistantPreserveEnd",
508
598
  tick: x.ticks === false ? false : void 0,
509
599
  ...tickAngle ? { angle: tickAngle, textAnchor: tickAngle < 0 ? "end" : "start" } : {},
510
600
  height: x.ticks === false && !x.title ? 4 : tickBand,
@@ -520,7 +610,7 @@ function SeriesPlot({
520
610
  )
521
611
  }
522
612
  ),
523
- axes.map((axis) => {
613
+ drawnAxes.map((axis) => {
524
614
  const domain = fittedY(axis);
525
615
  const zoomed = anchored(axis) ? zoom?.xDomain !== void 0 : zoom?.yDomains[axis.id] !== void 0;
526
616
  return /* @__PURE__ */ jsx(
@@ -532,7 +622,7 @@ function SeriesPlot({
532
622
  ticks: resolveTicks(axis.tickValues, domain, finite) ?? (wholeOnly(axis) ? integerTicks(domain) ?? niceTicks(domain) : niceTicks(domain)),
533
623
  allowDataOverflow: zoomed,
534
624
  orientation: axis.orientation ?? "left",
535
- width: axisBandWidth(axis.width, Boolean(axis.title) && !axis.hide),
625
+ width: axis.hide ? 0 : axisBandWidth(axis.width, Boolean(axis.title)),
536
626
  tickLine: false,
537
627
  axisLine: false,
538
628
  tickFormatter: axis.format ?? number,
@@ -575,7 +665,7 @@ function SeriesPlot({
575
665
  const own = entry.dash ?? (entry.dashed ? 1 : 0);
576
666
  const dash = entry.step ? strokeDash(STEP_DASH) : typeof own === "string" ? own : strokeDash(own);
577
667
  const curve = entry.step ? "stepAfter" : entry.curve ?? "monotone";
578
- const width = entry.strokeWidth ?? (entry.step ? STEP_WIDTH : LINE_WIDTH);
668
+ const width2 = entry.strokeWidth ?? (entry.step ? STEP_WIDTH : LINE_WIDTH);
579
669
  if (type === "bar") {
580
670
  const stub = entry.minBarLength ?? minBarLength;
581
671
  return /* @__PURE__ */ jsx(
@@ -608,7 +698,7 @@ function SeriesPlot({
608
698
  dataKey: entry.key,
609
699
  stackId: entry.stack,
610
700
  stroke: color,
611
- strokeWidth: width,
701
+ strokeWidth: width2,
612
702
  strokeDasharray: dash,
613
703
  fill: color,
614
704
  fillOpacity: entry.fillOpacity ?? (entry.stack !== void 0 ? 0.55 : 0.2),
@@ -627,7 +717,7 @@ function SeriesPlot({
627
717
  type: curve,
628
718
  dataKey: entry.key,
629
719
  stroke: color,
630
- strokeWidth: width,
720
+ strokeWidth: width2,
631
721
  strokeDasharray: dash,
632
722
  dot: dotFor(entry),
633
723
  ...entry.activeDot !== void 0 ? { activeDot: entry.activeDot } : {},
@@ -690,13 +780,7 @@ function SeriesPlot({
690
780
  stroke: "var(--bg-surface)",
691
781
  strokeWidth: 1.5,
692
782
  ifOverflow: "discard",
693
- label: marker.label ? {
694
- value: marker.label,
695
- position: "top",
696
- fontSize: 11,
697
- fontWeight: 600,
698
- fill: "var(--text-primary)"
699
- } : void 0
783
+ label: marker.label ? { value: marker.label, position: "top", content: /* @__PURE__ */ jsx(MarkerLabel, {}) } : void 0
700
784
  },
701
785
  marker.key ?? `marker-${index}`
702
786
  );