@ahrowe/ui 0.31.0 → 0.32.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 (118) hide show
  1. package/dist/esm/common/actionButtons/actionButtons.mjs +1 -1
  2. package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -1
  3. package/dist/esm/common/alert/alert.mjs +1 -1
  4. package/dist/esm/common/alert/alert.mjs.map +1 -1
  5. package/dist/esm/common/alert/alert.types.mjs.map +1 -1
  6. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  7. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  8. package/dist/esm/common/carousel/carousel.mjs +1 -1
  9. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  10. package/dist/esm/common/chip/chip.mjs +1 -1
  11. package/dist/esm/common/chip/chip.mjs.map +1 -1
  12. package/dist/esm/common/chip/chip.types.mjs.map +1 -1
  13. package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
  14. package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
  15. package/dist/esm/common/configProvider/useLabels.mjs +2 -0
  16. package/dist/esm/common/configProvider/useLabels.mjs.map +1 -0
  17. package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
  18. package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
  19. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
  20. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  21. package/dist/esm/common/emptyState/emptyState.mjs +1 -1
  22. package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
  23. package/dist/esm/common/input/input.mjs +1 -1
  24. package/dist/esm/common/input/input.mjs.map +1 -1
  25. package/dist/esm/common/input/input.types.mjs.map +1 -1
  26. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  27. package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
  28. package/dist/esm/common/modal/modal.mjs +1 -1
  29. package/dist/esm/common/modal/modal.mjs.map +1 -1
  30. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  31. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  32. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  33. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  34. package/dist/esm/common/otpInput/otpInput.mjs +1 -1
  35. package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
  36. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  37. package/dist/esm/common/pagination/pagination.mjs +1 -1
  38. package/dist/esm/common/pagination/pagination.mjs.map +1 -1
  39. package/dist/esm/common/roomDrawer/roomDrawer.mjs +1 -1
  40. package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
  41. package/dist/esm/common/splitButton/splitButton.mjs +1 -1
  42. package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
  43. package/dist/esm/common/timer/timer.mjs +1 -1
  44. package/dist/esm/common/timer/timer.mjs.map +1 -1
  45. package/dist/esm/common/toast/toast.mjs +1 -1
  46. package/dist/esm/common/toast/toast.mjs.map +1 -1
  47. package/dist/esm/common/toast/toastProvider.mjs +1 -1
  48. package/dist/esm/common/toast/toastProvider.mjs.map +1 -1
  49. package/dist/esm/common/tree/tree.mjs +1 -1
  50. package/dist/esm/common/tree/tree.mjs.map +1 -1
  51. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  52. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  53. package/dist/esm/common/virtualList/virtualListHeader.mjs +1 -1
  54. package/dist/esm/common/virtualList/virtualListHeader.mjs.map +1 -1
  55. package/dist/esm/index.mjs +1 -1
  56. package/dist/index.cjs +3 -3
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/types/common/actionButtons/actionButtons.types.d.ts +9 -2
  59. package/dist/types/common/alert/alert.types.d.ts +7 -0
  60. package/dist/types/common/breadcrumb/breadcrumb.types.d.ts +7 -0
  61. package/dist/types/common/carousel/carousel.types.d.ts +13 -0
  62. package/dist/types/common/chip/chip.types.d.ts +7 -1
  63. package/dist/types/common/colorPicker/colorPicker.d.ts +1 -1
  64. package/dist/types/common/colorPicker/colorPicker.types.d.ts +7 -0
  65. package/dist/types/common/configProvider/configProvider.types.d.ts +22 -1
  66. package/dist/types/common/configProvider/index.d.ts +1 -0
  67. package/dist/types/common/configProvider/useLabels.d.ts +22 -0
  68. package/dist/types/common/confirmModal/confirmModal.types.d.ts +9 -2
  69. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +1 -13
  70. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +20 -0
  71. package/dist/types/common/datePicker/datePicker.d.ts +1 -22
  72. package/dist/types/common/datePicker/datePicker.types.d.ts +51 -0
  73. package/dist/types/common/datePicker/index.d.ts +1 -0
  74. package/dist/types/common/emptyState/emptyState.d.ts +1 -1
  75. package/dist/types/common/emptyState/emptyState.types.d.ts +7 -0
  76. package/dist/types/common/input/input.types.d.ts +13 -0
  77. package/dist/types/common/klipyPicker/klipyPicker.d.ts +1 -1
  78. package/dist/types/common/klipyPicker/klipyPicker.types.d.ts +7 -0
  79. package/dist/types/common/modal/modal.types.d.ts +7 -0
  80. package/dist/types/common/multiSelect/multiSelect.types.d.ts +13 -6
  81. package/dist/types/common/numberInput/numberInput.types.d.ts +9 -2
  82. package/dist/types/common/otpInput/otpInput.types.d.ts +9 -0
  83. package/dist/types/common/pagination/pagination.types.d.ts +15 -0
  84. package/dist/types/common/roomDrawer/roomDrawer.types.d.ts +6 -0
  85. package/dist/types/common/splitButton/splitButton.types.d.ts +7 -0
  86. package/dist/types/common/timer/timer.types.d.ts +7 -0
  87. package/dist/types/common/toast/toast.d.ts +4 -2
  88. package/dist/types/common/toast/toast.types.d.ts +11 -1
  89. package/dist/types/common/toast/toastProvider.d.ts +1 -1
  90. package/dist/types/common/tree/tree.types.d.ts +7 -2
  91. package/dist/types/common/virtualList/virtualList.types.d.ts +15 -6
  92. package/dist/types/common/virtualList/virtualListHeader.d.ts +3 -3
  93. package/docs/ActionButtons.md +7 -6
  94. package/docs/Alert.md +2 -0
  95. package/docs/Breadcrumb.md +2 -0
  96. package/docs/Carousel.md +2 -0
  97. package/docs/Chip.md +3 -1
  98. package/docs/ColorPicker.md +2 -0
  99. package/docs/ConfigProvider.md +23 -0
  100. package/docs/ConfirmModal.md +7 -5
  101. package/docs/DatePicker.md +2 -1
  102. package/docs/EmptyState.md +2 -0
  103. package/docs/FormValidatorGroup.md +1 -1
  104. package/docs/Input.md +2 -0
  105. package/docs/KlipyPicker.md +2 -0
  106. package/docs/Modal.md +2 -0
  107. package/docs/MultiSelect.md +7 -5
  108. package/docs/NumberInput.md +4 -2
  109. package/docs/OtpInput.md +2 -0
  110. package/docs/Pagination.md +2 -0
  111. package/docs/RoomDrawer.md +2 -0
  112. package/docs/SplitButton.md +2 -0
  113. package/docs/Timer.md +2 -0
  114. package/docs/Toast.md +2 -0
  115. package/docs/Tree.md +3 -1
  116. package/docs/VirtualList.md +3 -2
  117. package/docs/Wizard.md +1 -2
  118. package/package.json +1 -1
@@ -3,6 +3,11 @@ import { SlotClassNames, SlotStyles } from '../types/slots.types';
3
3
  export type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
4
4
  export type ToastType = 'default' | 'info' | 'success' | 'error' | 'warn';
5
5
  export type ToastSlots = 'root' | 'icon' | 'content' | 'closeButton' | 'progressBar';
6
+ /** Text Toast renders of its own, for translating it. */
7
+ export interface ToastLabels {
8
+ /** The dismiss button, read out by screen readers. */
9
+ close?: string;
10
+ }
6
11
  export interface ToastContextConfig {
7
12
  position?: ToastPosition;
8
13
  /** Duration in ms. 0 = persistent. */
@@ -13,6 +18,11 @@ export interface ToastContextConfig {
13
18
  allowStacking?: boolean;
14
19
  /** Pause the auto-dismiss timer while the toast is hovered or focused. */
15
20
  pauseOnHover?: boolean;
21
+ /**
22
+ * Overrides the text a toast renders of its own. Set on `ToastProvider` for
23
+ * the whole app, or per toast through `showToast` options.
24
+ */
25
+ labels?: ToastLabels;
16
26
  }
17
27
  export interface ToastOptions extends ToastContextConfig {
18
28
  type?: ToastType;
@@ -22,7 +32,7 @@ export interface ToastOptions extends ToastContextConfig {
22
32
  export interface ToastProviderProps extends ToastContextConfig {
23
33
  children: ReactNode;
24
34
  }
25
- export interface ToastItem {
35
+ export interface ToastItem extends Pick<ToastOptions, 'labels'> {
26
36
  id: string;
27
37
  content: ReactNode;
28
38
  options: ResolvedToastOptions;
@@ -3,6 +3,6 @@ import { ToastContextConfig } from './toast.types';
3
3
  interface ToastProviderProps extends ToastContextConfig {
4
4
  children: ReactNode;
5
5
  }
6
- declare function ToastProvider({ children, position, duration, showRemainingTime, showCloseButton, allowStacking, pauseOnHover, }: ToastProviderProps): React.JSX.Element;
6
+ declare function ToastProvider({ children, position, duration, showRemainingTime, showCloseButton, allowStacking, pauseOnHover, labels, }: ToastProviderProps): React.JSX.Element;
7
7
  export default ToastProvider;
8
8
  export type { ToastProviderProps };
@@ -25,6 +25,11 @@ export interface FlatTreeNode {
25
25
  posInSet: number;
26
26
  }
27
27
  export type TreeSlots = 'root' | 'node' | 'toggle' | 'icon' | 'label' | 'empty';
28
+ /** Text Tree renders of its own, for translating it. */
29
+ export interface TreeLabels {
30
+ /** Shown when `nodes` is empty (default `Nothing here`). */
31
+ empty?: string;
32
+ }
28
33
  export interface TreeProps extends Omit<HtmlProps<HTMLDivElement>, 'onSelect'> {
29
34
  nodes: TreeNode[];
30
35
  /** Controlled set of expanded branch keys. Omit for uncontrolled. */
@@ -51,12 +56,12 @@ export interface TreeProps extends Omit<HtmlProps<HTMLDivElement>, 'onSelect'> {
51
56
  height?: number | string;
52
57
  /** Row height used by the windowed renderer before measurement (default `32`). */
53
58
  estimatedRowHeight?: number;
54
- /** Shown when `nodes` is empty (default `'Nothing here'`). */
55
- emptyLabel?: string;
56
59
  disabled?: boolean;
57
60
  'aria-label'?: string;
58
61
  className?: string;
59
62
  style?: CSSProperties;
60
63
  classNames?: SlotClassNames<TreeSlots>;
61
64
  styles?: SlotStyles<TreeSlots>;
65
+ /** Overrides the text Tree renders of its own. Merged per key. */
66
+ labels?: TreeLabels;
62
67
  }
@@ -116,6 +116,19 @@ export interface TreeDropTarget {
116
116
  */
117
117
  position: TreeDropPosition;
118
118
  }
119
+ /** Text VirtualList renders of its own, for translating it. */
120
+ export interface VirtualListLabels {
121
+ /** A row's select checkbox, read out by screen readers. */
122
+ selectRow?: string;
123
+ /** The header's select-all checkbox, read out by screen readers. */
124
+ selectAllRows?: string;
125
+ /** The gear that opens the column menu, read out by screen readers. */
126
+ toggleColumns?: string;
127
+ /** The badge on the gear, given how many columns the user has hidden. */
128
+ columnsHidden?: (count: number) => string;
129
+ /** The entry in the column menu that undoes the user's column widths. */
130
+ resetColumnWidths?: ReactNode;
131
+ }
119
132
  export interface VirtualListProps<T> extends HtmlProps {
120
133
  items: T[];
121
134
  /** Render function for list mode (no columns). Ignored when `columns` is provided. */
@@ -210,12 +223,8 @@ export interface VirtualListProps<T> extends HtmlProps {
210
223
  resizableColumns?: boolean;
211
224
  /** Controlled column widths in px, keyed by column key. */
212
225
  columnWidths?: Record<string, number>;
213
- /**
214
- * Text of the gear-menu entry that undoes the user's column widths (default
215
- * `'Reset column widths'`). The only text this component renders itself, so
216
- * it is also the only one a localised app has to pass.
217
- */
218
- resetColumnWidthsLabel?: ReactNode;
226
+ /** Overrides the text VirtualList renders of its own. Merged per key. */
227
+ labels?: VirtualListLabels;
219
228
  /** Called with the full width map whenever the user resizes or auto-fits a column. */
220
229
  onColumnWidthsChange?: (widths: Record<string, number>) => void;
221
230
  /** Show the gear column-toggle button in the header. Default: true when columns present. */
@@ -2,7 +2,7 @@ import { default as React } from 'react';
2
2
  import { UseColumnsResult } from './useColumns';
3
3
  import { UseColumnResizeResult } from './useColumnResize';
4
4
  import { SlotClassNames, SlotStyles } from '../types/slots.types';
5
- import { VirtualListColumn, VirtualListSlots, VirtualListSort } from './virtualList.types';
5
+ import { VirtualListColumn, VirtualListLabels, VirtualListSlots, VirtualListSort } from './virtualList.types';
6
6
  interface VirtualListHeaderProps<T> {
7
7
  headerRef: React.RefObject<HTMLDivElement | null>;
8
8
  /** Every column, including hidden ones: the toggle menu lists them all. */
@@ -15,7 +15,7 @@ interface VirtualListHeaderProps<T> {
15
15
  allSelected: boolean;
16
16
  someSelected: boolean;
17
17
  onSelectAll: () => void;
18
- resetColumnWidthsLabel: React.ReactNode;
18
+ labels: Required<VirtualListLabels>;
19
19
  classNames?: SlotClassNames<VirtualListSlots>;
20
20
  styles?: SlotStyles<VirtualListSlots>;
21
21
  }
@@ -31,5 +31,5 @@ interface VirtualListHeaderProps<T> {
31
31
  * keys resizes, Alt+Home and Alt+End take the column to its minimum or to its
32
32
  * content width.
33
33
  */
34
- declare function VirtualListHeader<T>({ headerRef, columns, cols, resize, sort, onSort, multiSelect, allSelected, someSelected, onSelectAll, resetColumnWidthsLabel, classNames, styles: slotStyles, }: VirtualListHeaderProps<T>): React.JSX.Element;
34
+ declare function VirtualListHeader<T>({ headerRef, columns, cols, resize, sort, onSort, multiSelect, allSelected, someSelected, onSelectAll, labels, classNames, styles: slotStyles, }: VirtualListHeaderProps<T>): React.JSX.Element;
35
35
  export default VirtualListHeader;
@@ -10,8 +10,7 @@
10
10
  import { ActionButtons, ButtonStyleType } from '@ahrowe/ui';
11
11
 
12
12
  <ActionButtons
13
- submitLabel="Save"
14
- cancelLabel="Discard"
13
+ labels={{ submit: 'Save', cancel: 'Discard' }}
15
14
  onSubmit={handleSave}
16
15
  onClose={handleClose}
17
16
  isSubmitButtonLoading={isSaving}
@@ -19,7 +18,7 @@ import { ActionButtons, ButtonStyleType } from '@ahrowe/ui';
19
18
 
20
19
  // Destructive action
21
20
  <ActionButtons
22
- submitLabel="Delete"
21
+ labels={{ submit: 'Delete' }}
23
22
  submitButtonStyle={ButtonStyleType.Delete}
24
23
  onSubmit={handleDelete}
25
24
  onClose={onClose}
@@ -27,7 +26,7 @@ import { ActionButtons, ButtonStyleType } from '@ahrowe/ui';
27
26
 
28
27
  // Stacked, full-width buttons, a common mobile default
29
28
  <ActionButtons
30
- submitLabel="Save"
29
+ labels={{ submit: 'Save' }}
31
30
  onSubmit={handleSave}
32
31
  onClose={handleClose}
33
32
  stackButtons
@@ -40,8 +39,8 @@ import { ActionButtons, ButtonStyleType } from '@ahrowe/ui';
40
39
  |------|------|-------------|
41
40
  | `onSubmit` | `() => void` | Primary button click |
42
41
  | `onClose` | `() => void` | Secondary button click |
43
- | `submitLabel` | `ReactNode \| string` | Primary button label |
44
- | `cancelLabel` | `ReactNode \| string` | Secondary button label |
42
+ | `labels.submit` | `ReactNode \| string` | Primary button label |
43
+ | `labels.cancel` | `ReactNode \| string` | Secondary button label |
45
44
  | `submitButtonStyle` | `ButtonStyleType` | `Primary` (default), `Delete`, `Default` |
46
45
  | `isSubmitButtonLoading` | `boolean` | Shows spinner on primary button |
47
46
  | `isSubmitButtonDisabled` | `boolean` | |
@@ -53,3 +52,5 @@ import { ActionButtons, ButtonStyleType } from '@ahrowe/ui';
53
52
  | `stackButtons` | `boolean` | Stack the buttons vertically, each stretched to full width (default `false`). A common mobile default, easy to set globally via `ConfigProvider` |
54
53
 
55
54
  **Slots:** `root` `submitButton` `cancelButton`
55
+
56
+ **Labels:** `submit` `cancel` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `ActionButtonsLabels`.
package/docs/Alert.md CHANGED
@@ -65,6 +65,8 @@ import { faRocket } from '@fortawesome/free-solid-svg-icons';
65
65
 
66
66
  **Slots:** `root` `icon` `content` `title` `description` `closeButton`
67
67
 
68
+ **Labels:** `dismiss` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `AlertLabels`.
69
+
68
70
  ## Sizing
69
71
 
70
72
  Every length in an alert is `em`, so the padding, the icon, the close button and the accent bar keep their ratios to the body copy at any base font.
@@ -106,3 +106,5 @@ function Example() {
106
106
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Breadcrumb: { separator: '/' } }}`. See [ConfigProvider.md](ConfigProvider.md).
107
107
 
108
108
  **Slots:** `root` `list` `item` `link` `icon` `separator` `current` `ellipsis` `hiddenList` `hiddenItem`
109
+
110
+ **Labels:** `showHidden` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `BreadcrumbLabels`.
package/docs/Carousel.md CHANGED
@@ -103,3 +103,5 @@ Slides announce themselves as the panel each dot controls, or as "slide 2 of 5"
103
103
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Carousel: { autoPlay: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
104
104
 
105
105
  **Slots:** `root` `track` `slide` `prevButton` `nextButton` `dots` `dot`
106
+
107
+ **Labels:** `previous` `next` `slides` `goToSlide(slide)` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `CarouselLabels`.
package/docs/Chip.md CHANGED
@@ -56,7 +56,7 @@ import { Chip, ChipContainer, ChipStyleType } from '@ahrowe/ui';
56
56
  | `text` | `string` | Chip label |
57
57
  | `styleType` | `ChipStyleType` | Colour variant (default `Default`) |
58
58
  | `thumbnail` | `string` | Avatar image URL |
59
- | `removeLabel` | `string` | Accessible name for the remove button. Default: `'Remove'` |
59
+ | `labels.remove` | `string` | Accessible name for the remove button. Default: `'Remove'` |
60
60
  | `showRemoveIcon` | `boolean` | Show × icon |
61
61
  | `onRemove` | `() => void` | Remove button handler |
62
62
  | `onClick` | `() => void` | Makes chip clickable |
@@ -66,3 +66,5 @@ import { Chip, ChipContainer, ChipStyleType } from '@ahrowe/ui';
66
66
  | Prop | Type | Description |
67
67
  |------|------|-------------|
68
68
  | `inline` | `boolean` | Inline layout (default wraps) |
69
+
70
+ **Labels:** `remove` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `ChipLabels`.
@@ -50,3 +50,5 @@ Parsing uses the browser's own colour engine, which means it needs a DOM with a
50
50
  The inline swatch tracks the theme's text size, since it sits beside a label: `--swatch-size` falls back to `2em`, i.e. 32px at a 16px base, and the gap, the hex overlay and the transparency checkerboard scale with it.
51
51
 
52
52
  The picker panel deliberately does not. It is a floating control surface with its own fixed layout — a saturation area, sliders and a hex field — and it holds together at a large base font rather than needing to grow with it.
53
+
54
+ **Labels:** `pickFromScreen` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `ColorPickerLabels`.
@@ -114,3 +114,26 @@ Each entry is a `Partial<...Props>`, so any of that component's props can be def
114
114
  `Textarea`, `NumberInput`, and `DatePicker` are built on top of `Input`, so they **also** inherit `Input` defaults for the props they forward to it. Their own component-keyed defaults take precedence for props they handle themselves. Example: with `Input: { alwaysFloatLabel: true }` set, every `Textarea` / `NumberInput` / `DatePicker` floats its label too, without needing a separate entry.
115
115
 
116
116
  The `ComponentDefaults` type is the source of truth for which keys are currently supported — more components adopt it over time.
117
+
118
+ ## Translating the components
119
+
120
+ Every string a component renders of its own is set through its `labels` prop, and a `ConfigProvider` sets them for the whole app at once:
121
+
122
+ ```tsx
123
+ <ConfigProvider
124
+ defaultProps={{
125
+ Alert: { labels: { dismiss: 'Schließen' } },
126
+ Modal: { labels: { close: 'Schließen' } },
127
+ Pagination: { labels: { goToPage: (page) => `Zu Seite ${page}` } },
128
+ VirtualList: { labels: { selectRow: 'Zeile auswählen', selectAllRows: 'Alle Zeilen auswählen' } },
129
+ }}
130
+ >
131
+ <App />
132
+ </ConfigProvider>
133
+ ```
134
+
135
+ **Labels merge per key**, unlike every other default here. An instance that overrides one string keeps the provider's translations for the rest, so `<Alert labels={{ dismiss: 'Weg damit' }} />` under the provider above does not lose anything else Alert might have been given. Anything the component does not produce itself, a `title`, a column `label`, a button's children, is already yours and never appears in `labels`.
136
+
137
+ `ColorPicker` and `VirtualList` appear in `ComponentDefaults` with their labels only: the first is configured elsewhere, the second has generic props that a per-key default map cannot express. `Toast` is not there at all, because `ToastProvider` is already its app-wide configuration and carries `labels` itself.
138
+
139
+ Each component's doc lists its own keys under **Labels:**.
@@ -38,9 +38,9 @@ const [isOpen, setIsOpen] = useState(false);
38
38
  | `content` | `ReactNode` | Dialog body |
39
39
  | `onConfirm` | `() => void \| Promise<void>` | Called when user confirms |
40
40
  | `onClose` | `(didSubmit: boolean) => void` | Called on both confirm and cancel |
41
- | `submitLabel` | `string` | Confirm button label (default `'Confirm'`) |
41
+ | `labels.submit` | `string` | Confirm button label (default `'Confirm'`) |
42
42
  | `isDelete` | `boolean` | Render the confirm button with the destructive (delete) style |
43
- | `actionButtonsProps` | `ActionButtonsProps` | Overrides passed through to the underlying `ActionButtons` (wins over `submitLabel` / `isDelete`) |
43
+ | `actionButtonsProps` | `ActionButtonsProps` | Overrides passed through to the underlying `ActionButtons` (wins over `labels.submit` / `isDelete`) |
44
44
  | `children` | `ReactNode` | Alternative to `content` prop |
45
45
 
46
46
  **Destructive action:**
@@ -51,16 +51,18 @@ const [isOpen, setIsOpen] = useState(false);
51
51
  title="Delete item?"
52
52
  content="This action cannot be undone."
53
53
  isDelete
54
- submitLabel="Delete"
54
+ labels={{ submit: 'Delete' }}
55
55
  onConfirm={async () => { await deleteItem(); }}
56
56
  onClose={() => setIsOpen(false)}
57
57
  />
58
58
  ```
59
59
 
60
- **Global defaults:** `ConfirmModal` supports `ConfigProvider` — set a default `submitLabel` (or any other prop) app-wide:
60
+ **Global defaults:** `ConfirmModal` supports `ConfigProvider` — set a default `labels.submit` (or any other prop) app-wide:
61
61
 
62
62
  ```tsx
63
- <ConfigProvider defaultProps={{ ConfirmModal: { submitLabel: 'OK' } }}>
63
+ <ConfigProvider defaultProps={{ ConfirmModal: { labels: { submit: 'OK' } } }}>
64
64
  <App />
65
65
  </ConfigProvider>
66
66
  ```
67
+
68
+ **Labels:** `submit` `cancel` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `ConfirmModalLabels`.
@@ -6,7 +6,8 @@
6
6
 
7
7
  **Keyboard:** the day grid uses a roving tab stop (the selected day, or today, or the 1st — one Tab reaches it, not every day individually); arrow keys move by day (`←`/`→`) or by week (`↑`/`↓`), crossing into the adjacent month automatically when they run past the edge, and Enter/Space selects the focused day.
8
8
 
9
- **Import:** `import { DatePicker } from '@ahrowe/ui'`
9
+ **Import:** `import { DatePicker } from '@ahrowe/ui'`
10
+ **Types:** `import type { DatePickerProps } from '@ahrowe/ui'`
10
11
 
11
12
  ```tsx
12
13
  import { DatePicker, FormValidator } from '@ahrowe/ui';
@@ -28,3 +28,5 @@ import { faInbox } from '@fortawesome/free-solid-svg-icons';
28
28
  | `icon` | `IconDefinition \| ReactElement` | Icon shown above the message — FontAwesome icon or any React element |
29
29
  | `children` | `ReactNode` | Message body (defaults to `"No entries available"`) |
30
30
  | `className` | `string` | Root element class |
31
+
32
+ **Labels:** `empty` — the text this component renders of its own. Pass `labels` to override it, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `EmptyStateLabels`.
@@ -38,7 +38,7 @@ function ProfileForm({ user, onSaved }) {
38
38
  <Input label="Name" formValidator={form.group.name} />
39
39
  <Input label="Email" type={InputType.Email} formValidator={form.group.email} />
40
40
  <ActionButtons
41
- submitLabel="Save"
41
+ labels={{ submit: 'Save' }}
42
42
  onSubmit={form.submit}
43
43
  isSubmitButtonLoading={form.isSubmitting}
44
44
  isSubmitButtonDisabled={!form.isDirty}
package/docs/Input.md CHANGED
@@ -125,6 +125,8 @@ The stored value is the formatted one, spaces included, so strip them before a l
125
125
 
126
126
  **Slots:** `label` `container` `input` `suffix` `upperRightLabel` `fieldset`
127
127
 
128
+ **Labels:** `clear` `clearSearch` `showPassword` `hidePassword` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `InputLabels`.
129
+
128
130
  ## Browser autofill
129
131
 
130
132
  `autoComplete` is the plain HTML attribute and is passed straight through — use `'one-time-code'`, `'new-password'`, `'street-address'` and the rest as you would on a bare `<input>`. Input does **not** set it: autofill and password managers are usability and accessibility features, and a plain field has no suggestion list of its own for them to collide with.
@@ -41,3 +41,5 @@ import { KlipyPicker } from '@ahrowe/ui';
41
41
  | `selected` | `string \| null` | Currently selected GIF id (for visual highlight) |
42
42
  | `onSelect` | `(preview: KlipyResult \| null) => void \| Promise<void>` | Fires when a GIF is picked; `null` when cleared |
43
43
  | `className` | `string` | Root element class |
44
+
45
+ **Labels:** `search` — the text this component renders of its own. Pass `labels` to override it, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `KlipyPickerLabels`.
package/docs/Modal.md CHANGED
@@ -71,3 +71,5 @@ A sheet-presented Modal takes 90% of the screen height rather than the 70% a men
71
71
  The panel also takes the full native `div` attribute set (`id`, `role`, `aria-*`, `data-*`, …). Pass `aria-label` when using `hideHeader`, since there is then no title to label the dialog with.
72
72
 
73
73
  **Slots:** `container` `backdrop` `modal` `header` `title` `closeButton` `body`
74
+
75
+ **Labels:** `close` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `ModalLabels`.
@@ -28,10 +28,10 @@ const [value, setValue] = useState<MultiSelectValue[]>([]);
28
28
  <MultiSelect items={items} defaultValue={['apple']} onChange={(value) => console.log(value)} />
29
29
 
30
30
  // Searchable, for a list too long to scan
31
- <MultiSelect items={countries} searchable searchPlaceholder="Filter countries…" />
31
+ <MultiSelect items={countries} searchable labels={{ searchPlaceholder: 'Filter countries…' }} />
32
32
 
33
33
  // Tag entry: type a value that isn't in `items` and pick the "add" row
34
- <MultiSelect items={commonTags} allowCustomValues createLabel={(value) => `Neu: ${value}`} />
34
+ <MultiSelect items={commonTags} allowCustomValues labels={{ create: (value) => `Neu: ${value }}`} />
35
35
 
36
36
  // Cap the selection — unselected options disable once the cap is reached
37
37
  <MultiSelect items={items} maxSelected={3} />
@@ -72,9 +72,9 @@ import { Presentation } from '@ahrowe/ui';
72
72
  | `placeholder` | `string` | Shown while nothing is selected. With a `label`, it fades in only after the label has finished floating clear |
73
73
  | `searchable` | `boolean` | Show a search box in the panel (default `false`) |
74
74
  | `allowCustomValues` | `boolean` | Let the user add a value not in `items`. Implies `searchable` |
75
- | `createLabel` | `(value: string) => string` | Label for the add row (default `Add "…"`) |
76
- | `searchPlaceholder` | `string` | Placeholder for that box (default `'Search…'`) |
77
- | `emptyLabel` | `string` | Shown when nothing matches (default `'No matches'`) |
75
+ | `labels.create` | `(value: string) => string` | Label for the add row (default `Add "…"`) |
76
+ | `labels.searchPlaceholder` | `string` | Placeholder for that box (default `'Search…'`) |
77
+ | `labels.empty` | `string` | Shown when nothing matches (default `'No matches'`) |
78
78
  | `maxSelected` | `number` | Cap the selection; unselected options disable at the cap |
79
79
  | `clearable` | `boolean` | Show the clear-all button (default `true`) |
80
80
  | `disabled` | `boolean` | Dims the field and blocks interaction |
@@ -98,3 +98,5 @@ import { Presentation } from '@ahrowe/ui';
98
98
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ MultiSelect: { searchable: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
99
99
 
100
100
  **Slots:** `root` `label` `fieldset` `control` `values` `chip` `placeholder` `clearButton` `icon` `panel` `search` `options` `option` `optionCheck` `optionLabel` `empty`
101
+
102
+ **Labels:** `clearSelection` `create(value)` `searchPlaceholder` `empty` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `MultiSelectLabels`.
@@ -74,8 +74,8 @@ const priceValidator = new FormValidator<number | undefined>(undefined, [Validat
74
74
  | `min` | `number` | Lower bound — see the note below |
75
75
  | `max` | `number` | Upper bound — see the note below |
76
76
  | `arrowsLayout` | `'auto' \| 'stacked' \| 'split'` | Stepper layout. Default: `'auto'` |
77
- | `increaseLabel` | `string` | Accessible name for the increase button. Default: `'Increase'` |
78
- | `decreaseLabel` | `string` | Accessible name for the decrease button. Default: `'Decrease'` |
77
+ | `labels.increase` | `string` | Accessible name for the increase button. Default: `'Increase'` |
78
+ | `labels.decrease` | `string` | Accessible name for the decrease button. Default: `'Decrease'` |
79
79
 
80
80
  **Steppers (`showArrows`):** two layouts, picked by `arrowsLayout`:
81
81
 
@@ -124,3 +124,5 @@ const qty = new FormValidator<number | undefined>(undefined, [inRange(10, 100)])
124
124
  ```
125
125
 
126
126
  **Mobile keyboard layout:** shows the numeric on-screen keyboard automatically (`inputMode="numeric"` when `decimalScale={0}`, `"decimal"` otherwise, so a decimal separator key is available whenever fractional values are allowed). Pass `inputMode` directly to override.
127
+
128
+ **Labels:** `increase` `decrease` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `NumberInputLabels`.
package/docs/OtpInput.md CHANGED
@@ -91,6 +91,8 @@ const codeValidator = new FormValidator('', [Validators.required(), Validators.m
91
91
 
92
92
  **Slots:** `root` `label` `inputs` `input` `separator`
93
93
 
94
+ **Labels:** `field` `digit(position, length)` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `OtpInputLabels`.
95
+
94
96
  ## Sizing
95
97
 
96
98
  The code boxes, the digit inside them, the gaps and the separator all scale with the theme's text, so the field stays in proportion with its label.
@@ -70,3 +70,5 @@ const [page, setPage] = useState(1);
70
70
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Pagination: { showEdges: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
71
71
 
72
72
  **Slots:** `root` `item` `control` `ellipsis`
73
+
74
+ **Labels:** `goToPage(page)` `first` `previous` `next` `last` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `PaginationLabels`.
@@ -373,3 +373,5 @@ The previous `RoomDrawer` had no data contract at all: `RoomDrawerProps` was `{
373
373
  - Removing a corner was a double-click, which was undiscoverable and impossible on touch. Select it and press `Delete` instead.
374
374
 
375
375
  **Slots:** `root` `toolbar` `toolButton` `toolIcon` `viewControls` `viewButton` `zoomLabel` `canvasWrapper` `canvas` `grid` `rooms` `roomFill` `roomLabel` `walls` `wallBody` `openings` `opening` `overlay` `measureLine` `floorBar` `floorTab` `inspector` `inspectorLabel` `inspectorField` `hint`
376
+
377
+ **Labels:** every string the drawer's own chrome renders, including `tools`, `storeyHeightHint` and `sillHeightHint`. Type: `RoomDrawerLabels`.
@@ -79,3 +79,5 @@ import { ButtonStyleType } from '@ahrowe/ui';
79
79
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ SplitButton: { styleType: ButtonStyleType.Default } }}`. See [ConfigProvider.md](ConfigProvider.md).
80
80
 
81
81
  **Slots:** `root` `primaryButton` `triggerButton` `menu` `menuItem`
82
+
83
+ **Labels:** `moreActions` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `SplitButtonLabels`.
package/docs/Timer.md CHANGED
@@ -140,6 +140,8 @@ function Example() {
140
140
 
141
141
  **Slots:** `root` `ringWrapper` `ringSvg` `ringTrack` `ringProgress` `ripples` `ripple` `display` `time` `label` `controls` `addButton` `removeButton` `pauseButton` `cancelButton`
142
142
 
143
+ **Labels:** `cancel` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `TimerLabels`.
144
+
143
145
  ## Sizing
144
146
 
145
147
  The ring follows the theme's text size, because the readout inside it does: `--timer-size` falls back to `10em`, i.e. 160px at a 16px base, and the gaps and padding around it are `em` too. The `size` prop still wins where it is given.
package/docs/Toast.md CHANGED
@@ -75,6 +75,8 @@ showToast('Done', {
75
75
 
76
76
  **Slots:** `root` `icon` `content` `closeButton` `progressBar`
77
77
 
78
+ **Labels:** `close` — the dismiss button's screen-reader name. Set it on `ToastProvider` for the whole app (`labels={{ close: 'Schließen' }}`), or per toast through the `showToast` options. Type: `ToastLabels`.
79
+
78
80
  ## Sizing
79
81
 
80
82
  A toast is sized and spaced by its font: the padding, the gap, the body copy, the icon, the close button, the variant accent bar and the progress bar all scale with the theme's text, as does the gap between stacked toasts.
package/docs/Tree.md CHANGED
@@ -62,7 +62,7 @@ import { faWarehouse } from '@fortawesome/free-solid-svg-icons';
62
62
  | `toggleIcon` | `IconDefinition \| ReactElement` | Toggle icon, rotated 90° when open (default a right chevron) |
63
63
  | `height` | `number \| string` | Windows the rows through `VirtualList` at this viewport height |
64
64
  | `estimatedRowHeight` | `number` | Row height for the windowed renderer (default `32`) |
65
- | `emptyLabel` | `string` | Shown when `nodes` is empty (default `'Nothing here'`) |
65
+ | `labels.empty` | `string` | Shown when `nodes` is empty (default `'Nothing here'`) |
66
66
  | `disabled` | `boolean` | Dims the tree and blocks interaction |
67
67
  | `aria-label` | `string` | Accessible name for the tree (default `'Tree'`) |
68
68
 
@@ -93,3 +93,5 @@ Two things change in that mode. Rows must be a uniform height, so size them with
93
93
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Tree: { indent: 30 } }}`. See [ConfigProvider.md](ConfigProvider.md).
94
94
 
95
95
  **Slots:** `root` `node` `toggle` `icon` `label` `empty`
96
+
97
+ **Labels:** `empty` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; keys merge individually. Type: `TreeLabels`.
@@ -144,7 +144,6 @@ const columns: VirtualListColumn<User>[] = [
144
144
  | `resizableColumns` | `boolean` | Let the user drag column edges to resize (see **Column resizing**) |
145
145
  | `columnWidths` | `Record<string, number>` | Controlled column widths in px, keyed by column key |
146
146
  | `onColumnWidthsChange` | `(widths) => void` | Called with the full width map after every resize or auto-fit |
147
- | `resetColumnWidthsLabel` | `ReactNode` | Text of the gear-menu reset entry (default `'Reset column widths'`) |
148
147
  | `showColumnToggle` | `boolean` | Show gear button to show/hide columns (default `true` when columns present) |
149
148
  | `visibleColumnKeys` | `string[]` | Controlled visible column keys |
150
149
  | `onVisibleColumnsChange` | `(keys) => void` | Column visibility change callback |
@@ -199,7 +198,7 @@ const [sort, setSort] = useState<VirtualListSort | null>(null);
199
198
  - **Keyboard**: `Alt` plus the arrow keys on the focused header cell, 10px a press (`Alt+Shift` for 1px). `Alt+Home` goes to the column's minimum, `Alt+End` auto-fits. The strip itself is a mouse affordance and is not a tab stop.
200
199
  - **Undo it**: once anything has been resized, the gear menu grows a **Reset column widths** entry, and the same thing is on the imperative handle as `resetColumnWidths()`. Both also clear the saved widths.
201
200
 
202
- That entry is the only text this component renders of its own, so it is the only string a localised app has to pass: `resetColumnWidthsLabel="Spaltenbreiten zurücksetzen"`. Everything else in the table comes from your columns and cells.
201
+ Its text, like every other string the table renders of its own, is set through `labels` (see below): `labels={{ resetColumnWidths: 'Spaltenbreiten zurücksetzen' }}`.
203
202
 
204
203
  ```tsx
205
204
  <VirtualList
@@ -366,4 +365,6 @@ This needs the list to have a **bounded height** (the default `height="100%"` in
366
365
 
367
366
  **Slots:** `root` `header` `headerCell` `headerSort` `sortIcon` `resizeHandle` `headerToggle` `togglePopover` `toggleItem` `toggleReset` `body` `row` `cell` `selectCell` `activeRow` `loadingIndicator` `dropIndicator` `columnChip`
368
367
 
368
+ **Labels:** `selectRow` `selectAllRows` `toggleColumns` `columnsHidden(count)` `resetColumnWidths` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `VirtualListLabels`.
369
+
369
370
  **In-row popovers:** Rows support inline popover content that overflows the row's bottom edge — e.g. a `Dropdown`, `InputDropdown`, `Tooltip`, or `FloatingMenu` whose list opens below its trigger. All four render their popover through a `BodyEnd` portal and track their trigger's position directly, so they always escape row/cell clipping and paint above the rows below, regardless of focus — no special CSS is needed on the row or cell for this. Cells still clip their own content by default (ellipsis / neighbour-spill guard); that's unaffected. This works in both list mode (`renderRow`) and table mode (`columns`). Stop the row's click handler from firing when interacting with the control (`onClick={(e) => e.stopPropagation()}` on the cell) if the row is also selectable.
package/docs/Wizard.md CHANGED
@@ -26,8 +26,7 @@ const [step, setStep] = useState(0);
26
26
  />
27
27
 
28
28
  <ActionButtons
29
- submitLabel={step < STEPS.length - 1 ? 'Next' : 'Finish'}
30
- cancelLabel={step > 0 ? 'Back' : 'Cancel'}
29
+ labels={{ submit: step < STEPS.length - 1 ? 'Next' : 'Finish', cancel: step > 0 ? 'Back' : 'Cancel' }}
31
30
  onSubmit={() => step < STEPS.length - 1 ? setStep(step + 1) : handleFinish()}
32
31
  onClose={() => step > 0 ? setStep(step - 1) : handleCancel()}
33
32
  />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahrowe/ui",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "A React UI component library with theming, CSS Modules, and TypeScript support",
5
5
  "keywords": [
6
6
  "components",