@eifi1/ui-kit 0.15.5 → 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 (140) hide show
  1. package/README.md +17 -12
  2. package/dist/chart.d.ts +3 -3
  3. package/dist/components/amount-input.d.ts +10 -3
  4. package/dist/components/amount-input.js +165 -156
  5. package/dist/components/amount-input.js.map +1 -1
  6. package/dist/components/authed-image.d.ts +14 -3
  7. package/dist/components/authed-image.js +32 -23
  8. package/dist/components/authed-image.js.map +1 -1
  9. package/dist/components/button-group.d.ts +3 -3
  10. package/dist/components/calculator.d.ts +3 -3
  11. package/dist/components/copy-button.d.ts +3 -3
  12. package/dist/components/facing-pair.d.ts +3 -3
  13. package/dist/components/file-button.d.ts +3 -3
  14. package/dist/components/file-button.js +64 -31
  15. package/dist/components/file-button.js.map +1 -1
  16. package/dist/components/file-dropzone.d.ts +3 -3
  17. package/dist/components/form-actions.d.ts +4 -4
  18. package/dist/components/form-actions.js +18 -6
  19. package/dist/components/form-actions.js.map +1 -1
  20. package/dist/components/line-items.d.ts +53 -2
  21. package/dist/components/line-items.js +73 -7
  22. package/dist/components/line-items.js.map +1 -1
  23. package/dist/components/list.d.ts +99 -5
  24. package/dist/components/list.js +103 -38
  25. package/dist/components/list.js.map +1 -1
  26. package/dist/components/loading-state.d.ts +19 -3
  27. package/dist/components/loading-state.js +14 -3
  28. package/dist/components/loading-state.js.map +1 -1
  29. package/dist/components/money-field.d.ts +3 -3
  30. package/dist/components/number-field.d.ts +3 -3
  31. package/dist/components/number-input.d.ts +3 -3
  32. package/dist/components/number-input.js +4 -2
  33. package/dist/components/number-input.js.map +1 -1
  34. package/dist/components/numpad-sheet.d.ts +3 -3
  35. package/dist/components/passkeys-setting.d.ts +30 -10
  36. package/dist/components/passkeys-setting.js +19 -11
  37. package/dist/components/passkeys-setting.js.map +1 -1
  38. package/dist/components/progress-bar.d.ts +12 -3
  39. package/dist/components/progress-bar.js +21 -11
  40. package/dist/components/progress-bar.js.map +1 -1
  41. package/dist/components/series-chart.d.ts +3 -3
  42. package/dist/components/settings-fields.d.ts +3 -3
  43. package/dist/components/signed-amount.d.ts +28 -4
  44. package/dist/components/signed-amount.js +17 -8
  45. package/dist/components/signed-amount.js.map +1 -1
  46. package/dist/components/stat-tile.d.ts +31 -2
  47. package/dist/components/stat-tile.js +37 -6
  48. package/dist/components/stat-tile.js.map +1 -1
  49. package/dist/components/status-dot.d.ts +4 -1
  50. package/dist/components/status-dot.js +20 -1
  51. package/dist/components/status-dot.js.map +1 -1
  52. package/dist/components/swatch-picker.d.ts +3 -1
  53. package/dist/components/swatch-picker.js.map +1 -1
  54. package/dist/components/table.d.ts +18 -13
  55. package/dist/components/table.js +20 -5
  56. package/dist/components/table.js.map +1 -1
  57. package/dist/components/text-link.d.ts +3 -3
  58. package/dist/components/time-input.d.ts +3 -3
  59. package/dist/components/toggle-legend.d.ts +12 -1
  60. package/dist/components/toggle-legend.js +6 -2
  61. package/dist/components/toggle-legend.js.map +1 -1
  62. package/dist/components/ui.d.ts +3 -3
  63. package/dist/components/ui.js +149 -45
  64. package/dist/components/ui.js.map +1 -1
  65. package/dist/feedback/feedback-attachment.d.ts +1 -1
  66. package/dist/feedback/feedback-attachment.js +24 -11
  67. package/dist/feedback/feedback-attachment.js.map +1 -1
  68. package/dist/feedback/feedback-dialog.d.ts +1 -1
  69. package/dist/feedback/feedback-dialog.js +6 -5
  70. package/dist/feedback/feedback-dialog.js.map +1 -1
  71. package/dist/feedback/feedback-inbox.d.ts +1 -1
  72. package/dist/feedback/feedback-thread.d.ts +1 -1
  73. package/dist/{feedback-attachment-BYAHJMOr.d.ts → feedback-attachment-WFiXJ8We.d.ts} +21 -8
  74. package/dist/feedback.d.ts +1 -1
  75. package/dist/hooks/use-file-drop.d.ts +3 -3
  76. package/dist/i18n/defaults.d.ts +3 -3
  77. package/dist/i18n/kit-labels.d.ts +2 -2
  78. package/dist/i18n/locales/de-CH-informal.d.ts +3 -3
  79. package/dist/i18n/locales/de-CH.d.ts +3 -3
  80. package/dist/i18n/locales/de-informal.d.ts +3 -3
  81. package/dist/i18n/locales/de.d.ts +3 -3
  82. package/dist/i18n/locales/de.js +1 -1
  83. package/dist/i18n/locales/de.js.map +1 -1
  84. package/dist/i18n/locales/es.d.ts +3 -3
  85. package/dist/i18n/locales/es.js +1 -1
  86. package/dist/i18n/locales/es.js.map +1 -1
  87. package/dist/i18n/locales/fr.d.ts +3 -3
  88. package/dist/i18n/locales/fr.js +1 -1
  89. package/dist/i18n/locales/fr.js.map +1 -1
  90. package/dist/i18n/locales/hu.d.ts +3 -3
  91. package/dist/i18n/locales/hu.js +1 -1
  92. package/dist/i18n/locales/hu.js.map +1 -1
  93. package/dist/i18n/locales/it.d.ts +3 -3
  94. package/dist/i18n/locales/it.js +1 -1
  95. package/dist/i18n/locales/it.js.map +1 -1
  96. package/dist/i18n/locales/zh.d.ts +3 -3
  97. package/dist/i18n/locales/zh.js +1 -1
  98. package/dist/i18n/locales/zh.js.map +1 -1
  99. package/dist/index.d.ts +10 -10
  100. package/dist/{kit-labels-BD2F7sOz.d.ts → kit-labels-DE--LmCk.d.ts} +153 -12
  101. package/dist/lib/format.d.ts +18 -3
  102. package/dist/lib/format.js +2 -1
  103. package/dist/lib/format.js.map +1 -1
  104. package/dist/rhf/fields.d.ts +3 -3
  105. package/dist/rhf/form.d.ts +3 -3
  106. package/dist/rhf/line-items.js.map +1 -1
  107. package/dist/rhf.d.ts +3 -3
  108. package/dist/shell/app-shell.d.ts +3 -3
  109. package/dist/shell/top-bar-brand.d.ts +3 -3
  110. package/dist/shell.d.ts +3 -3
  111. package/dist/wizard/stepper-nav.d.ts +3 -3
  112. package/dist/wizard.d.ts +3 -3
  113. package/package.json +1 -1
  114. package/src/components/amount-input.tsx +39 -15
  115. package/src/components/authed-image.tsx +20 -2
  116. package/src/components/file-button.tsx +77 -27
  117. package/src/components/form-actions.tsx +86 -8
  118. package/src/components/line-items.tsx +131 -14
  119. package/src/components/list.tsx +240 -50
  120. package/src/components/loading-state.tsx +35 -4
  121. package/src/components/number-input.tsx +18 -2
  122. package/src/components/passkeys-setting.tsx +45 -18
  123. package/src/components/progress-bar.tsx +46 -21
  124. package/src/components/signed-amount.tsx +47 -8
  125. package/src/components/stat-tile.tsx +76 -6
  126. package/src/components/status-dot.tsx +31 -0
  127. package/src/components/swatch-picker.tsx +3 -1
  128. package/src/components/table.tsx +42 -15
  129. package/src/components/toggle-legend.tsx +21 -4
  130. package/src/components/ui.tsx +273 -63
  131. package/src/feedback/feedback-attachment.tsx +45 -14
  132. package/src/feedback/feedback-dialog.tsx +31 -16
  133. package/src/i18n/locales/de.ts +1 -1
  134. package/src/i18n/locales/es.ts +1 -1
  135. package/src/i18n/locales/fr.ts +1 -1
  136. package/src/i18n/locales/hu.ts +1 -1
  137. package/src/i18n/locales/it.ts +1 -1
  138. package/src/i18n/locales/zh.ts +1 -1
  139. package/src/lib/format.ts +24 -3
  140. package/src/rhf/line-items.tsx +6 -0
@@ -6,6 +6,7 @@ import { useMediaQuery } from "../hooks/use-media-query";
6
6
  import { useKitLabels } from "../i18n/kit-labels";
7
7
  import {
8
8
  DEFAULT_ATTACHMENT_ACCEPT,
9
+ DEFAULT_FEEDBACK_ATTACHMENT_LABELS,
9
10
  DEFAULT_MAX_ATTACHMENT_BYTES,
10
11
  FeedbackAttachmentField,
11
12
  type FeedbackAttachmentError,
@@ -28,9 +29,13 @@ export interface FeedbackAttachmentLabels {
28
29
  * straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */
29
30
  attachmentPaste?: string;
30
31
  attachmentRemove: string;
31
- /** `multiple` mode (0.15.5): the chip list's accessible name. Optional, as are the
32
- * two below — they fall back to the provider's `feedbackAttachment`, then English. */
32
+ /** `multiple` mode (0.15.5): the chip list's accessible name — and, in
33
+ * `<FeedbackDialog attachments="multiple">`, the heading over it (0.16.0). Optional,
34
+ * as are the keys below — they fall back to the provider's `feedbackAttachment`,
35
+ * then English. */
33
36
  attachmentList?: string;
37
+ /** `multiple` mode (0.16.0): the screenshot slot's chip title, in place of its file name. */
38
+ attachmentScreenshot?: string;
34
39
  /** `multiple` mode: one chip's remove button, given the file's name. */
35
40
  attachmentRemoveFile?: (name: string) => string;
36
41
  /** `multiple` mode: the line shown once `max` files are attached. */
@@ -46,8 +51,9 @@ export interface FeedbackDialogLabels extends FeedbackAttachmentLabels {
46
51
  submitHint: string;
47
52
  cancel: string;
48
53
  save: string;
49
- /** The heading over the attachments under `attachments="multiple"` (0.15.5), where
50
- * they are a screenshot AND photos. Optional; falls back to the provider, then English. */
54
+ /** @deprecated since 0.16.0 — use `attachmentList`, the one key for the heading and
55
+ * the chip list it names. Still honoured: set, it wins over the provider's
56
+ * `attachmentList` (but not over an `attachmentList` passed beside it). */
51
57
  attachments?: string;
52
58
  }
53
59
 
@@ -73,8 +79,10 @@ export interface FeedbackDialogTextLabels {
73
79
  submitHint: string;
74
80
  cancel: string;
75
81
  save: string;
76
- /** The heading over the attachments under `attachments="multiple"` (0.15.5).
77
- * Optional, so a complete `UiKitLabels` typed before 0.15.5 still compiles. */
82
+ /** @deprecated since 0.16.0 — use `feedbackAttachment.attachmentList`. It and this
83
+ * key were two names for one heading ("Attachments" over the chips that list names
84
+ * "Attachments"), and a catalogue that translated one left the other English. Still
85
+ * honoured when set: it wins over `feedbackAttachment.attachmentList`. */
78
86
  attachments?: string;
79
87
  }
80
88
 
@@ -85,7 +93,8 @@ export const DEFAULT_FEEDBACK_DIALOG_LABELS: FeedbackDialogTextLabels = {
85
93
  body: "What happened?",
86
94
  bodyOptional: "What happened? (optional)",
87
95
  attachment: "Screenshot",
88
- attachments: "Attachments",
96
+ // No `attachments`: the multiple-mode heading is `feedbackAttachment.attachmentList`,
97
+ // and a default here would shadow a provider that translated only that one.
89
98
  submitHint: "Ctrl/⌘ + Enter to send",
90
99
  cancel: "Cancel",
91
100
  save: "Send",
@@ -210,17 +219,23 @@ export function FeedbackDialog(props: FeedbackDialogProps) {
210
219
  const [files, setFiles] = useState<File[]>([]);
211
220
  const isMobile = useMediaQuery(PHONE_QUERY, false);
212
221
  const labels = useKitLabels("feedbackDialog", DEFAULT_FEEDBACK_DIALOG_LABELS, labelsProp);
222
+ const attachmentText = useKitLabels("feedbackAttachment", DEFAULT_FEEDBACK_ATTACHMENT_LABELS, labelsProp);
223
+ // Under `multiple` the heading is `attachmentList` — a screenshot AND photos — which
224
+ // also names the chip list beneath it: one string, so the two cannot disagree. The
225
+ // deprecated `feedbackDialog.attachments` (prop or provider) still wins over the
226
+ // provider's `attachmentList`, as it did before 0.16.0; an `attachmentList` prop wins
227
+ // over both.
228
+ const listHeading =
229
+ labelsProp?.attachmentList ??
230
+ labels.attachments ??
231
+ attachmentText.attachmentList ??
232
+ DEFAULT_FEEDBACK_ATTACHMENT_LABELS.attachmentList!;
213
233
  // The attachment field resolves its own keys from `feedbackAttachment`; it gets the
214
234
  // prop's (so a caller's `attachmentAdd` still wins) plus the resolved heading.
215
- // Under `multiple` the heading is `attachments` — a screenshot AND photos — unless the
216
- // caller named the multiple heading themselves.
217
- const attachmentLabels = {
218
- ...labelsProp,
219
- attachment:
220
- props.attachments === "multiple"
221
- ? (labels.attachments ?? DEFAULT_FEEDBACK_DIALOG_LABELS.attachments)
222
- : labels.attachment,
223
- };
235
+ const attachmentLabels =
236
+ props.attachments === "multiple"
237
+ ? { ...labelsProp, attachment: listHeading, attachmentList: listHeading }
238
+ : { ...labelsProp, attachment: labels.attachment };
224
239
 
225
240
  // Reset the form whenever the dialog is (re)opened — during render, on the
226
241
  // closed-to-open transition, so the old draft never paints for a frame.
@@ -21,6 +21,7 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
21
21
  attachmentPaste: "…oder einen Screenshot aus der Zwischenablage einfügen.",
22
22
  attachmentRemove: "Anhang entfernen",
23
23
  attachmentList: "Anhänge",
24
+ attachmentScreenshot: "Screenshot",
24
25
  attachmentRemoveFile: (name) => `${name} entfernen`,
25
26
  attachmentLimit: (max) => `Maximal ${n(max)} ${max === 1 ? "Anhang" : "Anhänge"} – zum Hinzufügen erst einen entfernen.`,
26
27
  },
@@ -31,7 +32,6 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
31
32
  body: "Was ist passiert?",
32
33
  bodyOptional: "Was ist passiert? (optional)",
33
34
  attachment: "Screenshot",
34
- attachments: "Anhänge",
35
35
  submitHint: "Strg/⌘ + Enter zum Senden",
36
36
  cancel: "Abbrechen",
37
37
  save: "Senden",
@@ -22,6 +22,7 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
22
22
  attachmentPaste: "…o pega una captura de pantalla desde el portapapeles.",
23
23
  attachmentRemove: "Quitar adjunto",
24
24
  attachmentList: "Adjuntos",
25
+ attachmentScreenshot: "Captura de pantalla",
25
26
  attachmentRemoveFile: (name) => `Quitar ${name}`,
26
27
  attachmentLimit: (max) => `Máximo ${n(max)} ${max === 1 ? "adjunto" : "adjuntos"}: quita uno para añadir otro.`,
27
28
  },
@@ -32,7 +33,6 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
32
33
  body: "¿Qué ha pasado?",
33
34
  bodyOptional: "¿Qué ha pasado? (opcional)",
34
35
  attachment: "Captura de pantalla",
35
- attachments: "Adjuntos",
36
36
  submitHint: "Ctrl/⌘ + Intro para enviar",
37
37
  cancel: "Cancelar",
38
38
  save: "Enviar",
@@ -22,6 +22,7 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
22
22
  attachmentPaste: "…ou collez une capture d’écran depuis le presse-papiers.",
23
23
  attachmentRemove: "Retirer la pièce jointe",
24
24
  attachmentList: "Pièces jointes",
25
+ attachmentScreenshot: "Capture d’écran",
25
26
  attachmentRemoveFile: (name) => `Retirer ${name}`,
26
27
  attachmentLimit: (max) => `${n(max)} ${max === 1 ? "pièce jointe" : "pièces jointes"} au maximum — retirez-en une pour en ajouter une autre.`,
27
28
  },
@@ -32,7 +33,6 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
32
33
  body: "Que s’est-il passé\u202f?",
33
34
  bodyOptional: "Que s’est-il passé\u202f? (facultatif)",
34
35
  attachment: "Capture d’écran",
35
- attachments: "Pièces jointes",
36
36
  submitHint: "Ctrl/⌘ + Entrée pour envoyer",
37
37
  cancel: "Annuler",
38
38
  save: "Envoyer",
@@ -21,6 +21,7 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
21
21
  attachmentPaste: "…vagy illesszen be egy képernyőképet a vágólapról.",
22
22
  attachmentRemove: "Melléklet eltávolítása",
23
23
  attachmentList: "Mellékletek",
24
+ attachmentScreenshot: "Képernyőkép",
24
25
  attachmentRemoveFile: (name) => `${name} eltávolítása`,
25
26
  attachmentLimit: (max) => `Legfeljebb ${n(max)} melléklet – egy újabbhoz távolítson el egyet.`,
26
27
  },
@@ -31,7 +32,6 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
31
32
  body: "Mi történt?",
32
33
  bodyOptional: "Mi történt? (nem kötelező)",
33
34
  attachment: "Képernyőkép",
34
- attachments: "Mellékletek",
35
35
  submitHint: "Ctrl/⌘ + Enter a küldéshez",
36
36
  cancel: "Mégse",
37
37
  save: "Küldés",
@@ -22,6 +22,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
22
22
  attachmentPaste: "…oppure incolla uno screenshot dagli appunti.",
23
23
  attachmentRemove: "Rimuovi allegato",
24
24
  attachmentList: "Allegati",
25
+ attachmentScreenshot: "Screenshot",
25
26
  attachmentRemoveFile: (name) => `Rimuovi ${name}`,
26
27
  attachmentLimit: (max) => `Massimo ${n(max)} ${max === 1 ? "allegato" : "allegati"}: rimuovine uno per aggiungerne un altro.`,
27
28
  },
@@ -32,7 +33,6 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
32
33
  body: "Cosa è successo?",
33
34
  bodyOptional: "Cosa è successo? (facoltativo)",
34
35
  attachment: "Screenshot",
35
- attachments: "Allegati",
36
36
  submitHint: "Ctrl/⌘ + Invio per inviare",
37
37
  cancel: "Annulla",
38
38
  save: "Invia",
@@ -21,6 +21,7 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
21
21
  attachmentPaste: "……或从剪贴板粘贴截图。",
22
22
  attachmentRemove: "移除附件",
23
23
  attachmentList: "附件",
24
+ attachmentScreenshot: "截图",
24
25
  attachmentRemoveFile: (name) => `移除 ${name}`,
25
26
  attachmentLimit: (max) => `最多 ${n(max)} 个附件,请先移除一个再添加。`,
26
27
  },
@@ -31,7 +32,6 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
31
32
  body: "发生了什么?",
32
33
  bodyOptional: "发生了什么?(可选)",
33
34
  attachment: "截图",
34
- attachments: "附件",
35
35
  submitHint: "Ctrl/⌘ + Enter 发送",
36
36
  cancel: "取消",
37
37
  save: "发送",
package/src/lib/format.ts CHANGED
@@ -365,15 +365,36 @@ export function currencyMinorDigits(currency: string | null | undefined): number
365
365
  }
366
366
  }
367
367
 
368
+ /** The options form of {@link roundToCurrency}'s third argument. */
369
+ export interface RoundToCurrencyOptions {
370
+ /** Decimals to round to, whatever the currency — the plain `digits` argument. */
371
+ digits?: number;
372
+ /**
373
+ * Decimals for a currency `Intl` cannot resolve — no code yet (`null`, `""`), or a
374
+ * malformed one ("EURO", "€"). Left out, such a value comes back unchanged, as
375
+ * before. Note that `Intl` resolves ANY well-formed three-letter code, a made-up
376
+ * "XYZ" included (to 2), so this is the case of a missing or broken code, not of a
377
+ * rare currency.
378
+ */
379
+ fallbackDigits?: number;
380
+ }
381
+
368
382
  /**
369
383
  * `value` rounded to the currency's minor unit (or to `digits`), half away from zero,
370
384
  * in decimal arithmetic: 93.4213 CHF → 93.42, 1.005 EUR → 1.01 (`Math.round(1.005 *
371
385
  * 100)` is 100, since 1.005 is 1.00499… in binary). A non-finite value, or a currency
372
386
  * `Intl` does not know without `digits`, comes back unchanged (keksdose live #356: an
373
- * FX estimate set into an AmountInput showed four decimals).
387
+ * FX estimate set into an AmountInput showed four decimals) — unless the options form
388
+ * gives `fallbackDigits`: `roundToCurrency(v, code, { fallbackDigits: 2 })` rounds a
389
+ * figure whose currency is not chosen yet to cents rather than leaving 0.1 + 0.2 as is.
374
390
  */
375
- export function roundToCurrency(value: number, currency: string | null | undefined, digits?: number): number {
376
- const places = digits ?? currencyMinorDigits(currency);
391
+ export function roundToCurrency(
392
+ value: number,
393
+ currency: string | null | undefined,
394
+ digits?: number | RoundToCurrencyOptions,
395
+ ): number {
396
+ const options = typeof digits === "object" && digits !== null ? digits : { digits };
397
+ const places = options.digits ?? currencyMinorDigits(currency) ?? options.fallbackDigits;
377
398
  if (places === undefined || !Number.isFinite(value)) return value;
378
399
  const magnitude = Number(`${Math.round(Number(`${Math.abs(value)}e${places}`))}e-${places}`);
379
400
  return value < 0 ? -magnitude : magnitude;
@@ -23,6 +23,12 @@
23
23
  * itself — the `rules` here, or a resolver's `lines: "At least two lines"` — is the
24
24
  * list's `error`. Each cell's `render` gets `name`, the row's path
25
25
  * (`"components.2"`), to bind its field to.
26
+ *
27
+ * `summary`, `fieldLabels` and `narrowColumns` pass through to {@link LineItems}. With
28
+ * `fieldLabels="floating"` a cell's `fieldLabel` is the column's name; the bound
29
+ * fields' own `label` is a `FormLabel` ABOVE the control, so for the floating
30
+ * one render the kit field through `RhfField`:
31
+ * `render={({ field, invalid }) => <Input label={fieldLabel} aria-label={label} {...field} invalid={invalid} />}`.
26
32
  */
27
33
  import type { ReactNode } from "react";
28
34
  import {