@eifi1/ui-kit 0.15.4 → 0.16.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 (160) hide show
  1. package/README.md +20 -15
  2. package/dist/chart.d.ts +3 -4
  3. package/dist/components/alert-banner.js +1 -1
  4. package/dist/components/alert-banner.js.map +1 -1
  5. package/dist/components/amount-input.d.ts +13 -4
  6. package/dist/components/amount-input.js +166 -157
  7. package/dist/components/amount-input.js.map +1 -1
  8. package/dist/components/authed-image.d.ts +14 -3
  9. package/dist/components/authed-image.js +32 -23
  10. package/dist/components/authed-image.js.map +1 -1
  11. package/dist/components/button-group.d.ts +3 -4
  12. package/dist/components/calculator.d.ts +3 -4
  13. package/dist/components/checkbox.js +1 -1
  14. package/dist/components/checkbox.js.map +1 -1
  15. package/dist/components/choice-card.js +1 -1
  16. package/dist/components/choice-card.js.map +1 -1
  17. package/dist/components/copy-button.d.ts +3 -4
  18. package/dist/components/error-boundary.js +1 -1
  19. package/dist/components/error-boundary.js.map +1 -1
  20. package/dist/components/facing-pair.d.ts +3 -4
  21. package/dist/components/file-button.d.ts +3 -4
  22. package/dist/components/file-button.js +64 -31
  23. package/dist/components/file-button.js.map +1 -1
  24. package/dist/components/file-dropzone.d.ts +3 -4
  25. package/dist/components/file-dropzone.js +1 -1
  26. package/dist/components/file-dropzone.js.map +1 -1
  27. package/dist/components/form-actions.d.ts +4 -5
  28. package/dist/components/form-actions.js +18 -6
  29. package/dist/components/form-actions.js.map +1 -1
  30. package/dist/components/line-items.d.ts +53 -2
  31. package/dist/components/line-items.js +73 -7
  32. package/dist/components/line-items.js.map +1 -1
  33. package/dist/components/list.d.ts +99 -5
  34. package/dist/components/list.js +103 -38
  35. package/dist/components/list.js.map +1 -1
  36. package/dist/components/loading-state.d.ts +19 -3
  37. package/dist/components/loading-state.js +14 -3
  38. package/dist/components/loading-state.js.map +1 -1
  39. package/dist/components/money-field.d.ts +3 -4
  40. package/dist/components/number-field.d.ts +3 -4
  41. package/dist/components/number-input.d.ts +3 -4
  42. package/dist/components/number-input.js +4 -2
  43. package/dist/components/number-input.js.map +1 -1
  44. package/dist/components/numpad-sheet.d.ts +3 -4
  45. package/dist/components/passkeys-setting.d.ts +30 -10
  46. package/dist/components/passkeys-setting.js +19 -11
  47. package/dist/components/passkeys-setting.js.map +1 -1
  48. package/dist/components/progress-bar.d.ts +12 -3
  49. package/dist/components/progress-bar.js +21 -11
  50. package/dist/components/progress-bar.js.map +1 -1
  51. package/dist/components/series-chart.d.ts +3 -4
  52. package/dist/components/settings-fields.d.ts +3 -4
  53. package/dist/components/signed-amount.d.ts +28 -4
  54. package/dist/components/signed-amount.js +17 -8
  55. package/dist/components/signed-amount.js.map +1 -1
  56. package/dist/components/stat-tile.d.ts +31 -2
  57. package/dist/components/stat-tile.js +37 -6
  58. package/dist/components/stat-tile.js.map +1 -1
  59. package/dist/components/status-dot.d.ts +4 -1
  60. package/dist/components/status-dot.js +20 -1
  61. package/dist/components/status-dot.js.map +1 -1
  62. package/dist/components/swatch-picker.d.ts +3 -1
  63. package/dist/components/swatch-picker.js.map +1 -1
  64. package/dist/components/table.d.ts +18 -13
  65. package/dist/components/table.js +20 -5
  66. package/dist/components/table.js.map +1 -1
  67. package/dist/components/text-link.d.ts +3 -4
  68. package/dist/components/time-input.d.ts +3 -4
  69. package/dist/components/toggle-legend.d.ts +12 -1
  70. package/dist/components/toggle-legend.js +6 -2
  71. package/dist/components/toggle-legend.js.map +1 -1
  72. package/dist/components/ui.d.ts +3 -4
  73. package/dist/components/ui.js +156 -52
  74. package/dist/components/ui.js.map +1 -1
  75. package/dist/feedback/feedback-attachment.d.ts +2 -82
  76. package/dist/feedback/feedback-attachment.js +285 -55
  77. package/dist/feedback/feedback-attachment.js.map +1 -1
  78. package/dist/feedback/feedback-dialog.d.ts +2 -105
  79. package/dist/feedback/feedback-dialog.js +57 -25
  80. package/dist/feedback/feedback-dialog.js.map +1 -1
  81. package/dist/feedback/feedback-inbox.d.ts +1 -1
  82. package/dist/feedback/feedback-thread.d.ts +2 -2
  83. package/dist/feedback-attachment-WFiXJ8We.d.ts +302 -0
  84. package/dist/feedback.d.ts +1 -2
  85. package/dist/hooks/use-file-drop.d.ts +3 -4
  86. package/dist/i18n/defaults.d.ts +3 -4
  87. package/dist/i18n/kit-labels.d.ts +2 -3
  88. package/dist/i18n/locales/de-CH-informal.d.ts +3 -4
  89. package/dist/i18n/locales/de-CH.d.ts +3 -4
  90. package/dist/i18n/locales/de-informal.d.ts +3 -4
  91. package/dist/i18n/locales/de.d.ts +3 -4
  92. package/dist/i18n/locales/de.js +5 -1
  93. package/dist/i18n/locales/de.js.map +1 -1
  94. package/dist/i18n/locales/es.d.ts +3 -4
  95. package/dist/i18n/locales/es.js +5 -1
  96. package/dist/i18n/locales/es.js.map +1 -1
  97. package/dist/i18n/locales/fr.d.ts +3 -4
  98. package/dist/i18n/locales/fr.js +5 -1
  99. package/dist/i18n/locales/fr.js.map +1 -1
  100. package/dist/i18n/locales/hu.d.ts +3 -4
  101. package/dist/i18n/locales/hu.js +5 -1
  102. package/dist/i18n/locales/hu.js.map +1 -1
  103. package/dist/i18n/locales/it.d.ts +3 -4
  104. package/dist/i18n/locales/it.js +5 -1
  105. package/dist/i18n/locales/it.js.map +1 -1
  106. package/dist/i18n/locales/zh.d.ts +3 -4
  107. package/dist/i18n/locales/zh.js +5 -1
  108. package/dist/i18n/locales/zh.js.map +1 -1
  109. package/dist/index.d.ts +10 -11
  110. package/dist/{kit-labels-CnnBd-2N.d.ts → kit-labels-DE--LmCk.d.ts} +154 -14
  111. package/dist/lib/format.d.ts +18 -3
  112. package/dist/lib/format.js +2 -1
  113. package/dist/lib/format.js.map +1 -1
  114. package/dist/rhf/fields.d.ts +3 -4
  115. package/dist/rhf/form.d.ts +3 -4
  116. package/dist/rhf/line-items.js.map +1 -1
  117. package/dist/rhf.d.ts +3 -4
  118. package/dist/shell/app-shell.d.ts +3 -4
  119. package/dist/shell/top-bar-brand.d.ts +3 -4
  120. package/dist/shell.d.ts +3 -4
  121. package/dist/theme/palette-derive.d.ts +3 -0
  122. package/dist/theme/palette-derive.js +7 -0
  123. package/dist/theme/palette-derive.js.map +1 -1
  124. package/dist/wizard/stepper-nav.d.ts +3 -4
  125. package/dist/wizard.d.ts +3 -4
  126. package/package.json +4 -2
  127. package/src/components/alert-banner.tsx +1 -1
  128. package/src/components/amount-input.tsx +47 -16
  129. package/src/components/authed-image.tsx +20 -2
  130. package/src/components/checkbox.tsx +1 -1
  131. package/src/components/choice-card.tsx +1 -1
  132. package/src/components/error-boundary.tsx +1 -1
  133. package/src/components/file-button.tsx +77 -27
  134. package/src/components/file-dropzone.tsx +1 -1
  135. package/src/components/form-actions.tsx +86 -8
  136. package/src/components/line-items.tsx +131 -14
  137. package/src/components/list.tsx +240 -50
  138. package/src/components/loading-state.tsx +35 -4
  139. package/src/components/number-input.tsx +18 -2
  140. package/src/components/passkeys-setting.tsx +45 -18
  141. package/src/components/progress-bar.tsx +46 -21
  142. package/src/components/signed-amount.tsx +47 -8
  143. package/src/components/stat-tile.tsx +76 -6
  144. package/src/components/status-dot.tsx +31 -0
  145. package/src/components/swatch-picker.tsx +3 -1
  146. package/src/components/table.tsx +42 -15
  147. package/src/components/toggle-legend.tsx +21 -4
  148. package/src/components/ui.tsx +280 -70
  149. package/src/feedback/feedback-attachment.tsx +472 -96
  150. package/src/feedback/feedback-dialog.tsx +162 -50
  151. package/src/i18n/locales/de.ts +4 -0
  152. package/src/i18n/locales/es.ts +4 -0
  153. package/src/i18n/locales/fr.ts +4 -0
  154. package/src/i18n/locales/hu.ts +4 -0
  155. package/src/i18n/locales/it.ts +4 -0
  156. package/src/i18n/locales/zh.ts +4 -0
  157. package/src/lib/format.ts +24 -3
  158. package/src/rhf/line-items.tsx +6 -0
  159. package/src/theme/palette-derive.ts +10 -0
  160. package/tokens.css +9 -1
@@ -1,6 +1,7 @@
1
- import { Children, createContext, useContext, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
2
- import type { ComponentPropsWithoutRef, ReactNode } from "react";
1
+ import { Children, createContext, useCallback, useContext, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
2
+ import type { ComponentPropsWithRef, ReactNode, Ref } from "react";
3
3
  import { cn } from "../lib/cn";
4
+ import { assignRef } from "./choice-parts";
4
5
  import { THIN_SCROLLBAR_CLASS, useScrollOverflow } from "./scroll-area";
5
6
 
6
7
  /** `none` (0.10.0): no cell padding at all — keksdose's VAT summary, a table set
@@ -91,6 +92,22 @@ function useSection<E extends HTMLElement>(): [TableSection, ((el: E | null) =>
91
92
  return [fromContext ?? detected ?? "body", fromContext === undefined ? setNode : undefined];
92
93
  }
93
94
 
95
+ /**
96
+ * One callback ref for the caller's `ref` and the part's own (0.16.0). Every part takes
97
+ * a `ref` to its DOM element — React 19 hands it to a function component as a prop —
98
+ * and the parts that hold the node themselves (the table, a row or a head cell reading
99
+ * its section off the DOM) must still get it when the caller passes one too.
100
+ */
101
+ function useMergedRef<E>(own: ((el: E | null) => void) | { current: E | null } | undefined, ref: Ref<E> | undefined) {
102
+ return useCallback(
103
+ (node: E | null) => {
104
+ assignRef(own as Ref<E> | undefined, node);
105
+ assignRef(ref, node);
106
+ },
107
+ [own, ref],
108
+ );
109
+ }
110
+
94
111
  /** A {@link TableRow}'s `valign`, which its cells take unless they set their own. It
95
112
  * cannot be left to CSS inheritance: every cell states its own default alignment,
96
113
  * and a class on the cell beats one on the row. */
@@ -133,7 +150,12 @@ const ALIGN: Record<TableAlign, string> = {
133
150
  */
134
151
  export const NUMERIC_CELL_CLASS = "text-end tabular-nums";
135
152
 
136
- export interface TableProps extends ComponentPropsWithoutRef<"table"> {
153
+ /**
154
+ * Every part's props are `ComponentPropsWithRef` (0.16.0), so `ref` reaches the DOM
155
+ * element: keksdose scrolled a budget row into view through `useId` + `getElementById`
156
+ * because `<TableRow ref>` did not type-check.
157
+ */
158
+ export interface TableProps extends ComponentPropsWithRef<"table"> {
137
159
  /** `compact` for a dense detail view (a ledger, a spec sheet). */
138
160
  density?: TableDensity;
139
161
  /** Tint every other body row. */
@@ -216,6 +238,7 @@ export function Table({
216
238
  stack,
217
239
  className,
218
240
  "aria-label": ariaLabel,
241
+ ref,
219
242
  ...rest
220
243
  }: TableProps) {
221
244
  const captionId = useId();
@@ -223,6 +246,7 @@ export function Table({
223
246
  const wrapper = useRef<HTMLDivElement | null>(null);
224
247
  const overflowing = useScrollOverflow(wrapper);
225
248
  const tableRef = useRef<HTMLTableElement | null>(null);
249
+ const setTableRef = useMergedRef(tableRef, ref);
226
250
 
227
251
  // `stack="phone"`: label every body cell with its column's header text, and keep the
228
252
  // table's roles explicit — `display: block` on table parts drops their table
@@ -296,7 +320,7 @@ export function Table({
296
320
  >
297
321
  <table
298
322
  {...rest}
299
- ref={tableRef}
323
+ ref={setTableRef}
300
324
  aria-label={ariaLabel}
301
325
  className={cn(
302
326
  "w-full caption-bottom border-collapse text-sm text-[var(--text-primary)]",
@@ -312,7 +336,7 @@ export function Table({
312
336
  );
313
337
  }
314
338
 
315
- export interface TableHeadProps extends ComponentPropsWithoutRef<"thead"> {
339
+ export interface TableHeadProps extends ComponentPropsWithRef<"thead"> {
316
340
  /** The rule under the head. Default true; `false` for a quiet header over a small
317
341
  * table (keksdose's VAT summary wrote `className="border-b-0"` to lose it). */
318
342
  bordered?: boolean;
@@ -326,7 +350,7 @@ export function TableHead({ bordered = true, className, ...rest }: TableHeadProp
326
350
  );
327
351
  }
328
352
 
329
- export interface TableBodyProps extends ComponentPropsWithoutRef<"tbody"> {
353
+ export interface TableBodyProps extends ComponentPropsWithRef<"tbody"> {
330
354
  /**
331
355
  * Shown as ONE full-width row (a {@link TableEmpty}) when the body has no rows —
332
356
  * `children` that render nothing: an empty `.map`, a `false`, `null`. kastlan hand-
@@ -354,7 +378,7 @@ export function TableBody({ className, empty, children, ...rest }: TableBodyProp
354
378
  );
355
379
  }
356
380
 
357
- export interface TableEmptyProps extends Omit<ComponentPropsWithoutRef<"tr">, "children"> {
381
+ export interface TableEmptyProps extends Omit<ComponentPropsWithRef<"tr">, "children"> {
358
382
  children: ReactNode;
359
383
  /** Columns to span. Default: MEASURED — the widest row of the table it renders in,
360
384
  * counted after mount, so the row stays full width when a column is added. */
@@ -407,7 +431,7 @@ export function TableEmpty({ children, colSpan, cellClassName, className, ...res
407
431
  );
408
432
  }
409
433
 
410
- export type TableFootProps = ComponentPropsWithoutRef<"tfoot">;
434
+ export type TableFootProps = ComponentPropsWithRef<"tfoot">;
411
435
 
412
436
  /** The totals row. Not in the brief, but every ledger view has one and a `<tfoot>`
413
437
  * is what tells a reader it is a total rather than one more row. */
@@ -429,7 +453,7 @@ const ROW_VARIANT: Record<TableRowVariant, string | false> = {
429
453
  };
430
454
 
431
455
  /** The deprecated HTML `valign` attribute is replaced by a class-backed one. */
432
- export interface TableRowProps extends ComponentPropsWithoutRef<"tr"> {
456
+ export interface TableRowProps extends ComponentPropsWithRef<"tr"> {
433
457
  /** Vertical alignment for every cell of the row that does not set its own. See
434
458
  * {@link TableVAlign}. Left out, each cell keeps its default. */
435
459
  valign?: TableVAlign;
@@ -440,9 +464,10 @@ export interface TableRowProps extends ComponentPropsWithoutRef<"tr"> {
440
464
  bordered?: boolean;
441
465
  }
442
466
 
443
- export function TableRow({ valign, variant = "row", bordered, className, ...rest }: TableRowProps) {
467
+ export function TableRow({ valign, variant = "row", bordered, className, ref: refProp, ...rest }: TableRowProps) {
444
468
  const { zebra, hover, rowDividers } = useContext(TableContext);
445
- const [section, ref] = useSection<HTMLTableRowElement>();
469
+ const [section, sectionRef] = useSection<HTMLTableRowElement>();
470
+ const ref = useMergedRef(sectionRef, refProp);
446
471
  const body = section === "body";
447
472
  const record = body && variant === "row";
448
473
  const row = (
@@ -475,7 +500,7 @@ interface CellAlignProps {
475
500
  }
476
501
 
477
502
  /** The deprecated HTML `align` and `valign` attributes are replaced by class-backed ones. */
478
- export interface TableHeaderCellProps extends Omit<ComponentPropsWithoutRef<"th">, "align" | "valign">, CellAlignProps {
503
+ export interface TableHeaderCellProps extends Omit<ComponentPropsWithRef<"th">, "align" | "valign">, CellAlignProps {
479
504
  /**
480
505
  * Type size. Left out: `xs` in the head, the table's own size in the body — as
481
506
  * before. keksdose's VAT summary heads its columns at the body size and normal weight
@@ -500,10 +525,12 @@ export function TableHeaderCell({
500
525
  weight = "medium",
501
526
  scope,
502
527
  className,
528
+ ref: refProp,
503
529
  ...rest
504
530
  }: TableHeaderCellProps) {
505
531
  const { density } = useContext(TableContext);
506
- const [section, ref] = useSection<HTMLTableCellElement>();
532
+ const [section, sectionRef] = useSection<HTMLTableCellElement>();
533
+ const ref = useMergedRef(sectionRef, refProp);
507
534
  const rowVAlign = useContext(RowVAlignContext);
508
535
  const head = section === "head";
509
536
  const textSize = size ?? (head ? "xs" : undefined);
@@ -526,7 +553,7 @@ export function TableHeaderCell({
526
553
  );
527
554
  }
528
555
 
529
- export interface TableCellProps extends Omit<ComponentPropsWithoutRef<"td">, "align" | "valign">, CellAlignProps {}
556
+ export interface TableCellProps extends Omit<ComponentPropsWithRef<"td">, "align" | "valign">, CellAlignProps {}
530
557
 
531
558
  export function TableCell({ numeric = false, align, valign, className, ...rest }: TableCellProps) {
532
559
  const { density } = useContext(TableContext);
@@ -545,7 +572,7 @@ export function TableCell({ numeric = false, align, valign, className, ...rest }
545
572
  );
546
573
  }
547
574
 
548
- export type TableCaptionProps = ComponentPropsWithoutRef<"caption">;
575
+ export type TableCaptionProps = ComponentPropsWithRef<"caption">;
549
576
 
550
577
  /**
551
578
  * The table's title. Beneath the table by default (`caption-bottom`, the shadcn
@@ -194,6 +194,17 @@ export interface StaticLegendProps {
194
194
  orientation?: "horizontal" | "vertical";
195
195
  /** The list's accessible name. Default: the `seriesChart.legend` label. */
196
196
  "aria-label"?: string;
197
+ /**
198
+ * `ul` (default): a list — "list, 4 items", walked with the list keys. Its entries are
199
+ * `listitem`s, so a host test that counts `getAllByRole("listitem")` on a page with
200
+ * the legend on it counts the legend too: scope it (`within(...)`) or use `div`.
201
+ *
202
+ * `div`: a named `role="group"` of plain entries, for a legend set inside something
203
+ * that is already a list or a table row, where a list in a list reads as nesting that
204
+ * is not there, or where the entries are too few for "list, 2 items" to help. The
205
+ * entries are read in order either way; only the list framing goes.
206
+ */
207
+ as?: "ul" | "div";
197
208
  className?: string;
198
209
  /** Per-instance strings over `<UiKitProvider labels={{ seriesChart }}>`. */
199
210
  labels?: Partial<SeriesChartLabels>;
@@ -218,13 +229,19 @@ export function StaticLegend({
218
229
  entries,
219
230
  orientation = "horizontal",
220
231
  "aria-label": ariaLabel,
232
+ as = "ul",
221
233
  className,
222
234
  labels: labelsProp,
223
235
  }: StaticLegendProps) {
224
236
  const labels = useKitLabels("seriesChart", DEFAULT_SERIES_CHART_LABELS, labelsProp);
225
237
  if (entries.length === 0) return null;
238
+ const List = as;
239
+ const Item = as === "ul" ? "li" : "div";
226
240
  return (
227
- <ul
241
+ <List
242
+ // A `div` takes `group`: a name on a role-less div is one ARIA forbids and
243
+ // screen readers drop, and the name is what says these marks are a key.
244
+ role={as === "div" ? "group" : undefined}
228
245
  aria-label={ariaLabel ?? labels.legend}
229
246
  className={cn(
230
247
  "m-0 flex list-none gap-x-3 gap-y-1 p-0",
@@ -235,7 +252,7 @@ export function StaticLegend({
235
252
  )}
236
253
  >
237
254
  {entries.map((entry) => (
238
- <li
255
+ <Item
239
256
  key={entry.key}
240
257
  className={cn(
241
258
  "flex items-center gap-1.5 text-[11px] text-[var(--text-secondary)]",
@@ -244,9 +261,9 @@ export function StaticLegend({
244
261
  >
245
262
  <LegendMark entry={entry} off={false} />
246
263
  {entry.label}
247
- </li>
264
+ </Item>
248
265
  ))}
249
- </ul>
266
+ </List>
250
267
  );
251
268
  }
252
269