@eifi1/ui-kit 0.21.0 → 0.22.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 (278) hide show
  1. package/dist/chart.d.ts +10 -8
  2. package/dist/components/account-chips.d.ts +10 -3
  3. package/dist/components/account-chips.js +5 -2
  4. package/dist/components/account-chips.js.map +1 -1
  5. package/dist/components/account-settings.d.ts +33 -2
  6. package/dist/components/account-settings.js +43 -21
  7. package/dist/components/account-settings.js.map +1 -1
  8. package/dist/components/amount-input.d.ts +27 -8
  9. package/dist/components/amount-input.js +15 -28
  10. package/dist/components/amount-input.js.map +1 -1
  11. package/dist/components/autocomplete.d.ts +8 -0
  12. package/dist/components/autocomplete.js +9 -4
  13. package/dist/components/autocomplete.js.map +1 -1
  14. package/dist/components/button-group.d.ts +10 -8
  15. package/dist/components/calculator.d.ts +10 -8
  16. package/dist/components/checkbox-group.d.ts +104 -0
  17. package/dist/components/checkbox-group.js +111 -0
  18. package/dist/components/checkbox-group.js.map +1 -0
  19. package/dist/components/checkbox.d.ts +19 -0
  20. package/dist/components/checkbox.js +30 -7
  21. package/dist/components/checkbox.js.map +1 -1
  22. package/dist/components/chip.d.ts +18 -0
  23. package/dist/components/chip.js +47 -10
  24. package/dist/components/chip.js.map +1 -1
  25. package/dist/components/combobox.d.ts +13 -2
  26. package/dist/components/combobox.js +17 -8
  27. package/dist/components/combobox.js.map +1 -1
  28. package/dist/components/confirm-dialog.d.ts +66 -161
  29. package/dist/components/copy-button.d.ts +10 -8
  30. package/dist/components/country-select.d.ts +124 -0
  31. package/dist/components/country-select.js +237 -0
  32. package/dist/components/country-select.js.map +1 -0
  33. package/dist/components/currency-select.d.ts +17 -1
  34. package/dist/components/currency-select.js +56 -23
  35. package/dist/components/currency-select.js.map +1 -1
  36. package/dist/components/danger-confirm.d.ts +66 -166
  37. package/dist/components/danger-confirm.js +133 -49
  38. package/dist/components/danger-confirm.js.map +1 -1
  39. package/dist/components/data-table-cells.d.ts +1 -2
  40. package/dist/components/data-table-filter-popover.d.ts +1 -2
  41. package/dist/components/data-table-filters.d.ts +1 -2
  42. package/dist/components/data-table-labels.d.ts +4 -97
  43. package/dist/components/data-table-labels.js +9 -1
  44. package/dist/components/data-table-labels.js.map +1 -1
  45. package/dist/components/data-table-pagination.d.ts +3 -1
  46. package/dist/components/data-table.d.ts +1 -2
  47. package/dist/components/data-table.js +98 -3
  48. package/dist/components/data-table.js.map +1 -1
  49. package/dist/components/date-picker.d.ts +25 -5
  50. package/dist/components/date-picker.js +110 -59
  51. package/dist/components/date-picker.js.map +1 -1
  52. package/dist/components/entity-combobox.d.ts +8 -1
  53. package/dist/components/entity-combobox.js +9 -4
  54. package/dist/components/entity-combobox.js.map +1 -1
  55. package/dist/components/facing-pair.d.ts +10 -8
  56. package/dist/components/field-anatomy.d.ts +95 -0
  57. package/dist/components/field-anatomy.js +84 -0
  58. package/dist/components/field-anatomy.js.map +1 -0
  59. package/dist/components/field-parts.d.ts +114 -0
  60. package/dist/components/field-parts.js +72 -0
  61. package/dist/components/field-parts.js.map +1 -0
  62. package/dist/components/file-button.d.ts +10 -8
  63. package/dist/components/file-button.js +13 -3
  64. package/dist/components/file-button.js.map +1 -1
  65. package/dist/components/file-dropzone.d.ts +32 -9
  66. package/dist/components/file-dropzone.js +57 -34
  67. package/dist/components/file-dropzone.js.map +1 -1
  68. package/dist/components/form-actions.d.ts +10 -8
  69. package/dist/components/form-actions.js +61 -3
  70. package/dist/components/form-actions.js.map +1 -1
  71. package/dist/components/iban-input.d.ts +66 -0
  72. package/dist/components/iban-input.js +125 -0
  73. package/dist/components/iban-input.js.map +1 -0
  74. package/dist/components/icon-picker.d.ts +12 -2
  75. package/dist/components/icon-picker.js +9 -2
  76. package/dist/components/icon-picker.js.map +1 -1
  77. package/dist/components/inline-edit-field.d.ts +167 -0
  78. package/dist/components/inline-edit-field.js +293 -0
  79. package/dist/components/inline-edit-field.js.map +1 -0
  80. package/dist/components/language-select.d.ts +127 -0
  81. package/dist/components/language-select.js +18 -0
  82. package/dist/components/language-select.js.map +1 -0
  83. package/dist/components/line-items.d.ts +25 -3
  84. package/dist/components/line-items.js +55 -46
  85. package/dist/components/line-items.js.map +1 -1
  86. package/dist/components/list.d.ts +25 -0
  87. package/dist/components/list.js +16 -5
  88. package/dist/components/list.js.map +1 -1
  89. package/dist/components/money-field.d.ts +20 -8
  90. package/dist/components/money-field.js.map +1 -1
  91. package/dist/components/month-picker.d.ts +52 -4
  92. package/dist/components/month-picker.js +290 -86
  93. package/dist/components/month-picker.js.map +1 -1
  94. package/dist/components/multi-select.d.ts +8 -1
  95. package/dist/components/multi-select.js +9 -4
  96. package/dist/components/multi-select.js.map +1 -1
  97. package/dist/components/number-field.d.ts +25 -13
  98. package/dist/components/number-field.js +6 -20
  99. package/dist/components/number-field.js.map +1 -1
  100. package/dist/components/number-input.d.ts +70 -13
  101. package/dist/components/number-input.js +90 -38
  102. package/dist/components/number-input.js.map +1 -1
  103. package/dist/components/numpad-sheet.d.ts +10 -8
  104. package/dist/components/one-time-code-input.d.ts +100 -0
  105. package/dist/components/one-time-code-input.js +137 -0
  106. package/dist/components/one-time-code-input.js.map +1 -0
  107. package/dist/components/phone-input.d.ts +66 -0
  108. package/dist/components/phone-input.js +171 -0
  109. package/dist/components/phone-input.js.map +1 -0
  110. package/dist/components/series-chart.d.ts +10 -8
  111. package/dist/components/settings-fields.d.ts +10 -8
  112. package/dist/components/share-card.d.ts +8 -6
  113. package/dist/components/sign-chip.d.ts +66 -0
  114. package/dist/components/sign-chip.js +39 -0
  115. package/dist/components/sign-chip.js.map +1 -0
  116. package/dist/components/swatch-picker.d.ts +27 -2
  117. package/dist/components/swatch-picker.js +73 -31
  118. package/dist/components/swatch-picker.js.map +1 -1
  119. package/dist/components/switch.d.ts +19 -0
  120. package/dist/components/switch.js +24 -6
  121. package/dist/components/switch.js.map +1 -1
  122. package/dist/components/text-link.d.ts +10 -8
  123. package/dist/components/tile-radio.d.ts +68 -13
  124. package/dist/components/tile-radio.js +3 -3
  125. package/dist/components/tile-radio.js.map +1 -1
  126. package/dist/components/time-input.d.ts +15 -9
  127. package/dist/components/time-input.js.map +1 -1
  128. package/dist/components/toggle-group.d.ts +47 -1
  129. package/dist/components/toggle-group.js +110 -69
  130. package/dist/components/toggle-group.js.map +1 -1
  131. package/dist/components/ui.d.ts +10 -8
  132. package/dist/components/ui.js +280 -78
  133. package/dist/components/ui.js.map +1 -1
  134. package/dist/components/use-table-state.d.ts +1 -2
  135. package/dist/{data-table-3mi2R3so.d.ts → data-table-labels-B7OdnM0S.d.ts} +140 -3
  136. package/dist/data-table.d.ts +1 -2
  137. package/dist/data-table.js +2 -1
  138. package/dist/data-table.js.map +1 -1
  139. package/dist/feedback/feedback-attachment.d.ts +1 -1
  140. package/dist/feedback/feedback-attachment.js +210 -3
  141. package/dist/feedback/feedback-attachment.js.map +1 -1
  142. package/dist/feedback/feedback-dialog.d.ts +1 -1
  143. package/dist/feedback/feedback-dialog.js.map +1 -1
  144. package/dist/feedback/feedback-inbox.d.ts +1 -1
  145. package/dist/feedback/feedback-thread.d.ts +37 -3
  146. package/dist/feedback/feedback-thread.js +38 -9
  147. package/dist/feedback/feedback-thread.js.map +1 -1
  148. package/dist/{feedback-attachment-WFiXJ8We.d.ts → feedback-attachment-NhUm7Zga.d.ts} +70 -5
  149. package/dist/feedback.d.ts +2 -2
  150. package/dist/hooks/use-file-drop.d.ts +10 -8
  151. package/dist/i18n/defaults.d.ts +10 -8
  152. package/dist/i18n/defaults.js +17 -2
  153. package/dist/i18n/defaults.js.map +1 -1
  154. package/dist/i18n/german.d.ts +10 -8
  155. package/dist/i18n/german.js +50 -5
  156. package/dist/i18n/german.js.map +1 -1
  157. package/dist/i18n/kit-labels.d.ts +10 -8
  158. package/dist/i18n/kit-labels.js +8 -2
  159. package/dist/i18n/kit-labels.js.map +1 -1
  160. package/dist/i18n/languages.d.ts +10 -8
  161. package/dist/i18n/locales/de-CH.d.ts +10 -8
  162. package/dist/i18n/locales/en.d.ts +10 -8
  163. package/dist/i18n/locales/en.js +9 -0
  164. package/dist/i18n/locales/en.js.map +1 -1
  165. package/dist/i18n/locales/es.d.ts +10 -8
  166. package/dist/i18n/locales/es.js +48 -5
  167. package/dist/i18n/locales/es.js.map +1 -1
  168. package/dist/i18n/locales/fr.d.ts +10 -8
  169. package/dist/i18n/locales/fr.js +48 -5
  170. package/dist/i18n/locales/fr.js.map +1 -1
  171. package/dist/i18n/locales/hu.d.ts +10 -8
  172. package/dist/i18n/locales/hu.js +49 -5
  173. package/dist/i18n/locales/hu.js.map +1 -1
  174. package/dist/i18n/locales/it.d.ts +10 -8
  175. package/dist/i18n/locales/it.js +49 -5
  176. package/dist/i18n/locales/it.js.map +1 -1
  177. package/dist/i18n/locales/zh.d.ts +10 -8
  178. package/dist/i18n/locales/zh.js +48 -5
  179. package/dist/i18n/locales/zh.js.map +1 -1
  180. package/dist/i18n/review.d.ts +10 -8
  181. package/dist/i18n/review.js +8 -1
  182. package/dist/i18n/review.js.map +1 -1
  183. package/dist/index.d.ts +17 -10
  184. package/dist/index.js +57 -2
  185. package/dist/index.js.map +1 -1
  186. package/dist/{kit-labels-D1J2_jyD.d.ts → kit-labels-R8mIAc9N.d.ts} +811 -8
  187. package/dist/lib/countries.d.ts +43 -0
  188. package/dist/lib/countries.js +39 -0
  189. package/dist/lib/countries.js.map +1 -0
  190. package/dist/lib/decimal-marks.d.ts +46 -0
  191. package/dist/lib/decimal-marks.js +40 -0
  192. package/dist/lib/decimal-marks.js.map +1 -0
  193. package/dist/lib/iban.d.ts +98 -0
  194. package/dist/lib/iban.js +154 -0
  195. package/dist/lib/iban.js.map +1 -0
  196. package/dist/lib/isin.d.ts +30 -0
  197. package/dist/lib/isin.js +36 -0
  198. package/dist/lib/isin.js.map +1 -0
  199. package/dist/lib/phone.d.ts +69 -0
  200. package/dist/lib/phone.js +121 -0
  201. package/dist/lib/phone.js.map +1 -0
  202. package/dist/rhf/fields.d.ts +148 -11
  203. package/dist/rhf/fields.js +332 -3
  204. package/dist/rhf/fields.js.map +1 -1
  205. package/dist/rhf/form.d.ts +10 -8
  206. package/dist/rhf.d.ts +13 -9
  207. package/dist/rhf.js.map +1 -1
  208. package/dist/shell/app-shell.d.ts +10 -8
  209. package/dist/shell/top-bar-brand.d.ts +10 -8
  210. package/dist/shell.d.ts +10 -8
  211. package/dist/tour/tour.js +20 -24
  212. package/dist/tour/tour.js.map +1 -1
  213. package/dist/wizard/stepper-nav.d.ts +10 -8
  214. package/dist/wizard.d.ts +10 -8
  215. package/package.json +1 -1
  216. package/src/components/account-chips.tsx +17 -3
  217. package/src/components/account-settings.tsx +92 -26
  218. package/src/components/amount-input.tsx +49 -56
  219. package/src/components/autocomplete.tsx +133 -110
  220. package/src/components/checkbox-group.tsx +229 -0
  221. package/src/components/checkbox.tsx +72 -8
  222. package/src/components/chip.tsx +80 -10
  223. package/src/components/combobox.tsx +292 -253
  224. package/src/components/country-select.tsx +443 -0
  225. package/src/components/currency-select.tsx +109 -33
  226. package/src/components/danger-confirm.tsx +345 -77
  227. package/src/components/data-table-labels.ts +16 -1
  228. package/src/components/data-table.tsx +175 -6
  229. package/src/components/date-picker.tsx +173 -62
  230. package/src/components/entity-combobox.tsx +107 -87
  231. package/src/components/field-anatomy.tsx +190 -0
  232. package/src/components/field-parts.tsx +184 -0
  233. package/src/components/file-button.tsx +36 -3
  234. package/src/components/file-dropzone.tsx +106 -38
  235. package/src/components/form-actions.tsx +115 -2
  236. package/src/components/iban-input.tsx +231 -0
  237. package/src/components/icon-picker.tsx +26 -4
  238. package/src/components/inline-edit-field.tsx +533 -0
  239. package/src/components/language-select.tsx +78 -0
  240. package/src/components/line-items.tsx +35 -2
  241. package/src/components/list.tsx +55 -6
  242. package/src/components/money-field.tsx +10 -0
  243. package/src/components/month-picker.tsx +399 -63
  244. package/src/components/multi-select.tsx +80 -58
  245. package/src/components/number-field.tsx +28 -46
  246. package/src/components/number-input.tsx +210 -43
  247. package/src/components/one-time-code-input.tsx +288 -0
  248. package/src/components/phone-input.tsx +299 -0
  249. package/src/components/sign-chip.tsx +103 -0
  250. package/src/components/swatch-picker.tsx +118 -30
  251. package/src/components/switch.tsx +58 -7
  252. package/src/components/tile-radio.tsx +71 -16
  253. package/src/components/time-input.tsx +8 -1
  254. package/src/components/toggle-group.tsx +206 -73
  255. package/src/components/ui.tsx +472 -105
  256. package/src/data-table.ts +2 -1
  257. package/src/feedback/feedback-attachment.tsx +313 -9
  258. package/src/feedback/feedback-dialog.tsx +2 -0
  259. package/src/feedback/feedback-thread.tsx +66 -5
  260. package/src/i18n/defaults.ts +16 -1
  261. package/src/i18n/german.ts +47 -0
  262. package/src/i18n/kit-labels.tsx +78 -2
  263. package/src/i18n/locales/en.ts +10 -0
  264. package/src/i18n/locales/es.ts +46 -0
  265. package/src/i18n/locales/fr.ts +45 -0
  266. package/src/i18n/locales/hu.ts +46 -0
  267. package/src/i18n/locales/it.ts +47 -0
  268. package/src/i18n/locales/zh.ts +44 -0
  269. package/src/i18n/review.ts +7 -0
  270. package/src/index.ts +53 -3
  271. package/src/lib/countries.ts +91 -0
  272. package/src/lib/decimal-marks.ts +99 -0
  273. package/src/lib/iban.ts +171 -0
  274. package/src/lib/isin.ts +62 -0
  275. package/src/lib/phone.ts +211 -0
  276. package/src/rhf/fields.tsx +606 -9
  277. package/src/rhf.ts +2 -1
  278. package/src/tour/tour.tsx +66 -28
@@ -1,5 +1,4 @@
1
1
  import 'react';
2
2
  import './data-table-sort.js';
3
- export { z as DEFAULT_PERSIST_PREFIX, T as TableUrlState, g as TableUrlStateProps, h as TableUrlSync, U as UseTableUrlStateOptions, i as UseTableUrlStateReturn, r as readTableUrlState, A as useTableState, w as useTableUrlState } from '../data-table-3mi2R3so.js';
3
+ export { I as DEFAULT_PERSIST_PREFIX, T as TableUrlState, k as TableUrlStateProps, l as TableUrlSync, U as UseTableUrlStateOptions, m as UseTableUrlStateReturn, w as readTableUrlState, J as useTableState, E as useTableUrlState } from '../data-table-labels-B7OdnM0S.js';
4
4
  import './swipeable-row.js';
5
- import './data-table-labels.js';
@@ -2,7 +2,6 @@ import * as react from 'react';
2
2
  import { ReactNode, TdHTMLAttributes, ThHTMLAttributes } from 'react';
3
3
  import { SortState, SortDir, SortCycle } from './components/data-table-sort.js';
4
4
  import { SwipeAction } from './components/swipeable-row.js';
5
- import { DataTableLabels } from './components/data-table-labels.js';
6
5
 
7
6
  /** How a column is filtered. `text`/`select`/`date`/`number` each read a value
8
7
  * off the row and compare it against the user's {@link FilterValue}. */
@@ -280,6 +279,14 @@ interface DataTableColumn<T> {
280
279
  * Default `"asc"`.
281
280
  */
282
281
  firstSort?: SortDir;
282
+ /**
283
+ * The column's name as plain text, for the places a ReactNode `header` cannot go:
284
+ * the phone sort control's options ({@link DataTableProps.mobileSort}), the spoken
285
+ * "Sorted by …" and the column-settings checklist. Only needed when `header` is not
286
+ * a string (an icon, a unit suffix); without it those places fall back to the
287
+ * header string, then to `key`.
288
+ */
289
+ headerText?: string;
283
290
  /**
284
291
  * Extra attributes for this column's `<td>` in a given row — a `data-*` hook, a
285
292
  * `title`, an `aria-describedby`, a class. keksdose's accounts page
@@ -537,6 +544,18 @@ interface DataTableProps<T> {
537
544
  * wastes space (feedback #317). Desktop is unaffected.
538
545
  */
539
546
  mobileCard?: (row: T) => ReactNode;
547
+ /**
548
+ * A "Sort by" select and a direction button above the phone card list (keksdose
549
+ * K10). The card list has no header row, so without it a phone user is stuck with
550
+ * whatever order the table opened in. It drives the same sort state as the column
551
+ * headers — `sorts`/`onSortsChange` when controlled, the URL and `storageKey` when
552
+ * not — and offers the columns a header click could sort (those with a `sortBy`).
553
+ * Each option is named by the column's `headerText`, else its string `header`.
554
+ *
555
+ * Off by default, so no existing phone layout gains a row. Strings:
556
+ * {@link DataTableSortLabels}. Phones only; the desktop table is unchanged.
557
+ */
558
+ mobileSort?: boolean;
540
559
  /**
541
560
  * Swipe actions for a mobile row, revealed by dragging it horizontally. Return
542
561
  * `null` (or empty sides) for rows that should not move — a locked row, one whose
@@ -714,7 +733,125 @@ interface MobileSwipeActions {
714
733
  /** Committed by dragging physically RIGHT, whatever the direction. */
715
734
  right?: SwipeAction[];
716
735
  }
736
+ /**
737
+ * The phone sort control's strings (keksdose K10). They are `dataTable` strings —
738
+ * read from the table's resolved labels, so the `labels` prop and the provider's
739
+ * `dataTable` namespace reach them — and are declared here, beside the control, with
740
+ * English defaults until `DataTableLabels` declares them itself.
741
+ */
742
+ interface DataTableSortLabels {
743
+ /** The control's visible label: "Sort by". */
744
+ sortBy: string;
745
+ /** The "no sort" option — the rows in the order they were given: "Default order". */
746
+ sortDefault: string;
747
+ /** The direction button's name while the sort ascends: "Ascending". */
748
+ sortAscending: string;
749
+ /** …and while it descends: "Descending". */
750
+ sortDescending: string;
751
+ }
752
+ /** The phone sort control's words, as they sit in {@link DEFAULT_DATA_TABLE_LABELS}
753
+ * (DataTableLabels extends DataTableSortLabels; one source for the English). */
754
+ declare const DEFAULT_DATA_TABLE_SORT_LABELS: DataTableSortLabels;
717
755
 
718
- declare function DataTable<T>({ rows, columns: columnsProp, rowKey, defaultPageSize, onRowClick, rowHref, expandedRow, isExpanded, rowClassName, rowAttributes, paginated, empty, storageKey, urlSync, fillHeight, maxBodyHeight, serverPagination, filters: filtersProp, onFiltersChange, sorts: sortsProp, onSortsChange, selection, labels: labelsProp, locale: localeProp, storageKeyPrefix, mobileExpandAsDialog, mobileDialogBackCloses, mobileGroupBy, mobileGroupLabel, mobileCard, mobileSwipeActions, leadingRow, density, sortCycle, chrome, columnSettings: columnSettingsProp, resizable: resizableProp, multiSort: multiSortProp, frame, className, rowActions, toolbar, footerLabel, footer: footerProp, }: DataTableProps<T>): react.JSX.Element;
756
+ declare function DataTable<T>({ rows, columns: columnsProp, rowKey, defaultPageSize, onRowClick, rowHref, expandedRow, isExpanded, rowClassName, rowAttributes, paginated, empty, storageKey, urlSync, fillHeight, maxBodyHeight, serverPagination, filters: filtersProp, onFiltersChange, sorts: sortsProp, onSortsChange, selection, labels: labelsProp, locale: localeProp, storageKeyPrefix, mobileExpandAsDialog, mobileDialogBackCloses, mobileGroupBy, mobileGroupLabel, mobileCard, mobileSort, mobileSwipeActions, leadingRow, density, sortCycle, chrome, columnSettings: columnSettingsProp, resizable: resizableProp, multiSort: multiSortProp, frame, className, rowActions, toolbar, footerLabel, footer: footerProp, }: DataTableProps<T>): react.JSX.Element;
757
+
758
+ /** The phone sort control's four keys (`sortBy`, `sortDefault`, `sortAscending`,
759
+ * `sortDescending`, 0.22.0) are {@link DataTableSortLabels}', declared beside the
760
+ * control and part of this namespace like every other key. */
761
+ interface DataTableLabels extends DataTableSortLabels {
762
+ columns: string;
763
+ selectAllRows: string;
764
+ sortHint: string;
765
+ filter: string;
766
+ close: string;
767
+ selectRow: string;
768
+ autoSize: string;
769
+ loading: string;
770
+ filters: string;
771
+ clearAll: string;
772
+ done: string;
773
+ pageSize: string;
774
+ pageSizeAll: string;
775
+ prevPage: string;
776
+ nextPage: string;
777
+ clearFilter: string;
778
+ filterPlaceholder: string;
779
+ selectFilter: string;
780
+ selectAll: string;
781
+ selectNone: string;
782
+ dateFrom: string;
783
+ dateTo: string;
784
+ numberMin: string;
785
+ numberMax: string;
786
+ numberAbs: string;
787
+ presets: Record<string, string>;
788
+ /**
789
+ * The table's own accessible name. Deliberately a label rather than a second,
790
+ * parallel `tableLabel` prop: the audit already records "three different prop
791
+ * names for the accessible name" as a finding, and a table that is not "Data
792
+ * table" says so with `labels={{ table: "Transactions" }}` at the call site.
793
+ */
794
+ table: string;
795
+ /** After a filter changes: "12 of 137 rows". */
796
+ filterResults: (shown: number, total: number) => string;
797
+ /** After a header is activated: "Sorted by Name, ascending". */
798
+ sortedAscending: (column: string) => string;
799
+ sortedDescending: (column: string) => string;
800
+ /** The third click, which removes the column from the sort entirely. */
801
+ sortCleared: (column: string) => string;
802
+ /** After paging: "Page 3 of 14". `page` is 1-BASED, as spoken. */
803
+ pageChanged: (page: number, totalPages: number) => string;
804
+ /** The pagination range summary: "1–25 / 137". */
805
+ pageRange: (from: number, to: number, total: number) => string;
806
+ /** The same summary when the page size is "all" — just the row count. */
807
+ rowCount: (total: number) => string;
808
+ /** The column-settings rail and its heading: "Columns (4/9)". */
809
+ columnsCount: (visible: number, total: number) => string;
810
+ /** The body of a table with no rows and no `empty` prop of its own. A sentence, not
811
+ * "—": a dash in the only row of a table reads as one row with a missing value. */
812
+ empty: string;
813
+ /** The accessible name of the `rowActions` column (its header is visually empty). */
814
+ actions: string;
815
+ /** The `kind: "edit"` row action's name — its tooltip and its swipe label. */
816
+ edit: string;
817
+ /** The `kind: "delete"` row action's name. */
818
+ delete: string;
819
+ /** What {@link BooleanMark} says to a screen reader for `true` / `false` / nothing. */
820
+ booleanTrue: string;
821
+ booleanFalse: string;
822
+ booleanUnset: string;
823
+ }
824
+ declare const DEFAULT_DATA_TABLE_LABELS: DataTableLabels;
825
+ /**
826
+ * Merge caller overrides onto the English defaults (presets merged too).
827
+ *
828
+ * The parameter is `Partial` on purpose — a table with no labels at all still
829
+ * renders — but that is also how a translated app ends up half English and never
830
+ * hears about it: lenkbank ships nineteen of these keys in English in a German UI
831
+ * today, because every one of them is backfilled silently. The kit will not start
832
+ * throwing over it (three apps depend on the lenient merge), so
833
+ * {@link missingDataTableLabels} is the other half: it answers which keys fell back,
834
+ * and an app asserts on that in its OWN test, where the answer is actionable.
835
+ */
836
+ declare function resolveDataTableLabels(partial?: Partial<DataTableLabels>): DataTableLabels;
837
+ /**
838
+ * The label keys `labels` does not supply, and which therefore come back English
839
+ * from {@link resolveDataTableLabels}.
840
+ *
841
+ * For a consumer's own test:
842
+ *
843
+ * ```ts
844
+ * expect(missingDataTableLabels(de.dataTable)).toEqual([]);
845
+ * ```
846
+ *
847
+ * which fails the day the kit adds a key — which is the point. Adding a label is
848
+ * additive here and a silent regression in a translated app, and nothing else in
849
+ * either repository can tell the two apart.
850
+ *
851
+ * Preset labels are reported one at a time (`presets.yesterday`), because `presets`
852
+ * is a `Record` merged key by key: answering `"presets"` would say nothing about
853
+ * which of the eleven are still English.
854
+ */
855
+ declare function missingDataTableLabels(labels?: Partial<DataTableLabels>): string[];
719
856
 
720
- export { useTableState as A, type ColumnFilter as C, DataTable as D, type FilterState as F, type MobileSwipeActions as M, type ServerPagination as S, type TableUrlState as T, type UseTableUrlStateOptions as U, type DataTableChrome as a, type DataTableColumn as b, type DataTableDensity as c, type DataTableProps as d, type DataTableRowAction as e, type FilterValue as f, type TableUrlStateProps as g, type TableUrlSync as h, type UseTableUrlStateReturn as i, dateFilter as j, decodeFilterValue as k, decodeFilterValueOfType as l, defaultFilterState as m, encodeFilterValue as n, filterHref as o, isFilterActive as p, numberFilter as q, readTableUrlState as r, resolveFilter as s, rowMatches as t, selectFilter as u, textFilter as v, useTableUrlState as w, type DataTableCellProps as x, type DataTableHeadProps as y, DEFAULT_PERSIST_PREFIX as z };
857
+ export { selectFilter as A, textFilter as B, type ColumnFilter as C, DEFAULT_DATA_TABLE_LABELS as D, useTableUrlState as E, type FilterState as F, type DataTableCellProps as G, type DataTableHeadProps as H, DEFAULT_PERSIST_PREFIX as I, useTableState as J, type MobileSwipeActions as M, type ServerPagination as S, type TableUrlState as T, type UseTableUrlStateOptions as U, DEFAULT_DATA_TABLE_SORT_LABELS as a, DataTable as b, type DataTableChrome as c, type DataTableColumn as d, type DataTableDensity as e, type DataTableLabels as f, type DataTableProps as g, type DataTableRowAction as h, type DataTableSortLabels as i, type FilterValue as j, type TableUrlStateProps as k, type TableUrlSync as l, type UseTableUrlStateReturn as m, dateFilter as n, decodeFilterValue as o, decodeFilterValueOfType as p, defaultFilterState as q, encodeFilterValue as r, filterHref as s, isFilterActive as t, missingDataTableLabels as u, numberFilter as v, readTableUrlState as w, resolveDataTableLabels as x, resolveFilter as y, rowMatches as z };
@@ -1,6 +1,5 @@
1
- export { DEFAULT_DATA_TABLE_LABELS, DataTableLabels, missingDataTableLabels, resolveDataTableLabels } from './components/data-table-labels.js';
1
+ export { C as ColumnFilter, D as DEFAULT_DATA_TABLE_LABELS, a as DEFAULT_DATA_TABLE_SORT_LABELS, b as DataTable, c as DataTableChrome, d as DataTableColumn, e as DataTableDensity, f as DataTableLabels, g as DataTableProps, h as DataTableRowAction, i as DataTableSortLabels, F as FilterState, j as FilterValue, M as MobileSwipeActions, S as ServerPagination, T as TableUrlState, k as TableUrlStateProps, l as TableUrlSync, U as UseTableUrlStateOptions, m as UseTableUrlStateReturn, n as dateFilter, o as decodeFilterValue, p as decodeFilterValueOfType, q as defaultFilterState, r as encodeFilterValue, s as filterHref, t as isFilterActive, u as missingDataTableLabels, v as numberFilter, w as readTableUrlState, x as resolveDataTableLabels, y as resolveFilter, z as rowMatches, A as selectFilter, B as textFilter, E as useTableUrlState } from './data-table-labels-B7OdnM0S.js';
2
2
  export { SortCycle, SortDir, SortState, SortStepOptions, decodeSorts, encodeSorts, nextSorts, normalizeSorts } from './components/data-table-sort.js';
3
- export { C as ColumnFilter, D as DataTable, a as DataTableChrome, b as DataTableColumn, c as DataTableDensity, d as DataTableProps, e as DataTableRowAction, F as FilterState, f as FilterValue, M as MobileSwipeActions, S as ServerPagination, T as TableUrlState, g as TableUrlStateProps, h as TableUrlSync, U as UseTableUrlStateOptions, i as UseTableUrlStateReturn, j as dateFilter, k as decodeFilterValue, l as decodeFilterValueOfType, m as defaultFilterState, n as encodeFilterValue, o as filterHref, p as isFilterActive, q as numberFilter, r as readTableUrlState, s as resolveFilter, t as rowMatches, u as selectFilter, v as textFilter, w as useTableUrlState } from './data-table-3mi2R3so.js';
4
3
  export { PAGE_SIZE_OPTIONS, Pagination } from './components/data-table-pagination.js';
5
4
  export { FilterPopover } from './components/data-table-filter-popover.js';
6
5
  export { BooleanColumnOptions, BooleanMark, BooleanMarkProps, booleanColumn } from './components/data-table-cells.js';
@@ -4,10 +4,11 @@ export * from "./components/data-table-sort.js";
4
4
  export * from "./components/data-table-filters.js";
5
5
  export * from "./components/data-table-pagination.js";
6
6
  import { FilterPopover } from "./components/data-table-filter-popover.js";
7
- import { DataTable } from "./components/data-table.js";
7
+ import { DataTable, DEFAULT_DATA_TABLE_SORT_LABELS } from "./components/data-table.js";
8
8
  export * from "./components/data-table-cells.js";
9
9
  import { useTableUrlState, readTableUrlState } from "./components/use-table-state.js";
10
10
  export {
11
+ DEFAULT_DATA_TABLE_SORT_LABELS,
11
12
  DataTable,
12
13
  FilterPopover,
13
14
  readTableUrlState,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/data-table.ts"],"sourcesContent":["// `@eifi1/ui-kit/data-table` — the table suite.\n//\n// A re-slicing of the main barrel, not a new API. This entry point requires\n// `react-router`: DataTable calls useSearchParams unconditionally, above any `urlSync`\n// branch, so a Router is needed even with URL sync switched off.\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// `SortState` comes from data-table-sort above; re-exporting the module wholesale\n// would collide with it, which is why the main barrel names these explicitly too.\nexport { DataTable } from \"./components/data-table\";\nexport type {\n DataTableColumn,\n DataTableProps,\n ServerPagination,\n FilterState,\n MobileSwipeActions,\n DataTableDensity,\n DataTableChrome,\n DataTableRowAction,\n} from \"./components/data-table\";\nexport * from \"./components/data-table-cells\";\nexport { useTableUrlState, readTableUrlState } from \"./components/use-table-state\";\nexport type {\n TableUrlState,\n TableUrlSync,\n TableUrlStateProps,\n UseTableUrlStateOptions,\n UseTableUrlStateReturn,\n} from \"./components/use-table-state\";\n"],"mappings":";AAKA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;AAW1B,cAAc;AACd,SAAS,kBAAkB,yBAAyB;","names":[]}
1
+ {"version":3,"sources":["../src/data-table.ts"],"sourcesContent":["// `@eifi1/ui-kit/data-table` — the table suite.\n//\n// A re-slicing of the main barrel, not a new API. This entry point requires\n// `react-router`: DataTable calls useSearchParams unconditionally, above any `urlSync`\n// branch, so a Router is needed even with URL sync switched off.\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// `SortState` comes from data-table-sort above; re-exporting the module wholesale\n// would collide with it, which is why the main barrel names these explicitly too.\nexport { DataTable, DEFAULT_DATA_TABLE_SORT_LABELS } from \"./components/data-table\";\nexport type {\n DataTableSortLabels,\n DataTableColumn,\n DataTableProps,\n ServerPagination,\n FilterState,\n MobileSwipeActions,\n DataTableDensity,\n DataTableChrome,\n DataTableRowAction,\n} from \"./components/data-table\";\nexport * from \"./components/data-table-cells\";\nexport { useTableUrlState, readTableUrlState } from \"./components/use-table-state\";\nexport type {\n TableUrlState,\n TableUrlSync,\n TableUrlStateProps,\n UseTableUrlStateOptions,\n UseTableUrlStateReturn,\n} from \"./components/use-table-state\";\n"],"mappings":";AAKA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,WAAW,sCAAsC;AAY1D,cAAc;AACd,SAAS,kBAAkB,yBAAyB;","names":[]}
@@ -1,2 +1,2 @@
1
1
  import 'react';
2
- export { D as DEFAULT_ATTACHMENT_ACCEPT, a as DEFAULT_FEEDBACK_ATTACHMENT_LABELS, c as DEFAULT_MAX_ATTACHMENTS, d as DEFAULT_MAX_ATTACHMENT_BYTES, F as FeedbackAttachmentError, e as FeedbackAttachmentField, f as FeedbackAttachmentFieldLabels, g as FeedbackAttachmentFieldMultipleProps, h as FeedbackAttachmentFieldProps, i as FeedbackAttachmentFieldSingleProps, t as pastedName } from '../feedback-attachment-WFiXJ8We.js';
2
+ export { D as DEFAULT_ATTACHMENT_ACCEPT, a as DEFAULT_FEEDBACK_ATTACHMENT_LABELS, c as DEFAULT_MAX_ATTACHMENTS, d as DEFAULT_MAX_ATTACHMENT_BYTES, F as FeedbackAttachmentError, e as FeedbackAttachmentField, f as FeedbackAttachmentFieldLabels, g as FeedbackAttachmentFieldMultipleProps, h as FeedbackAttachmentFieldProps, i as FeedbackAttachmentFieldRefsProps, j as FeedbackAttachmentFieldSingleProps, l as FeedbackAttachmentRef, m as FeedbackAttachmentRefsError, w as pastedName } from '../feedback-attachment-NhUm7Zga.js';
@@ -2,8 +2,8 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { useEffect, useLayoutEffect, useRef, useState } from "react";
5
- import { Camera, FileText, Paperclip, X } from "lucide-react";
6
- import { Button } from "../components/ui.js";
5
+ import { Camera, FileText, Image as ImageIcon, Paperclip, X } from "lucide-react";
6
+ import { Button, Spinner } from "../components/ui.js";
7
7
  import { useKitFileLabels, useKitLabels } from "../i18n/kit-labels.js";
8
8
  const DEFAULT_ATTACHMENT_ACCEPT = ["image/png", "image/jpeg", "image/webp", "image/gif"];
9
9
  const DEFAULT_MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
@@ -16,9 +16,11 @@ const DEFAULT_FEEDBACK_ATTACHMENT_LABELS = {
16
16
  attachmentList: "Attachments",
17
17
  attachmentScreenshot: "Screenshot",
18
18
  attachmentRemoveFile: (name) => `Remove ${name}`,
19
- attachmentLimit: (max) => `Up to ${max} ${max === 1 ? "attachment" : "attachments"} \u2014 remove one to add another.`
19
+ attachmentLimit: (max) => `Up to ${max} ${max === 1 ? "attachment" : "attachments"} \u2014 remove one to add another.`,
20
+ attachmentUploading: "Uploading\u2026"
20
21
  };
21
22
  function FeedbackAttachmentField(props) {
23
+ if (props.refs) return /* @__PURE__ */ jsx(RefsField, { ...props });
22
24
  return props.multiple ? /* @__PURE__ */ jsx(MultipleField, { ...props }) : /* @__PURE__ */ jsx(SingleField, { ...props });
23
25
  }
24
26
  function SingleField({
@@ -283,6 +285,211 @@ function MultipleField({
283
285
  )
284
286
  ] });
285
287
  }
288
+ let nextUploadId = 0;
289
+ function RefsField({
290
+ value,
291
+ onChange,
292
+ onUpload,
293
+ onRemove,
294
+ onUploadingChange,
295
+ max = DEFAULT_MAX_ATTACHMENTS,
296
+ labels: labelsProp,
297
+ accept = DEFAULT_ATTACHMENT_ACCEPT,
298
+ maxBytes = DEFAULT_MAX_ATTACHMENT_BYTES,
299
+ onError,
300
+ onCaptureScreenshot,
301
+ documentPaste = false,
302
+ pasteFrom,
303
+ className
304
+ }) {
305
+ const rootRef = useRef(null);
306
+ const fileInputRef = useRef(null);
307
+ const fileText = useKitFileLabels();
308
+ const text = useKitLabels("feedbackAttachment", DEFAULT_FEEDBACK_ATTACHMENT_LABELS, labelsProp);
309
+ const removeLabel = text.attachmentRemoveFile ?? DEFAULT_FEEDBACK_ATTACHMENT_LABELS.attachmentRemoveFile;
310
+ const limitLabel = text.attachmentLimit ?? DEFAULT_FEEDBACK_ATTACHMENT_LABELS.attachmentLimit;
311
+ const uploadingLabel = text.attachmentUploading ?? DEFAULT_FEEDBACK_ATTACHMENT_LABELS.attachmentUploading;
312
+ const latest = useRef(value);
313
+ useLayoutEffect(() => {
314
+ latest.current = value;
315
+ });
316
+ const commit = (next) => {
317
+ latest.current = next;
318
+ onChange(next);
319
+ };
320
+ const [uploads, setUploads] = useState([]);
321
+ const inFlight = useRef([]);
322
+ const mounted = useRef(true);
323
+ useEffect(() => {
324
+ mounted.current = true;
325
+ return () => {
326
+ mounted.current = false;
327
+ };
328
+ }, []);
329
+ const uploadingChange = useRef(onUploadingChange);
330
+ useEffect(() => {
331
+ uploadingChange.current = onUploadingChange;
332
+ });
333
+ const room = Math.max(0, max - value.length - uploads.length);
334
+ const start = (file) => {
335
+ const upload = { id: nextUploadId++, file };
336
+ inFlight.current = [...inFlight.current, upload];
337
+ if (inFlight.current.length === 1) uploadingChange.current?.(true);
338
+ setUploads(inFlight.current);
339
+ const settle = () => {
340
+ inFlight.current = inFlight.current.filter((u) => u.id !== upload.id);
341
+ if (!mounted.current) return;
342
+ setUploads(inFlight.current);
343
+ if (inFlight.current.length === 0) uploadingChange.current?.(false);
344
+ };
345
+ let answer;
346
+ try {
347
+ answer = Promise.resolve(onUpload(file));
348
+ } catch (error) {
349
+ answer = Promise.reject(error);
350
+ }
351
+ answer.then(
352
+ (ref) => {
353
+ settle();
354
+ if (mounted.current) commit([...latest.current, ref]);
355
+ },
356
+ (error) => {
357
+ settle();
358
+ if (mounted.current) onError?.("upload", error);
359
+ }
360
+ );
361
+ };
362
+ const add = (incoming, pasted = false) => {
363
+ let space = Math.max(0, max - latest.current.length - inFlight.current.length);
364
+ const taken = /* @__PURE__ */ new Set([...latest.current.map((r) => r.name), ...inFlight.current.map((u) => u.file.name)]);
365
+ let dropped = false;
366
+ for (const raw of incoming) {
367
+ const problem = rejection(raw, accept, maxBytes);
368
+ if (problem) {
369
+ onError?.(problem);
370
+ continue;
371
+ }
372
+ if (space === 0) {
373
+ dropped = true;
374
+ continue;
375
+ }
376
+ const file = pasted ? renamed(raw, uniqueName(pastedName(raw.type), taken)) : raw;
377
+ taken.add(file.name);
378
+ space -= 1;
379
+ start(file);
380
+ }
381
+ if (dropped) onError?.("count");
382
+ };
383
+ const onPaste = usePaste((images) => add(images, true), documentPaste, pasteFrom);
384
+ const pendingFocus = useRef(null);
385
+ useEffect(() => {
386
+ const index = pendingFocus.current;
387
+ if (index === null) return;
388
+ pendingFocus.current = null;
389
+ const root = rootRef.current;
390
+ if (!root) return;
391
+ const removes = root.querySelectorAll("[data-attachment-remove]");
392
+ const target = removes[index] ?? root.querySelector("[data-attachment-action]") ?? removes[index - 1];
393
+ target?.focus();
394
+ }, [value]);
395
+ const remove = (key, index) => {
396
+ pendingFocus.current = index;
397
+ commit(latest.current.filter((r) => r.key !== key));
398
+ onRemove?.(key);
399
+ };
400
+ const hasChips = value.length > 0 || uploads.length > 0;
401
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative space-y-2", className), onPaste, children: [
402
+ /* @__PURE__ */ jsx(Heading, { text: labelsProp?.attachment, className: "mb-0" }),
403
+ hasChips && /* @__PURE__ */ jsxs("ul", { "aria-label": text.attachmentList, className: "flex flex-col gap-2", children: [
404
+ value.map((ref, index) => /* @__PURE__ */ jsxs(
405
+ "li",
406
+ {
407
+ className: "flex min-w-0 items-center gap-2 rounded-md border border-[var(--border)] bg-[var(--bg-surface)] p-1",
408
+ children: [
409
+ /* @__PURE__ */ jsx(RefGlyph, { type: ref.type }),
410
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
411
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm text-[var(--text-secondary)]", children: ref.name }),
412
+ ref.size !== void 0 && /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-[var(--text-muted)]", children: fileText.size(ref.size) })
413
+ ] }),
414
+ /* @__PURE__ */ jsx(
415
+ "button",
416
+ {
417
+ type: "button",
418
+ "data-attachment-remove": "",
419
+ onClick: () => remove(ref.key, index),
420
+ "aria-label": removeLabel(ref.name),
421
+ className: "shrink-0 rounded p-1.5 text-[var(--text-placeholder)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)]",
422
+ children: /* @__PURE__ */ jsx(X, { className: "size-4" })
423
+ }
424
+ )
425
+ ]
426
+ },
427
+ `ref:${ref.key}`
428
+ )),
429
+ uploads.map((upload) => /* @__PURE__ */ jsxs(
430
+ "li",
431
+ {
432
+ "aria-busy": "true",
433
+ "data-attachment-uploading": "",
434
+ className: "flex min-w-0 items-center gap-2 rounded-md border border-dashed border-[var(--border)] bg-[var(--bg-surface)] p-1",
435
+ children: [
436
+ /* @__PURE__ */ jsx("span", { className: "flex size-12 shrink-0 items-center justify-center rounded border border-[var(--border)] bg-[var(--bg-surface-2)] text-[var(--text-placeholder)]", children: /* @__PURE__ */ jsx(Spinner, { label: null, className: "size-5" }) }),
437
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
438
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm text-[var(--text-secondary)]", children: upload.file.name }),
439
+ /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-[var(--text-muted)]", children: uploadingLabel })
440
+ ] })
441
+ ]
442
+ },
443
+ `upload:${upload.id}`
444
+ ))
445
+ ] }),
446
+ room > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
447
+ /* @__PURE__ */ jsxs(
448
+ Button,
449
+ {
450
+ type: "button",
451
+ variant: "secondary",
452
+ "data-attachment-action": "",
453
+ onClick: () => fileInputRef.current?.click(),
454
+ children: [
455
+ /* @__PURE__ */ jsx(Paperclip, { className: "size-4" }),
456
+ " ",
457
+ text.attachmentAdd
458
+ ]
459
+ }
460
+ ),
461
+ onCaptureScreenshot && /* @__PURE__ */ jsx(
462
+ CaptureButton,
463
+ {
464
+ capture: onCaptureScreenshot,
465
+ onFile: (file) => add([file]),
466
+ label: text.attachmentCapture,
467
+ "data-attachment-action": ""
468
+ }
469
+ )
470
+ ] }),
471
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--text-muted)]", children: room > 0 ? text.attachmentPaste : limitLabel(max) }),
472
+ /* @__PURE__ */ jsx(
473
+ "input",
474
+ {
475
+ ref: fileInputRef,
476
+ type: "file",
477
+ multiple: room > 1,
478
+ accept: accept.join(","),
479
+ className: "sr-only",
480
+ tabIndex: -1,
481
+ "aria-hidden": true,
482
+ onChange: (e) => {
483
+ add(Array.from(e.target.files ?? []));
484
+ e.target.value = "";
485
+ }
486
+ }
487
+ )
488
+ ] });
489
+ }
490
+ function RefGlyph({ type }) {
491
+ return /* @__PURE__ */ jsx("span", { className: "flex size-12 shrink-0 items-center justify-center rounded border border-[var(--border)] bg-[var(--bg-surface-2)] text-[var(--text-placeholder)]", children: type?.startsWith("image/") ? /* @__PURE__ */ jsx(ImageIcon, { "aria-hidden": true, className: "size-6" }) : /* @__PURE__ */ jsx(FileText, { "aria-hidden": true, className: "size-6" }) });
492
+ }
286
493
  function Heading({ text, className }) {
287
494
  if (!text) return null;
288
495
  return /* @__PURE__ */ jsx("div", { className: cn("mb-1 text-xs font-medium uppercase tracking-wide text-[var(--text-muted)]", className), children: text });