@eifi1/ui-kit 0.7.1 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/README.md +32 -17
  2. package/dist/chart.d.ts +3 -2
  3. package/dist/components/alert-banner.d.ts +59 -10
  4. package/dist/components/alert-banner.js +114 -8
  5. package/dist/components/alert-banner.js.map +1 -1
  6. package/dist/components/amount-input.d.ts +3 -0
  7. package/dist/components/button-group.d.ts +26 -0
  8. package/dist/components/button-group.js +49 -0
  9. package/dist/components/button-group.js.map +1 -0
  10. package/dist/components/calculator.d.ts +3 -0
  11. package/dist/components/chart-zoom.d.ts +63 -14
  12. package/dist/components/chart-zoom.js +82 -16
  13. package/dist/components/chart-zoom.js.map +1 -1
  14. package/dist/components/chip.d.ts +67 -2
  15. package/dist/components/chip.js +73 -8
  16. package/dist/components/chip.js.map +1 -1
  17. package/dist/components/confirm-dialog.d.ts +120 -0
  18. package/dist/components/confirm-dialog.js +96 -0
  19. package/dist/components/confirm-dialog.js.map +1 -0
  20. package/dist/components/copy-button.d.ts +62 -0
  21. package/dist/components/copy-button.js +95 -0
  22. package/dist/components/copy-button.js.map +1 -0
  23. package/dist/components/data-table-filter-popover.d.ts +1 -1
  24. package/dist/components/data-table-filters.d.ts +1 -1
  25. package/dist/components/data-table-pagination.d.ts +5 -1
  26. package/dist/components/data-table-pagination.js +71 -58
  27. package/dist/components/data-table-pagination.js.map +1 -1
  28. package/dist/components/data-table-sort.d.ts +28 -5
  29. package/dist/components/data-table-sort.js +11 -7
  30. package/dist/components/data-table-sort.js.map +1 -1
  31. package/dist/components/data-table.d.ts +1 -1
  32. package/dist/components/data-table.js +544 -423
  33. package/dist/components/data-table.js.map +1 -1
  34. package/dist/components/date-picker.d.ts +51 -5
  35. package/dist/components/date-picker.js +152 -40
  36. package/dist/components/date-picker.js.map +1 -1
  37. package/dist/components/description-list.d.ts +60 -0
  38. package/dist/components/description-list.js +112 -0
  39. package/dist/components/description-list.js.map +1 -0
  40. package/dist/components/disclosure.d.ts +37 -2
  41. package/dist/components/disclosure.js +14 -5
  42. package/dist/components/disclosure.js.map +1 -1
  43. package/dist/components/facing-pair.d.ts +2 -0
  44. package/dist/components/file-button.d.ts +17 -1
  45. package/dist/components/file-button.js +8 -1
  46. package/dist/components/file-button.js.map +1 -1
  47. package/dist/components/file-dropzone.d.ts +54 -9
  48. package/dist/components/file-dropzone.js +100 -70
  49. package/dist/components/file-dropzone.js.map +1 -1
  50. package/dist/components/floating-panel.d.ts +107 -0
  51. package/dist/components/floating-panel.js +206 -0
  52. package/dist/components/floating-panel.js.map +1 -0
  53. package/dist/components/full-bleed-dialog.d.ts +12 -1
  54. package/dist/components/full-bleed-dialog.js +28 -5
  55. package/dist/components/full-bleed-dialog.js.map +1 -1
  56. package/dist/components/modal.d.ts +6 -2
  57. package/dist/components/modal.js +2 -1
  58. package/dist/components/modal.js.map +1 -1
  59. package/dist/components/number-field.d.ts +3 -0
  60. package/dist/components/number-input.d.ts +3 -0
  61. package/dist/components/numpad-sheet.d.ts +3 -0
  62. package/dist/components/progress-bar.d.ts +54 -0
  63. package/dist/components/progress-bar.js +94 -0
  64. package/dist/components/progress-bar.js.map +1 -0
  65. package/dist/components/scroll-area.d.ts +53 -0
  66. package/dist/components/scroll-area.js +86 -0
  67. package/dist/components/scroll-area.js.map +1 -0
  68. package/dist/components/separator.d.ts +23 -0
  69. package/dist/components/separator.js +24 -0
  70. package/dist/components/separator.js.map +1 -0
  71. package/dist/components/series-chart-ticks.d.ts +34 -1
  72. package/dist/components/series-chart-ticks.js +83 -1
  73. package/dist/components/series-chart-ticks.js.map +1 -1
  74. package/dist/components/series-chart.d.ts +314 -19
  75. package/dist/components/series-chart.js +510 -120
  76. package/dist/components/series-chart.js.map +1 -1
  77. package/dist/components/skeleton.d.ts +36 -0
  78. package/dist/components/skeleton.js +35 -0
  79. package/dist/components/skeleton.js.map +1 -0
  80. package/dist/components/stat-tile.d.ts +60 -6
  81. package/dist/components/stat-tile.js +60 -26
  82. package/dist/components/stat-tile.js.map +1 -1
  83. package/dist/components/table.d.ts +83 -0
  84. package/dist/components/table.js +166 -0
  85. package/dist/components/table.js.map +1 -0
  86. package/dist/components/toggle-legend.d.ts +3 -2
  87. package/dist/components/toggle-legend.js +1 -1
  88. package/dist/components/toggle-legend.js.map +1 -1
  89. package/dist/components/tree-view.d.ts +129 -0
  90. package/dist/components/tree-view.js +376 -0
  91. package/dist/components/tree-view.js.map +1 -0
  92. package/dist/components/treemap.d.ts +9 -2
  93. package/dist/components/treemap.js +6 -2
  94. package/dist/components/treemap.js.map +1 -1
  95. package/dist/components/ui.d.ts +94 -13
  96. package/dist/components/ui.js +111 -29
  97. package/dist/components/ui.js.map +1 -1
  98. package/dist/components/use-table-state.d.ts +1 -1
  99. package/dist/{data-table-filters-noy0Abvi.d.ts → data-table-filters-CF1PXqjQ.d.ts} +73 -3
  100. package/dist/data-table.d.ts +2 -2
  101. package/dist/data-table.js.map +1 -1
  102. package/dist/hooks/use-copy-to-clipboard.d.ts +28 -0
  103. package/dist/hooks/use-copy-to-clipboard.js +81 -0
  104. package/dist/hooks/use-copy-to-clipboard.js.map +1 -0
  105. package/dist/hooks/use-debounce.d.ts +43 -0
  106. package/dist/hooks/use-debounce.js +56 -0
  107. package/dist/hooks/use-debounce.js.map +1 -0
  108. package/dist/hooks/use-file-drop.d.ts +72 -0
  109. package/dist/hooks/use-file-drop.js +57 -0
  110. package/dist/hooks/use-file-drop.js.map +1 -0
  111. package/dist/i18n/defaults.d.ts +3 -0
  112. package/dist/i18n/defaults.js +7 -1
  113. package/dist/i18n/defaults.js.map +1 -1
  114. package/dist/i18n/kit-labels.d.ts +15 -0
  115. package/dist/i18n/kit-labels.js +6 -2
  116. package/dist/i18n/kit-labels.js.map +1 -1
  117. package/dist/i18n/locales/de-CH-informal.d.ts +43 -0
  118. package/dist/i18n/locales/de-CH-informal.js +8 -0
  119. package/dist/i18n/locales/de-CH-informal.js.map +1 -0
  120. package/dist/i18n/locales/de-CH.d.ts +3 -0
  121. package/dist/i18n/locales/de-CH.js +1 -14
  122. package/dist/i18n/locales/de-CH.js.map +1 -1
  123. package/dist/i18n/locales/de-informal.d.ts +64 -0
  124. package/dist/i18n/locales/de-informal.js +37 -0
  125. package/dist/i18n/locales/de-informal.js.map +1 -0
  126. package/dist/i18n/locales/de.d.ts +3 -0
  127. package/dist/i18n/locales/de.js +25 -0
  128. package/dist/i18n/locales/de.js.map +1 -1
  129. package/dist/i18n/locales/es.d.ts +3 -0
  130. package/dist/i18n/locales/es.js +25 -0
  131. package/dist/i18n/locales/es.js.map +1 -1
  132. package/dist/i18n/locales/fr.d.ts +3 -0
  133. package/dist/i18n/locales/fr.js +25 -0
  134. package/dist/i18n/locales/fr.js.map +1 -1
  135. package/dist/i18n/locales/hu.d.ts +3 -0
  136. package/dist/i18n/locales/hu.js +25 -0
  137. package/dist/i18n/locales/hu.js.map +1 -1
  138. package/dist/i18n/locales/it.d.ts +3 -0
  139. package/dist/i18n/locales/it.js +25 -0
  140. package/dist/i18n/locales/it.js.map +1 -1
  141. package/dist/i18n/locales/zh.d.ts +3 -0
  142. package/dist/i18n/locales/zh.js +25 -0
  143. package/dist/i18n/locales/zh.js.map +1 -1
  144. package/dist/i18n/swiss.d.ts +13 -0
  145. package/dist/i18n/swiss.js +19 -0
  146. package/dist/i18n/swiss.js.map +1 -0
  147. package/dist/index.d.ts +25 -10
  148. package/dist/index.js +22 -0
  149. package/dist/index.js.map +1 -1
  150. package/dist/lib/dates.d.ts +37 -1
  151. package/dist/lib/dates.js +19 -0
  152. package/dist/lib/dates.js.map +1 -1
  153. package/dist/search/command-palette.d.ts +15 -1
  154. package/dist/search/command-palette.js +10 -2
  155. package/dist/search/command-palette.js.map +1 -1
  156. package/dist/wizard/stepper-nav.d.ts +35 -2
  157. package/dist/wizard/stepper-nav.js +54 -22
  158. package/dist/wizard/stepper-nav.js.map +1 -1
  159. package/dist/wizard/types.d.ts +107 -5
  160. package/dist/wizard/types.js +2 -1
  161. package/dist/wizard/types.js.map +1 -1
  162. package/dist/wizard/use-wizard.js +141 -21
  163. package/dist/wizard/use-wizard.js.map +1 -1
  164. package/dist/wizard/wizard-summary.d.ts +10 -2
  165. package/dist/wizard/wizard-summary.js +3 -1
  166. package/dist/wizard/wizard-summary.js.map +1 -1
  167. package/dist/wizard.d.ts +4 -1
  168. package/dist/wizard.js.map +1 -1
  169. package/package.json +1 -1
  170. package/src/components/alert-banner.tsx +211 -20
  171. package/src/components/button-group.tsx +75 -0
  172. package/src/components/chart-zoom.tsx +158 -20
  173. package/src/components/chip.tsx +160 -9
  174. package/src/components/confirm-dialog.tsx +242 -0
  175. package/src/components/copy-button.tsx +158 -0
  176. package/src/components/data-table-pagination.tsx +19 -6
  177. package/src/components/data-table-sort.ts +49 -10
  178. package/src/components/data-table.tsx +293 -24
  179. package/src/components/date-picker.tsx +262 -57
  180. package/src/components/description-list.tsx +174 -0
  181. package/src/components/disclosure.tsx +58 -5
  182. package/src/components/file-button.tsx +22 -2
  183. package/src/components/file-dropzone.tsx +198 -100
  184. package/src/components/floating-panel.tsx +341 -0
  185. package/src/components/full-bleed-dialog.tsx +53 -5
  186. package/src/components/modal.tsx +9 -2
  187. package/src/components/progress-bar.tsx +163 -0
  188. package/src/components/scroll-area.tsx +129 -0
  189. package/src/components/separator.tsx +37 -0
  190. package/src/components/series-chart-ticks.ts +135 -0
  191. package/src/components/series-chart.tsx +934 -67
  192. package/src/components/skeleton.tsx +65 -0
  193. package/src/components/stat-tile.tsx +160 -27
  194. package/src/components/table.tsx +263 -0
  195. package/src/components/toggle-legend.tsx +4 -3
  196. package/src/components/tree-view.tsx +589 -0
  197. package/src/components/treemap.tsx +13 -2
  198. package/src/components/ui.tsx +270 -39
  199. package/src/data-table.ts +2 -0
  200. package/src/hooks/use-copy-to-clipboard.ts +122 -0
  201. package/src/hooks/use-debounce.ts +105 -0
  202. package/src/hooks/use-file-drop.ts +123 -0
  203. package/src/i18n/defaults.ts +6 -0
  204. package/src/i18n/kit-labels.tsx +19 -0
  205. package/src/i18n/locales/de-CH-informal.ts +10 -0
  206. package/src/i18n/locales/de-CH.ts +1 -16
  207. package/src/i18n/locales/de-informal.ts +61 -0
  208. package/src/i18n/locales/de.ts +25 -0
  209. package/src/i18n/locales/es.ts +25 -0
  210. package/src/i18n/locales/fr.ts +25 -0
  211. package/src/i18n/locales/hu.ts +25 -0
  212. package/src/i18n/locales/it.ts +25 -0
  213. package/src/i18n/locales/zh.ts +25 -0
  214. package/src/i18n/swiss.ts +25 -0
  215. package/src/index.ts +29 -0
  216. package/src/lib/dates.ts +48 -0
  217. package/src/search/command-palette.tsx +29 -3
  218. package/src/wizard/stepper-nav.tsx +102 -28
  219. package/src/wizard/types.ts +106 -4
  220. package/src/wizard/use-wizard.ts +211 -31
  221. package/src/wizard/wizard-summary.tsx +24 -12
  222. package/src/wizard.ts +3 -2
@@ -0,0 +1,105 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
+
3
+ /**
4
+ * A value that follows `value`, but only once it has stopped changing for `ms`.
5
+ *
6
+ * kastlan asked for the pair in this module because each of its search boxes carried
7
+ * its own copy of the same six lines — a `useEffect` with a `setTimeout` — and two of
8
+ * them forgot the cleanup, so a stale query landed AFTER the fresh one and replaced
9
+ * its results. The cleanup is the whole point of having one implementation.
10
+ *
11
+ * The first render returns `value` itself, not `undefined`: a list filtered by the
12
+ * debounced query must render its initial state immediately, not after `ms`.
13
+ */
14
+ export function useDebounce<T>(value: T, ms: number): T {
15
+ const [debounced, setDebounced] = useState(value);
16
+ useEffect(() => {
17
+ const timer = setTimeout(() => setDebounced(value), ms);
18
+ return () => clearTimeout(timer);
19
+ }, [value, ms]);
20
+ return debounced;
21
+ }
22
+
23
+ export interface DebouncedCallbackOptions {
24
+ /**
25
+ * The longest a call may be held back, however often it is re-triggered. Without
26
+ * it a user who never stops typing never saves; with it, a draft autosave still
27
+ * lands every `maxWait` ms while the typing goes on.
28
+ */
29
+ maxWait?: number;
30
+ }
31
+
32
+ /** The debounced function, plus the two escapes a caller needs around it. */
33
+ export type DebouncedFunction<A extends unknown[]> = ((...args: A) => void) & {
34
+ /** Drop the pending call, if there is one. */
35
+ cancel: () => void;
36
+ /** Run the pending call now, if there is one — e.g. on blur or before navigating
37
+ * away, so the last keystrokes of a form are not lost. */
38
+ flush: () => void;
39
+ /** Whether a call is waiting. */
40
+ pending: () => boolean;
41
+ };
42
+
43
+ /**
44
+ * `fn`, called only once calls have stopped arriving for `ms` — with the arguments
45
+ * of the LAST call.
46
+ *
47
+ * The returned function keeps its identity across renders (so it can sit in an
48
+ * effect's dependency list or be handed to a memoised child) and always calls the
49
+ * LATEST `fn`, so a handler that closes over current state never runs a stale copy.
50
+ * A pending call is cancelled on unmount: a debounced save firing into an unmounted
51
+ * form is the bug kastlan reported, not a feature.
52
+ */
53
+ export function useDebouncedCallback<A extends unknown[]>(
54
+ fn: (...args: A) => void,
55
+ ms: number,
56
+ { maxWait }: DebouncedCallbackOptions = {},
57
+ ): DebouncedFunction<A> {
58
+ const fnRef = useRef(fn);
59
+ // Layout effect, not render-time assignment: a ref written during render is a
60
+ // side effect React may replay or discard. Nothing can call the debounced function
61
+ // between this commit and the layout effect, so it is never one render behind.
62
+ useLayoutEffect(() => {
63
+ fnRef.current = fn;
64
+ });
65
+
66
+ const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
67
+ const maxTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
68
+ const lastArgs = useRef<A | null>(null);
69
+
70
+ const clear = useCallback(() => {
71
+ if (timer.current) clearTimeout(timer.current);
72
+ if (maxTimer.current) clearTimeout(maxTimer.current);
73
+ timer.current = null;
74
+ maxTimer.current = null;
75
+ }, []);
76
+
77
+ const invoke = useCallback(() => {
78
+ const args = lastArgs.current;
79
+ clear();
80
+ lastArgs.current = null;
81
+ if (args) fnRef.current(...args);
82
+ }, [clear]);
83
+
84
+ useEffect(() => clear, [clear]);
85
+
86
+ return useMemo(() => {
87
+ const debounced = ((...args: A) => {
88
+ lastArgs.current = args;
89
+ if (timer.current) clearTimeout(timer.current);
90
+ timer.current = setTimeout(invoke, ms);
91
+ if (maxWait !== undefined && !maxTimer.current) {
92
+ maxTimer.current = setTimeout(invoke, maxWait);
93
+ }
94
+ }) as DebouncedFunction<A>;
95
+ debounced.cancel = () => {
96
+ clear();
97
+ lastArgs.current = null;
98
+ };
99
+ debounced.flush = () => {
100
+ if (lastArgs.current) invoke();
101
+ };
102
+ debounced.pending = () => lastArgs.current !== null;
103
+ return debounced;
104
+ }, [ms, maxWait, invoke, clear]);
105
+ }
@@ -0,0 +1,123 @@
1
+ import { useRef, useState } from "react";
2
+ import type { DragEvent, ReactElement } from "react";
3
+ import { useFilePicker } from "../components/file-button";
4
+ import type { UseFilePickerOptions } from "../components/file-button";
5
+
6
+ /**
7
+ * Turn ANY element into a file drop target — kastlan's ask, for the document list of
8
+ * a booking and the rows of its gantt, which are drop targets without being a
9
+ * `FileDropzone` (a dashed box with a Browse button inside would be the wrong thing
10
+ * to draw over a list).
11
+ *
12
+ * ```tsx
13
+ * const { dropProps, isOver, element } = useFileDrop({ accept: ".pdf", multiple: true,
14
+ * maxSize: 10_000_000, onFiles: attach, onReject: ([r]) => setError(r.message) });
15
+ * return <>{element}<ul {...dropProps} data-drop-over={isOver || undefined}>…</ul></>;
16
+ * ```
17
+ *
18
+ * The screening is `useFilePicker`'s own — `accept` re-checked (a drop ignores the
19
+ * dialog's filter), `maxSize`, `maxFiles`, `isValid`, `onPick` — so a file refused by
20
+ * `FileButton` is refused here in the same words. It comes with `open()` as well, so
21
+ * the same options can also back a "choose a file" menu item beside the drop target.
22
+ */
23
+
24
+ /** `useFilePicker`'s options, minus `capture` (a camera does not take drops). */
25
+ export type UseFileDropOptions = Omit<UseFilePickerOptions, "capture">;
26
+
27
+ /** Spread onto the drop target. Four handlers, nothing else: the element keeps its
28
+ * own role, name and focus behaviour. */
29
+ export interface FileDropProps<E extends Element = Element> {
30
+ onDragEnter: (e: DragEvent<E>) => void;
31
+ onDragOver: (e: DragEvent<E>) => void;
32
+ onDragLeave: (e: DragEvent<E>) => void;
33
+ onDrop: (e: DragEvent<E>) => void;
34
+ }
35
+
36
+ export interface UseFileDropReturn<E extends Element = Element> {
37
+ dropProps: FileDropProps<E>;
38
+ /** A FILE drag is over the target (and it is not `disabled`). Style from this. */
39
+ isOver: boolean;
40
+ /** Open the system picker with the same options — from a click handler only. */
41
+ open: () => void;
42
+ /** Screen and deliver files that arrived another way (a paste). */
43
+ take: (files: ArrayLike<File> | null | undefined) => void;
44
+ /** The live region that speaks a refusal (and the picker's hidden input). Render it
45
+ * once, anywhere; without it a refusal reaches `onReject` but is not announced. */
46
+ element: ReactElement;
47
+ }
48
+
49
+ /** Whether a drag carries files — a dragged link, text or a row of the page does not,
50
+ * and must not light the target up or be swallowed by it. */
51
+ export function dragHasFiles(e: DragEvent): boolean {
52
+ return Array.from(e.dataTransfer?.types ?? []).includes("Files");
53
+ }
54
+
55
+ /**
56
+ * @internal The drag half on its own, shared with `FileDropzone`.
57
+ *
58
+ * `dragenter`/`dragleave` fire for every CHILD the pointer crosses: moving from the
59
+ * target onto a label inside it is a leave of the target followed by an enter of the
60
+ * label, which bubbles. A boolean flipped by each one flickers off and on across
61
+ * every child, and `relatedTarget` — the usual fix — is `null` in Safari's drag
62
+ * events. So this counts: +1 per enter, -1 per leave, over while above zero, and a
63
+ * drop resets it (the drop replaces the leave that would have balanced the enter).
64
+ *
65
+ * A file drag stops propagating here, so a target nested in another (a row inside a
66
+ * page-wide drop area) takes its own drop, and the outer one's count falls back to
67
+ * zero while the pointer is over the inner one — only one of them lights up.
68
+ */
69
+ export function useDragTarget<E extends Element = Element>({
70
+ disabled,
71
+ onDropFiles,
72
+ }: {
73
+ disabled?: boolean;
74
+ onDropFiles: (files: FileList | File[]) => void;
75
+ }): { dropProps: FileDropProps<E>; isOver: boolean } {
76
+ const depth = useRef(0);
77
+ const [over, setOver] = useState(false);
78
+
79
+ const dropProps: FileDropProps<E> = {
80
+ onDragEnter: (e) => {
81
+ if (!dragHasFiles(e)) return;
82
+ e.stopPropagation();
83
+ e.preventDefault();
84
+ depth.current += 1;
85
+ if (!disabled) setOver(true);
86
+ },
87
+ onDragOver: (e) => {
88
+ if (!dragHasFiles(e)) return;
89
+ e.stopPropagation();
90
+ // Always cancelled for a file drag, disabled or not: an uncancelled drop makes
91
+ // the browser NAVIGATE to the file, which loses the page.
92
+ e.preventDefault();
93
+ e.dataTransfer.dropEffect = disabled ? "none" : "copy";
94
+ },
95
+ onDragLeave: (e) => {
96
+ if (!dragHasFiles(e)) return;
97
+ e.stopPropagation();
98
+ depth.current = Math.max(0, depth.current - 1);
99
+ if (depth.current === 0) setOver(false);
100
+ },
101
+ onDrop: (e) => {
102
+ if (!dragHasFiles(e)) return;
103
+ e.stopPropagation();
104
+ e.preventDefault();
105
+ depth.current = 0;
106
+ setOver(false);
107
+ if (!disabled) onDropFiles(e.dataTransfer.files);
108
+ },
109
+ };
110
+
111
+ return { dropProps, isOver: over && !disabled };
112
+ }
113
+
114
+ export function useFileDrop<E extends Element = Element>(
115
+ options: UseFileDropOptions,
116
+ ): UseFileDropReturn<E> {
117
+ const picker = useFilePicker(options);
118
+ const { dropProps, isOver } = useDragTarget<E>({
119
+ disabled: options.disabled,
120
+ onDropFiles: picker.take,
121
+ });
122
+ return { dropProps, isOver, open: picker.open, take: picker.take, element: picker.element };
123
+ }
@@ -20,7 +20,10 @@ import { DEFAULT_ICON_PICKER_LABELS } from "../components/icon-picker";
20
20
  import { DEFAULT_DIALOG_FRAME_LABELS } from "../components/dialog-frame";
21
21
  import { DEFAULT_FILE_PICKER_LABELS } from "../components/file-button";
22
22
  import { DEFAULT_MEASURED_GRID_LABELS } from "../components/measured-grid";
23
+ import { DEFAULT_CONFIRM_DIALOG_LABELS } from "../components/confirm-dialog";
24
+ import { DEFAULT_FLOATING_PANEL_LABELS } from "../components/floating-panel";
23
25
  import { DEFAULT_FEEDBACK_ATTACHMENT_LABELS } from "../feedback/feedback-attachment";
26
+ import { DEFAULT_COPY_BUTTON_LABELS } from "../components/copy-button";
24
27
  import {
25
28
  DEFAULT_APP_SHELL_LABELS,
26
29
  DEFAULT_CALCULATOR_LABELS,
@@ -80,4 +83,7 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
80
83
  filePicker: DEFAULT_FILE_PICKER_LABELS,
81
84
  measuredGrid: DEFAULT_MEASURED_GRID_LABELS,
82
85
  feedbackAttachment: DEFAULT_FEEDBACK_ATTACHMENT_LABELS,
86
+ confirmDialog: DEFAULT_CONFIRM_DIALOG_LABELS,
87
+ floatingPanel: DEFAULT_FLOATING_PANEL_LABELS,
88
+ copyButton: DEFAULT_COPY_BUTTON_LABELS,
83
89
  };
@@ -23,6 +23,9 @@ import type { DialogFrameLabels } from "../components/dialog-frame";
23
23
  import type { FilePickerLabels } from "../components/file-button";
24
24
  import type { MeasuredGridLabels } from "../components/measured-grid";
25
25
  import type { FeedbackAttachmentFieldLabels } from "../feedback/feedback-attachment";
26
+ import type { ConfirmDialogLabels } from "../components/confirm-dialog";
27
+ import type { FloatingPanelLabels } from "../components/floating-panel";
28
+ import type { CopyButtonLabels } from "../components/copy-button";
26
29
 
27
30
  /**
28
31
  * EVERY string the kit renders, as one typed tree — and an optional provider that
@@ -72,6 +75,9 @@ export interface CommonLabels {
72
75
  * A colon-and-space is not universal punctuation (French puts a space before
73
76
  * the colon, Chinese uses a full-width one). */
74
77
  fieldValue: (field: string, value: string) => string;
78
+ /** The × that puts away a banner or a notice (`AlertBanner onDismiss`). Not `close`:
79
+ * nothing opened, and "Close" on a banner reads as closing the page it sits on. */
80
+ dismiss: string;
75
81
  }
76
82
 
77
83
  /** `DatePicker` / `DateRangePicker` chrome. The calendar inside has its own
@@ -85,6 +91,12 @@ export interface DatePickerLabels {
85
91
  previousDay: string;
86
92
  nextDay: string;
87
93
  today: string;
94
+ /** `DateRangePicker commit="apply"`: the button that commits the drafted range. */
95
+ apply: string;
96
+ /** …and the one that discards it. */
97
+ cancel: string;
98
+ /** Accessible name of `DateRangePicker`'s preset column. */
99
+ presets: string;
88
100
  }
89
101
 
90
102
  /** The whole combobox family: `Combobox`, `EntityCombobox`,
@@ -212,6 +224,9 @@ export interface UiKitLabels {
212
224
  filePicker: FilePickerLabels;
213
225
  measuredGrid: MeasuredGridLabels;
214
226
  feedbackAttachment: FeedbackAttachmentFieldLabels;
227
+ confirmDialog: ConfirmDialogLabels;
228
+ floatingPanel: FloatingPanelLabels;
229
+ copyButton: CopyButtonLabels;
215
230
  }
216
231
 
217
232
  /** Any subset of the tree, one level deep — each namespace may be partial, and a
@@ -233,6 +248,7 @@ export const DEFAULT_COMMON_LABELS: CommonLabels = {
233
248
  loading: "Loading…",
234
249
  noResults: "No results",
235
250
  fieldValue: (field, value) => `${field}: ${value}`,
251
+ dismiss: "Dismiss",
236
252
  };
237
253
 
238
254
  export const DEFAULT_DATE_PICKER_LABELS: DatePickerLabels = {
@@ -242,6 +258,9 @@ export const DEFAULT_DATE_PICKER_LABELS: DatePickerLabels = {
242
258
  previousDay: "Previous day",
243
259
  nextDay: "Next day",
244
260
  today: "Today",
261
+ apply: "Apply",
262
+ cancel: "Cancel",
263
+ presets: "Quick ranges",
245
264
  };
246
265
 
247
266
  export const DEFAULT_COMBOBOX_LABELS: ComboboxLabels = {
@@ -0,0 +1,10 @@
1
+ import type { UiKitLabels } from "../kit-labels";
2
+ import { swiss } from "../swiss";
3
+ import { uiKitLabelsDeInformal } from "./de-informal";
4
+
5
+ /**
6
+ * Swiss Standard German, informal ("du"): the informal German labels with Swiss
7
+ * spelling ("ss" for every "ß") and `de-CH` number formatting (1’234.5) — derived the
8
+ * same way `de-CH` is from `de`, so both stay in sync with their source.
9
+ */
10
+ export const UI_KIT_LABELS_DE_CH_INFORMAL: UiKitLabels = swiss(uiKitLabelsDeInformal("de-CH"));
@@ -1,4 +1,5 @@
1
1
  import type { UiKitLabels } from "../kit-labels";
2
+ import { swiss } from "../swiss";
2
3
  import { uiKitLabelsDe } from "./de";
3
4
 
4
5
  /**
@@ -12,19 +13,3 @@ import { uiKitLabelsDe } from "./de";
12
13
  * is what a Swiss app writing "ss" everywhere wants.
13
14
  */
14
15
  export const UI_KIT_LABELS_DE_CH: UiKitLabels = swiss(uiKitLabelsDe("de-CH"));
15
-
16
- function respell(text: string): string {
17
- return text.replace(/ß/g, "ss").replace(/ẞ/g, "SS");
18
- }
19
-
20
- function swiss<T>(value: T): T {
21
- if (typeof value === "string") return respell(value) as T;
22
- if (typeof value === "function") {
23
- const fn = value as (...args: unknown[]) => unknown;
24
- return ((...args: unknown[]) => swiss(fn(...args))) as T;
25
- }
26
- if (value && typeof value === "object") {
27
- return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, swiss(v)])) as T;
28
- }
29
- return value;
30
- }
@@ -0,0 +1,61 @@
1
+ import type { UiKitLabels } from "../kit-labels";
2
+ import { uiKitLabelsDe } from "./de";
3
+
4
+ /**
5
+ * The kit's words in informal German ("du"), for apps that address their users that way
6
+ * everywhere else: `<UiKitProvider labels={UI_KIT_LABELS_DE_INFORMAL}>`.
7
+ *
8
+ * Built on the formal catalogue ({@link uiKitLabelsDe}) rather than beside it: most of
9
+ * the kit's German never addresses anyone — buttons are infinitives ("Speichern"),
10
+ * status lines are impersonal ("Wird geladen…"), hints use the infinitive
11
+ * ("Mindestens 3 Zeichen eingeben", "Bitte erneut versuchen") — so it is the same text
12
+ * in both registers and stays in sync with `de.ts` by construction. Only the sentences
13
+ * that speak TO the user are rewritten here, by hand: du/Sie is grammar (verb forms,
14
+ * imperatives, possessives), not a substitution a regex could do.
15
+ *
16
+ * Every key of `de.ts` was reviewed. The overridden ones — the complete list of
17
+ * sentences that say "Sie" / "Ihr" / a Sie-imperative in the formal catalogue:
18
+ * - `miniCalendar.startSelected`, `miniCalendar.rangeSelected`
19
+ * - `dangerConfirm.phrase`
20
+ * - `wizard.confirmCancel`, `wizard.missingRequired`
21
+ * - `tour.awaitClickHint`
22
+ * - `signaturePad.instructions`, `signaturePad.typedFallbackHint`
23
+ *
24
+ * A key added to `de.ts` later is inherited as is; if it addresses the user, add its
25
+ * du form here (the "no formal address" test in locales.test.ts catches a "Sie").
26
+ * Conventions as in `de.ts`: „…“ quotes, `Intl` digits (via the `numberLocale`
27
+ * argument, e.g. `"de-AT"`), number agreement.
28
+ */
29
+ export function uiKitLabelsDeInformal(numberLocale = "de-DE"): UiKitLabels {
30
+ const de = uiKitLabelsDe(numberLocale);
31
+
32
+ return {
33
+ ...de,
34
+ miniCalendar: {
35
+ ...de.miniCalendar,
36
+ startSelected: (date) => `${date} als Startdatum gewählt. Wähle jetzt ein Enddatum.`,
37
+ rangeSelected: (from, to) =>
38
+ `Zeitraum ${from} bis ${to} gewählt. Wähle ein Startdatum, um neu zu beginnen.`,
39
+ },
40
+ dangerConfirm: {
41
+ ...de.dangerConfirm,
42
+ phrase: (phrase) => `Gib zur Bestätigung „${phrase}“ ein`,
43
+ },
44
+ wizard: {
45
+ ...de.wizard,
46
+ confirmCancel: "Deine Eingaben gehen verloren.",
47
+ missingRequired: "Bitte fülle alle Pflichtfelder aus.",
48
+ },
49
+ tour: {
50
+ ...de.tour,
51
+ awaitClickHint: "Klick auf das hervorgehobene Element, um fortzufahren",
52
+ },
53
+ signaturePad: {
54
+ ...de.signaturePad,
55
+ instructions: "Unterschreibe im Feld mit der Maus, dem Finger oder einem Stift.",
56
+ typedFallbackHint: "Wenn du nicht zeichnen kannst, gib stattdessen deinen Namen ein.",
57
+ },
58
+ };
59
+ }
60
+
61
+ export const UI_KIT_LABELS_DE_INFORMAL: UiKitLabels = uiKitLabelsDeInformal();
@@ -41,6 +41,7 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
41
41
  },
42
42
  pageContents: { title: "Auf dieser Seite" },
43
43
  common: {
44
+ dismiss: "Schließen",
44
45
  close: "Schließen",
45
46
  clear: "Leeren",
46
47
  search: "Suchen",
@@ -118,6 +119,9 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
118
119
  `Zeitraum ${from} bis ${to} gewählt. Wählen Sie ein Startdatum, um neu zu beginnen.`,
119
120
  },
120
121
  datePicker: {
122
+ apply: "Übernehmen",
123
+ cancel: "Abbrechen",
124
+ presets: "Schnellauswahl",
121
125
  panel: "Datum wählen",
122
126
  rangePanel: "Zeitraum wählen",
123
127
  clear: "Leeren",
@@ -243,6 +247,12 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
243
247
  size: (bytes) => formatFileSize(bytes, numberLocale),
244
248
  },
245
249
  filePicker: {
250
+ dropzone: "Datei-Upload",
251
+ browse: "Durchsuchen",
252
+ empty: "Datei hier ablegen",
253
+ emptyMultiple: "Dateien hier ablegen",
254
+ hint: (accept) => (accept ? `Erlaubt: ${accept}` : "Beliebiger Dateityp"),
255
+ busy: "Wird hochgeladen…",
246
256
  rejectedPick: (count) =>
247
257
  count === 1
248
258
  ? "Die Datei wurde nicht hinzugefügt"
@@ -265,6 +275,7 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
265
275
  cleared: "Alle Dateien entfernt",
266
276
  },
267
277
  wizard: {
278
+ done: "Fertig",
268
279
  cancel: "Abbrechen",
269
280
  back: "Zurück",
270
281
  next: "Weiter",
@@ -359,6 +370,20 @@ export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
359
370
  empty: "Keine Daten",
360
371
  legend: "Datenreihen",
361
372
  },
373
+ confirmDialog: {
374
+ confirm: "Bestätigen",
375
+ cancel: "Abbrechen",
376
+ },
377
+ floatingPanel: {
378
+ close: "Schließen",
379
+ },
380
+ copyButton: {
381
+ copy: "Kopieren",
382
+ copied: "Kopiert",
383
+ failed: "Kopieren fehlgeschlagen",
384
+ copiedAnnouncement: "In die Zwischenablage kopiert",
385
+ failedAnnouncement: "Kopieren in die Zwischenablage fehlgeschlagen",
386
+ },
362
387
  };
363
388
  }
364
389
 
@@ -42,6 +42,7 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
42
42
  },
43
43
  pageContents: { title: "En esta página" },
44
44
  common: {
45
+ dismiss: "Cerrar",
45
46
  close: "Cerrar",
46
47
  clear: "Borrar",
47
48
  search: "Buscar",
@@ -125,6 +126,9 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
125
126
  month: (monthYear) => monthYear,
126
127
  },
127
128
  datePicker: {
129
+ apply: "Aplicar",
130
+ cancel: "Cancelar",
131
+ presets: "Rangos rápidos",
128
132
  panel: "Elegir una fecha",
129
133
  rangePanel: "Elegir un intervalo de fechas",
130
134
  clear: "Borrar",
@@ -240,6 +244,12 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
240
244
  size: (bytes) => formatFileSize(bytes, numberLocale),
241
245
  },
242
246
  filePicker: {
247
+ dropzone: "Carga de archivos",
248
+ browse: "Examinar",
249
+ empty: "Suelte un archivo aquí",
250
+ emptyMultiple: "Suelte archivos aquí",
251
+ hint: (accept) => (accept ? `Aceptados: ${accept}` : "Cualquier tipo de archivo"),
252
+ busy: "Subiendo…",
243
253
  rejectedPick: (count) =>
244
254
  count === 1 ? "El archivo no se añadió" : `No se añadió ninguno de los ${count} archivos`,
245
255
  rejectedType: (name) => `El tipo de archivo de «${name}» no es compatible`,
@@ -258,6 +268,7 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
258
268
  cleared: "Se han quitado todos los archivos",
259
269
  },
260
270
  wizard: {
271
+ done: "Listo",
261
272
  cancel: "Cancelar",
262
273
  back: "Atrás",
263
274
  next: "Siguiente",
@@ -352,6 +363,20 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
352
363
  empty: "Sin datos",
353
364
  legend: "Series",
354
365
  },
366
+ confirmDialog: {
367
+ confirm: "Confirmar",
368
+ cancel: "Cancelar",
369
+ },
370
+ floatingPanel: {
371
+ close: "Cerrar",
372
+ },
373
+ copyButton: {
374
+ copy: "Copiar",
375
+ copied: "Copiado",
376
+ failed: "No se pudo copiar",
377
+ copiedAnnouncement: "Copiado al portapapeles",
378
+ failedAnnouncement: "No se pudo copiar al portapapeles",
379
+ },
355
380
  };
356
381
  }
357
382
 
@@ -44,6 +44,7 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
44
44
  },
45
45
  pageContents: { title: "Sur cette page" },
46
46
  common: {
47
+ dismiss: "Fermer",
47
48
  close: "Fermer",
48
49
  clear: "Effacer",
49
50
  search: "Rechercher",
@@ -122,6 +123,9 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
122
123
  `Période du ${from} au ${to} sélectionnée. Choisissez une date de début pour recommencer.`,
123
124
  },
124
125
  datePicker: {
126
+ apply: "Appliquer",
127
+ cancel: "Annuler",
128
+ presets: "Plages rapides",
125
129
  panel: "Choisir une date",
126
130
  rangePanel: "Choisir une période",
127
131
  clear: "Effacer",
@@ -245,6 +249,12 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
245
249
  size: (bytes) => formatFileSize(bytes, numberLocale),
246
250
  },
247
251
  filePicker: {
252
+ dropzone: "Envoi de fichier",
253
+ browse: "Parcourir",
254
+ empty: "Déposez un fichier ici",
255
+ emptyMultiple: "Déposez des fichiers ici",
256
+ hint: (accept) => (accept ? `Acceptés\u00a0: ${accept}` : "Tout type de fichier"),
257
+ busy: "Envoi en cours…",
248
258
  rejectedPick: (count) =>
249
259
  count < 2
250
260
  ? "Le fichier n\u2019a pas été ajouté"
@@ -270,6 +280,7 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
270
280
  cleared: "Tous les fichiers ont été supprimés",
271
281
  },
272
282
  wizard: {
283
+ done: "Terminé",
273
284
  cancel: "Annuler",
274
285
  back: "Retour",
275
286
  next: "Suivant",
@@ -365,6 +376,20 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
365
376
  empty: "Aucune donnée",
366
377
  legend: "Séries",
367
378
  },
379
+ confirmDialog: {
380
+ confirm: "Confirmer",
381
+ cancel: "Annuler",
382
+ },
383
+ floatingPanel: {
384
+ close: "Fermer",
385
+ },
386
+ copyButton: {
387
+ copy: "Copier",
388
+ copied: "Copié",
389
+ failed: "Échec de la copie",
390
+ copiedAnnouncement: "Copié dans le presse-papiers",
391
+ failedAnnouncement: "Impossible de copier dans le presse-papiers",
392
+ },
368
393
  };
369
394
  }
370
395
 
@@ -40,6 +40,7 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
40
40
  },
41
41
  pageContents: { title: "Ezen az oldalon" },
42
42
  common: {
43
+ dismiss: "Bezárás",
43
44
  close: "Bezárás",
44
45
  clear: "Törlés",
45
46
  search: "Keresés",
@@ -121,6 +122,9 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
121
122
  month: (monthYear) => monthYear,
122
123
  },
123
124
  datePicker: {
125
+ apply: "Alkalmaz",
126
+ cancel: "Mégse",
127
+ presets: "Gyors tartományok",
124
128
  panel: "Dátum kiválasztása",
125
129
  rangePanel: "Időszak kiválasztása",
126
130
  clear: "Törlés",
@@ -238,6 +242,12 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
238
242
  size: (bytes) => formatFileSize(bytes, numberLocale),
239
243
  },
240
244
  filePicker: {
245
+ dropzone: "Fájlfeltöltés",
246
+ browse: "Tallózás",
247
+ empty: "Húzzon ide egy fájlt",
248
+ emptyMultiple: "Húzzon ide fájlokat",
249
+ hint: (accept) => (accept ? `Elfogadott: ${accept}` : "Bármilyen fájltípus"),
250
+ busy: "Feltöltés…",
241
251
  rejectedPick: (count) =>
242
252
  count === 1
243
253
  ? "A fájl nem lett hozzáadva"
@@ -259,6 +269,7 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
259
269
  cleared: "Minden fájl eltávolítva",
260
270
  },
261
271
  wizard: {
272
+ done: "Kész",
262
273
  cancel: "Mégse",
263
274
  back: "Vissza",
264
275
  next: "Tovább",
@@ -353,6 +364,20 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
353
364
  empty: "Nincs adat",
354
365
  legend: "Adatsorok",
355
366
  },
367
+ confirmDialog: {
368
+ confirm: "Megerősítés",
369
+ cancel: "Mégse",
370
+ },
371
+ floatingPanel: {
372
+ close: "Bezárás",
373
+ },
374
+ copyButton: {
375
+ copy: "Másolás",
376
+ copied: "Másolva",
377
+ failed: "A másolás nem sikerült",
378
+ copiedAnnouncement: "Vágólapra másolva",
379
+ failedAnnouncement: "Nem sikerült a vágólapra másolni",
380
+ },
356
381
  };
357
382
  }
358
383