@cosmicdrift/kumiko-renderer 0.386.0 → 0.387.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 (185) hide show
  1. package/LICENSE +21 -57
  2. package/dist/app/action-form-body.d.ts +2 -2
  3. package/dist/app/action-form-body.js +2 -2
  4. package/dist/app/action-form-shim.d.ts +8 -8
  5. package/dist/app/action-form-shim.js +20 -22
  6. package/dist/app/app-features-context.js +4 -4
  7. package/dist/app/column-renderers.d.ts +7 -9
  8. package/dist/app/column-renderers.js +15 -18
  9. package/dist/app/config-edit-body.js +1 -1
  10. package/dist/app/config-edit-shim.d.ts +7 -8
  11. package/dist/app/config-edit-shim.js +18 -20
  12. package/dist/app/custom-screens.d.ts +3 -3
  13. package/dist/app/custom-screens.js +8 -8
  14. package/dist/app/dashboard-body.d.ts +2 -2
  15. package/dist/app/dashboard-body.js +2 -2
  16. package/dist/app/entity-edit-prefill.js +9 -9
  17. package/dist/app/entity-edit-screen.js +4 -4
  18. package/dist/app/entity-list-screen.js +3 -3
  19. package/dist/app/extension-form-submit.d.ts +1 -1
  20. package/dist/app/extension-form-submit.js +14 -15
  21. package/dist/app/extension-sections.d.ts +24 -25
  22. package/dist/app/extension-sections.js +10 -10
  23. package/dist/app/feature-schema.js +11 -11
  24. package/dist/app/form-schema.js +1 -1
  25. package/dist/app/header-actions-bar.js +1 -1
  26. package/dist/app/kumiko-screen.js +8 -10
  27. package/dist/app/layout-fields.js +1 -1
  28. package/dist/app/list-facets.js +3 -3
  29. package/dist/app/nav.d.ts +10 -10
  30. package/dist/app/nav.js +13 -13
  31. package/dist/app/projection-detail-body.js +4 -4
  32. package/dist/app/projection-detail-shim.d.ts +6 -5
  33. package/dist/app/projection-detail-shim.js +23 -22
  34. package/dist/app/projection-list-body.js +10 -10
  35. package/dist/app/projection-list-shim.d.ts +5 -5
  36. package/dist/app/projection-list-shim.js +17 -18
  37. package/dist/app/qn.js +10 -12
  38. package/dist/app/qualify-screen-id.js +1 -1
  39. package/dist/app/screen-access.js +2 -2
  40. package/dist/app/screen-shared.js +1 -1
  41. package/dist/app/secret-mint-body.js +4 -4
  42. package/dist/app/write-failed-error.js +8 -7
  43. package/dist/components/embedded-list-field.js +4 -4
  44. package/dist/components/grid-cell-for-field.d.ts +1 -1
  45. package/dist/components/reference-create-dialog.js +3 -3
  46. package/dist/components/related-list-section.d.ts +1 -1
  47. package/dist/components/related-list-section.js +1 -1
  48. package/dist/components/render-edit-logic.js +1 -1
  49. package/dist/components/render-edit-types.d.ts +6 -6
  50. package/dist/components/render-edit.js +63 -65
  51. package/dist/components/render-field.d.ts +7 -7
  52. package/dist/components/render-field.js +57 -59
  53. package/dist/components/render-list.d.ts +42 -43
  54. package/dist/components/render-list.js +63 -67
  55. package/dist/components/use-wizard-form-draft.js +10 -10
  56. package/dist/context/dispatcher-context.js +5 -5
  57. package/dist/context/user-roles-context.js +2 -2
  58. package/dist/headless/apex/index.d.ts +1 -2
  59. package/dist/headless/apex/index.js +5 -6
  60. package/dist/headless/form/form-controller.js +6 -6
  61. package/dist/headless/form/zod-bridge.js +2 -2
  62. package/dist/headless/format/money.js +1 -1
  63. package/dist/headless/index.js +2 -2
  64. package/dist/headless/view-model/edit.js +2 -2
  65. package/dist/headless/view-model/list.js +3 -4
  66. package/dist/headless/view-model/types.d.ts +3 -3
  67. package/dist/hooks/reference-limits.js +11 -12
  68. package/dist/hooks/use-list-url-state.d.ts +13 -13
  69. package/dist/hooks/use-list-url-state.js +21 -22
  70. package/dist/hooks/use-query.js +3 -3
  71. package/dist/hooks/use-reference-lookup.js +16 -17
  72. package/dist/hooks/use-store.js +18 -22
  73. package/dist/hooks/use-stream-handler.js +4 -2
  74. package/dist/i18n-defaults.js +2 -8
  75. package/dist/i18n.d.ts +10 -10
  76. package/dist/i18n.js +25 -25
  77. package/dist/index.js +5 -4
  78. package/dist/live/dispatcher-live.js +2 -2
  79. package/dist/primitives.d.ts +225 -221
  80. package/dist/primitives.js +1 -1
  81. package/dist/sse/live-events.d.ts +5 -5
  82. package/dist/sse/live-events.js +17 -17
  83. package/dist/tokens.d.ts +8 -8
  84. package/dist/tokens.js +16 -17
  85. package/dist/web/app/browser-locale.d.ts +9 -9
  86. package/dist/web/app/browser-locale.js +19 -19
  87. package/dist/web/app/client-plugin.d.ts +44 -52
  88. package/dist/web/app/client-plugin.js +4 -5
  89. package/dist/web/app/create-app.d.ts +28 -31
  90. package/dist/web/app/create-app.js +21 -22
  91. package/dist/web/app/document-lang-sync.js +1 -1
  92. package/dist/web/app/draft-storage.js +1 -1
  93. package/dist/web/app/nav-providers-context.d.ts +3 -3
  94. package/dist/web/app/nav-providers-context.js +3 -3
  95. package/dist/web/app/nav.d.ts +18 -17
  96. package/dist/web/app/nav.js +66 -64
  97. package/dist/web/app/rich-content-editor.js +1 -1
  98. package/dist/web/components/config-cascade.js +17 -18
  99. package/dist/web/components/config-source-badge.js +4 -4
  100. package/dist/web/layout/app-layout.d.ts +9 -9
  101. package/dist/web/layout/app-layout.js +2 -2
  102. package/dist/web/layout/avatar.d.ts +4 -3
  103. package/dist/web/layout/avatar.js +15 -17
  104. package/dist/web/layout/default-app-shell.d.ts +22 -23
  105. package/dist/web/layout/editor-panel.js +3 -3
  106. package/dist/web/layout/nav-tree.js +86 -84
  107. package/dist/web/layout/profile-menu.d.ts +1 -1
  108. package/dist/web/layout/sidebar-brand.d.ts +7 -7
  109. package/dist/web/layout/sidebar-user.d.ts +1 -1
  110. package/dist/web/layout/sidebar-user.js +4 -4
  111. package/dist/web/layout/sidebar.d.ts +8 -8
  112. package/dist/web/layout/sidebar.js +7 -7
  113. package/dist/web/layout/target-resolver-stub.d.ts +5 -5
  114. package/dist/web/layout/target-resolver-stub.js +20 -20
  115. package/dist/web/layout/target-url.d.ts +7 -7
  116. package/dist/web/layout/target-url.js +22 -22
  117. package/dist/web/layout/theme-toggle.js +4 -5
  118. package/dist/web/layout/workspace-shell.d.ts +21 -21
  119. package/dist/web/layout/workspace-shell.js +29 -30
  120. package/dist/web/lib/cn.d.ts +4 -4
  121. package/dist/web/lib/cn.js +4 -4
  122. package/dist/web/primitives/action-menu.d.ts +8 -8
  123. package/dist/web/primitives/action-menu.js +14 -13
  124. package/dist/web/primitives/calendar-popover.d.ts +1 -1
  125. package/dist/web/primitives/calendar-popover.js +10 -10
  126. package/dist/web/primitives/card-styles.js +1 -1
  127. package/dist/web/primitives/card.js +2 -2
  128. package/dist/web/primitives/combobox.d.ts +12 -12
  129. package/dist/web/primitives/combobox.js +34 -35
  130. package/dist/web/primitives/data-table-cell.js +2 -2
  131. package/dist/web/primitives/data-table.js +2 -3
  132. package/dist/web/primitives/date-field.js +2 -2
  133. package/dist/web/primitives/date-input.js +4 -4
  134. package/dist/web/primitives/default-form.js +2 -2
  135. package/dist/web/primitives/dropdown-menu.js +14 -15
  136. package/dist/web/primitives/embedded-list-input.js +3 -3
  137. package/dist/web/primitives/facet-filter.js +1 -1
  138. package/dist/web/primitives/field.js +9 -8
  139. package/dist/web/primitives/form.d.ts +1 -1
  140. package/dist/web/primitives/form.js +6 -6
  141. package/dist/web/primitives/input.js +2 -2
  142. package/dist/web/primitives/layout-elements.js +1 -1
  143. package/dist/web/primitives/layout.js +2 -2
  144. package/dist/web/primitives/located-timestamp-input.js +4 -4
  145. package/dist/web/primitives/money-input.js +13 -17
  146. package/dist/web/primitives/pager.js +1 -1
  147. package/dist/web/primitives/row-actions.js +3 -4
  148. package/dist/web/primitives/secret-reveal.js +1 -1
  149. package/dist/web/primitives/timestamp-input.d.ts +9 -9
  150. package/dist/web/primitives/timestamp-input.js +21 -21
  151. package/dist/web/primitives/toast.js +12 -13
  152. package/dist/web/sse/live-events.d.ts +6 -6
  153. package/dist/web/sse/live-events.js +3 -3
  154. package/dist/web/tokens.d.ts +11 -12
  155. package/dist/web/tokens.js +35 -37
  156. package/dist/web/version/update-checker.js +14 -13
  157. package/dist/web/widgets/ai-text-field.js +1 -1
  158. package/dist/web/widgets/charts.d.ts +10 -10
  159. package/dist/web/widgets/charts.js +8 -8
  160. package/dist/web/widgets/collapsible-section.d.ts +3 -3
  161. package/dist/web/widgets/collapsible-section.js +6 -6
  162. package/dist/web/widgets/detail-list.d.ts +1 -3
  163. package/dist/web/widgets/detail-list.js +1 -3
  164. package/dist/web/widgets/feed-list.d.ts +2 -2
  165. package/dist/web/widgets/feed-list.js +2 -2
  166. package/dist/web/widgets/form-fields.d.ts +14 -14
  167. package/dist/web/widgets/form-fields.js +14 -13
  168. package/dist/web/widgets/index.js +4 -4
  169. package/dist/web/widgets/infinity-list.js +3 -3
  170. package/dist/web/widgets/mode-switch.d.ts +2 -2
  171. package/dist/web/widgets/mode-switch.js +2 -2
  172. package/dist/web/widgets/progress-list.d.ts +1 -2
  173. package/dist/web/widgets/progress-list.js +1 -2
  174. package/dist/web/widgets/query-table.d.ts +6 -6
  175. package/dist/web/widgets/result-panel.d.ts +16 -16
  176. package/dist/web/widgets/result-panel.js +10 -10
  177. package/dist/web/widgets/section-card.d.ts +3 -3
  178. package/dist/web/widgets/section-card.js +3 -3
  179. package/dist/web/widgets/stat.d.ts +4 -4
  180. package/dist/web/widgets/stat.js +6 -6
  181. package/dist/web/widgets/states.d.ts +4 -4
  182. package/dist/web/widgets/states.js +4 -4
  183. package/dist/web/widgets/use-draft.d.ts +7 -7
  184. package/dist/web/widgets/use-draft.js +7 -7
  185. package/package.json +6 -6
@@ -4,8 +4,8 @@ export type FeedRow = {
4
4
  readonly primary: string;
5
5
  readonly trailing?: string;
6
6
  };
7
- /** Nicht-tabellarische Kurzliste (z.B. "nächste Termine") — Primary-Text +
8
- * optionaler rechtsbündiger Trailing-Wert pro Zeile. */
7
+ /** Non-tabular compact list (e.g. "upcoming appointments") — primary text plus
8
+ * an optional right-aligned trailing value for each row. */
9
9
  export declare function FeedList({ rows, emptyContent, testId, }: {
10
10
  readonly rows: readonly FeedRow[];
11
11
  readonly emptyContent?: ReactNode;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /** Nicht-tabellarische Kurzliste (z.B. "nächste Termine") — Primary-Text +
3
- * optionaler rechtsbündiger Trailing-Wert pro Zeile. */
2
+ /** Non-tabular compact list (e.g. "upcoming appointments") — primary text plus
3
+ * an optional right-aligned trailing value for each row. */
4
4
  export function FeedList({ rows, emptyContent, testId, }) {
5
5
  if (rows.length === 0) {
6
6
  return _jsx("div", { "data-testid": testId, children: emptyContent });
@@ -12,10 +12,10 @@ export interface NumberFieldProps {
12
12
  /** `false` renders without thousands separators (e.g. a year). Default `true`. */
13
13
  readonly grouping?: boolean;
14
14
  }
15
- /** Zahlenfeld = Field + Input(kind:"number") in einem — nimmt der Screen die
16
- * wiederholte id/name/value/onChange-Verdrahtung ab. `value` darf `undefined`
17
- * sein (leeres Feld), intern auf den `""`-Empty-State des Inputs gemappt.
18
- * Einheiten (€/%) gehören ins Label (`t("…Summe (€)")`), nicht als Badge. */
15
+ /** Number field = Field + Input(kind:"number"); avoids repeating the
16
+ * id/name/value/onChange wiring at each screen. `value` may be `undefined`
17
+ * (empty field) and is mapped internally to the Input's `""` empty state.
18
+ * Units (€/%) belong in the label (`t("…Summe (€)")`), not in a badge. */
19
19
  export declare function NumberField({ label, id, name, value, onChange, required, disabled, hideLabel, testId, grouping, }: NumberFieldProps): ReactNode;
20
20
  export declare const MoneyField: typeof NumberField;
21
21
  export declare const PercentField: typeof NumberField;
@@ -34,7 +34,7 @@ export interface TextFieldProps extends FieldBase {
34
34
  readonly placeholder?: string;
35
35
  readonly autoComplete?: string;
36
36
  }
37
- /** Textfeld = Field + Input(kind:"text"). */
37
+ /** Text field = Field + Input(kind:"text"). */
38
38
  export declare function TextField({ label, id, name, value, onChange, required, disabled, placeholder, autoComplete, hideLabel, testId, }: TextFieldProps): ReactNode;
39
39
  export interface SelectFieldProps extends FieldBase {
40
40
  readonly value: string;
@@ -44,7 +44,7 @@ export interface SelectFieldProps extends FieldBase {
44
44
  readonly label: string;
45
45
  }[];
46
46
  }
47
- /** Auswahlfeld = Field + Input(kind:"select"). */
47
+ /** Select field = Field + Input(kind:"select"). */
48
48
  export declare function SelectField({ label, id, name, value, onChange, options, required, disabled, hideLabel, testId, }: SelectFieldProps): ReactNode;
49
49
  export interface DateFieldProps extends FieldBase {
50
50
  readonly value: string;
@@ -52,7 +52,7 @@ export interface DateFieldProps extends FieldBase {
52
52
  readonly min?: string;
53
53
  readonly max?: string;
54
54
  }
55
- /** Datumsfeld = Field + Input(kind:"date"), ISO yyyy-mm-dd. */
55
+ /** Date field = Field + Input(kind:"date"), ISO yyyy-mm-dd. */
56
56
  export declare function DateField({ label, id, name, value, onChange, min, max, required, disabled, hideLabel, testId, }: DateFieldProps): ReactNode;
57
57
  export interface BooleanFieldProps extends FieldBase {
58
58
  readonly value: boolean;
@@ -65,7 +65,7 @@ export interface TextareaFieldProps extends FieldBase {
65
65
  readonly onChange: (v: string) => void;
66
66
  readonly rows?: number;
67
67
  }
68
- /** Mehrzeiliges Textfeld = Field + Input(kind:"textarea"). */
68
+ /** Multi-line text field = Field + Input(kind:"textarea"). */
69
69
  export declare function TextareaField({ label, id, name, value, onChange, rows, required, disabled, hideLabel, testId, }: TextareaFieldProps): ReactNode;
70
70
  export interface RangeFieldProps extends FieldBase {
71
71
  readonly value: number;
@@ -74,20 +74,20 @@ export interface RangeFieldProps extends FieldBase {
74
74
  readonly max: number;
75
75
  readonly step?: number;
76
76
  }
77
- /** Schieberegler = Field + Input(kind:"range"). */
77
+ /** Slider = Field + Input(kind:"range"). */
78
78
  export declare function RangeField({ label, id, name, value, onChange, min, max, step, required, disabled, hideLabel, testId, }: RangeFieldProps): ReactNode;
79
79
  export interface FileFieldProps extends FieldBase {
80
- /** FileRef-UUID der gespeicherten Datei, oder null. */
80
+ /** FileRef UUID of the stored file, or null. */
81
81
  readonly value: string | null;
82
82
  readonly onChange: (fileId: string | null) => void;
83
83
  readonly accept?: readonly string[];
84
- /** "image" zeigt eine Vorschau, "file" nur den Dateinamen. Default "file". */
84
+ /** "image" shows a preview; "file" shows only the file name. Default "file". */
85
85
  readonly variant?: "file" | "image";
86
- /** Bindet den Upload an ein konkretes Entity-Feld — der `/api/files`-Endpoint
87
- * prüft `accept`/`maxSize` dann serverseitig gegen dessen Feld-Definition. */
86
+ /** Binds the upload to a specific entity field; the `/api/files` endpoint
87
+ * then validates `accept`/`maxSize` server-side against that field's definition. */
88
88
  readonly entityType?: string;
89
89
  readonly fieldName?: string;
90
90
  }
91
- /** Datei-Upload = Field + Input(kind:"file"|"image") — FileRef-basiert. */
91
+ /** File upload = Field + Input(kind:"file"|"image"), based on FileRef. */
92
92
  export declare function FileField({ label, id, name, value, onChange, accept, variant, entityType, fieldName, required, disabled, hideLabel, testId, }: FileFieldProps): ReactNode;
93
93
  export {};
@@ -1,29 +1,30 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { usePrimitives } from "../../index.js";
3
- /** Zahlenfeld = Field + Input(kind:"number") in einem — nimmt der Screen die
4
- * wiederholte id/name/value/onChange-Verdrahtung ab. `value` darf `undefined`
5
- * sein (leeres Feld), intern auf den `""`-Empty-State des Inputs gemappt.
6
- * Einheiten (€/%) gehören ins Label (`t("…Summe (€)")`), nicht als Badge. */
3
+ /** Number field = Field + Input(kind:"number"); avoids repeating the
4
+ * id/name/value/onChange wiring at each screen. `value` may be `undefined`
5
+ * (empty field) and is mapped internally to the Input's `""` empty state.
6
+ * Units (€/%) belong in the label (`t("…Summe (€)")`), not in a badge. */
7
7
  export function NumberField({ label, id, name, value, onChange, required, disabled, hideLabel, testId, grouping, }) {
8
8
  const { Field, Input } = usePrimitives();
9
9
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "number", id: id, name: name, value: value ?? "", onChange: onChange, required: required, disabled: disabled, ...(grouping !== undefined && { grouping }) }) }));
10
10
  }
11
- // Aliase markieren die Feld-Absicht am Call-Site (lesbarer als NumberField
12
- // überall) ohne eigene Wrapper-Funktion vorzutäuschen — beide sind identisch
13
- // zu NumberField, kein Ort für künftige geld-/prozent-spezifische Formatierung.
11
+ // Aliases convey the field's intent at the call site (more readable than
12
+ // using NumberField everywhere) without pretending to be wrapper functions;
13
+ // both are identical to NumberField and are not intended for future
14
+ // money-/percentage-specific formatting.
14
15
  export const MoneyField = NumberField;
15
16
  export const PercentField = NumberField;
16
- /** Textfeld = Field + Input(kind:"text"). */
17
+ /** Text field = Field + Input(kind:"text"). */
17
18
  export function TextField({ label, id, name, value, onChange, required, disabled, placeholder, autoComplete, hideLabel, testId, }) {
18
19
  const { Field, Input } = usePrimitives();
19
20
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "text", id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled, ...(placeholder !== undefined && { placeholder }), ...(autoComplete !== undefined && { autoComplete }) }) }));
20
21
  }
21
- /** Auswahlfeld = Field + Input(kind:"select"). */
22
+ /** Select field = Field + Input(kind:"select"). */
22
23
  export function SelectField({ label, id, name, value, onChange, options, required, disabled, hideLabel, testId, }) {
23
24
  const { Field, Input } = usePrimitives();
24
25
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "select", id: id, name: name, value: value, onChange: onChange, options: options, required: required, disabled: disabled }) }));
25
26
  }
26
- /** Datumsfeld = Field + Input(kind:"date"), ISO yyyy-mm-dd. */
27
+ /** Date field = Field + Input(kind:"date"), ISO yyyy-mm-dd. */
27
28
  export function DateField({ label, id, name, value, onChange, min, max, required, disabled, hideLabel, testId, }) {
28
29
  const { Field, Input } = usePrimitives();
29
30
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "date", id: id, name: name, value: value, onChange: (v) => onChange(v ?? ""), required: required, disabled: disabled, ...(min !== undefined && { min }), ...(max !== undefined && { max }) }) }));
@@ -33,17 +34,17 @@ export function BooleanField({ label, id, name, value, onChange, required, disab
33
34
  const { Field, Input } = usePrimitives();
34
35
  return (_jsx(Field, { id: id, label: label, required: required, layout: "inline", hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "boolean", id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled }) }));
35
36
  }
36
- /** Mehrzeiliges Textfeld = Field + Input(kind:"textarea"). */
37
+ /** Multi-line text field = Field + Input(kind:"textarea"). */
37
38
  export function TextareaField({ label, id, name, value, onChange, rows, required, disabled, hideLabel, testId, }) {
38
39
  const { Field, Input } = usePrimitives();
39
40
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "textarea", id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled, ...(rows !== undefined && { rows }) }) }));
40
41
  }
41
- /** Schieberegler = Field + Input(kind:"range"). */
42
+ /** Slider = Field + Input(kind:"range"). */
42
43
  export function RangeField({ label, id, name, value, onChange, min, max, step, required, disabled, hideLabel, testId, }) {
43
44
  const { Field, Input } = usePrimitives();
44
45
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: "range", id: id, name: name, value: value, onChange: onChange, min: min, max: max, required: required, disabled: disabled, ...(step !== undefined && { step }) }) }));
45
46
  }
46
- /** Datei-Upload = Field + Input(kind:"file"|"image") — FileRef-basiert. */
47
+ /** File upload = Field + Input(kind:"file"|"image"), based on FileRef. */
47
48
  export function FileField({ label, id, name, value, onChange, accept, variant = "file", entityType, fieldName, required, disabled, hideLabel, testId, }) {
48
49
  const { Field, Input } = usePrimitives();
49
50
  return (_jsx(Field, { id: id, label: label, required: required, hideLabel: hideLabel, testId: testId, children: _jsx(Input, { kind: variant, id: id, name: name, value: value, onChange: onChange, required: required, disabled: disabled, ...(accept !== undefined && { accept }), ...(entityType !== undefined && { entityType }), ...(fieldName !== undefined && { fieldName }) }) }));
@@ -1,7 +1,7 @@
1
- // Mid-Level-Widgets — Kompositionen über den Primitives (Card, DataTable,
2
- // Banner) + Theme-Tokens. Für Custom-Screens: erst hier schauen, dann bauen.
3
- // Katalog: docs.kumiko.rocks → Guides → Widgets; visueller Überblick im
4
- // styleguide-Sample.
1
+ // Mid-level widgets — compositions built from primitives (Card, DataTable,
2
+ // Banner) and theme tokens. For custom screens, check here before building.
3
+ // Catalog: docs.kumiko.rocks → Guides → Widgets; visual overview in the
4
+ // styleguide sample.
5
5
  export { AiTextArea, AiTextField, } from "./ai-text-field.js";
6
6
  export { SegmentBarChart, StackedAreaChart, StackedBarChart, StatusBarChart, smoothPath, TimeseriesChart, } from "./charts.js";
7
7
  export { CollapsibleSection } from "./collapsible-section.js";
@@ -28,7 +28,7 @@ export function InfinityList({ query, payload, pageSize = 50, rows, nextCursor,
28
28
  // Discards a response whose request was superseded by a newer one before
29
29
  // it resolved (e.g. two searches fired in quick succession) — without
30
30
  // this, a slow earlier response can land after a faster later one and
31
- // overwrite it, leaving stale rows on screen (fw#1705).
31
+ // overwrite it, leaving stale rows on screen.
32
32
  const requestSeq = useRef(0);
33
33
  // IDs of the most recently loaded first page. refreshFirstPage() needs
34
34
  // this to tell "row dropped from page 1 elsewhere" (must be pruned) apart
@@ -84,7 +84,7 @@ export function InfinityList({ query, payload, pageSize = 50, rows, nextCursor,
84
84
  // to the front (newest-first feeds), rows it dropped (edited/deleted
85
85
  // elsewhere) are pruned, and everything beyond page 1 stays untouched.
86
86
  // A full reload would collapse already-accumulated pages and jump the
87
- // scroll position; see fw#1827.
87
+ // scroll position.
88
88
  // biome-ignore lint/correctness/useExhaustiveDependencies: payload goes through payloadKey
89
89
  const refreshFirstPage = useCallback(async () => {
90
90
  // Read, don't bump: a concurrent load() (e.g. the mount fetch still
@@ -127,7 +127,7 @@ export function InfinityList({ query, payload, pageSize = 50, rows, nextCursor,
127
127
  });
128
128
  }, [dispatcher, query, pageSize, payloadKey]);
129
129
  // Trailing debounce + in-flight coalesce: bulk SSE storms must not fan out
130
- // into one query per event (fw#1829). A refresh already running schedules
130
+ // into one query per event. A refresh already running schedules
131
131
  // exactly one trailing pass after it settles.
132
132
  const liveTimerRef = useRef(null);
133
133
  const liveInFlightRef = useRef(false);
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  export type ModeSwitchVariant = "outline" | "pill";
3
- /** Segmented-Control für sich ausschließende Modi — die prominente
4
- * Alternative zum vergrabenen <select>. */
3
+ /** Segmented control for mutually exclusive modes—the prominent
4
+ * alternative to the buried <select>. */
5
5
  export declare function ModeSwitch<T extends string>({ value, options, onChange, ariaLabel, variant, className, testId, }: {
6
6
  /** `null`: no option active. */
7
7
  readonly value: T | null;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/cn.js";
3
- /** Segmented-Control für sich ausschließende Modi — die prominente
4
- * Alternative zum vergrabenen <select>. */
3
+ /** Segmented control for mutually exclusive modes—the prominent
4
+ * alternative to the buried <select>. */
5
5
  export function ModeSwitch({ value, options, onChange, ariaLabel, variant = "outline", className, testId, }) {
6
6
  const pill = variant === "pill";
7
7
  return (_jsx("div", { "data-testid": testId, role: "group", "aria-label": ariaLabel, className: cn("flex min-h-8", pill
@@ -10,8 +10,7 @@ export type ProgressListRow = {
10
10
  /** Small line under the bar, e.g. "42 % repaid". */
11
11
  readonly sub?: string;
12
12
  };
13
- /** Liste aus Label/Wert-Kopfzeile + Fortschrittsbalken pro Eintrag (z.B.
14
- * Tilgungsfortschritt pro Kredit). */
13
+ /** Label/value header and progress bar for each entry (for example, loan repayment progress). */
15
14
  export declare function ProgressList({ rows, emptyContent, testId, }: {
16
15
  readonly rows: readonly ProgressListRow[];
17
16
  readonly emptyContent?: ReactNode;
@@ -1,8 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { ProgressBar } from "./progress-bar.js";
4
- /** Liste aus Label/Wert-Kopfzeile + Fortschrittsbalken pro Eintrag (z.B.
5
- * Tilgungsfortschritt pro Kredit). */
4
+ /** Label/value header and progress bar for each entry (for example, loan repayment progress). */
6
5
  export function ProgressList({ rows, emptyContent, testId, }) {
7
6
  if (rows.length === 0) {
8
7
  return _jsx("div", { "data-testid": testId, children: emptyContent });
@@ -2,25 +2,25 @@ import type { ReactNode } from "react";
2
2
  import { type DataTableProps } from "../../index.ts";
3
3
  export type QueryTableColumn = {
4
4
  readonly field: string;
5
- /** Translated Header-Label (i18n-Key auflösen liegt beim Caller). */
5
+ /** Translated header label (resolving the i18n key is the caller's responsibility). */
6
6
  readonly label: string;
7
- /** Field-Type für die Zell-Formatierung. Default "text". */
7
+ /** Field type for cell formatting. Default: "text". */
8
8
  readonly type?: string;
9
9
  };
10
10
  export type QueryTableProps<TData = unknown> = {
11
11
  /** Dispatcher-Query-Type (`<feature>:query:<entity>:<verb>`). */
12
12
  readonly query: string;
13
13
  readonly payload?: unknown;
14
- /** SSE-Invalidierung — refetcht bei Entity-Events (useQuery live-mode). */
14
+ /** SSE invalidation — refetches on entity events (useQuery live mode). */
15
15
  readonly live?: boolean;
16
16
  readonly columns: readonly QueryTableColumn[];
17
- /** Rows aus dem Query-Result ziehen. Default: Result selbst als Array. */
17
+ /** Extracts rows from the query result. Default: the result itself as an array. */
18
18
  readonly rows?: (data: TData) => readonly Readonly<Record<string, unknown>>[];
19
- /** Row-Id für Keys/Row-Click. Default: `row.id`, sonst der Index. */
19
+ /** Row ID for keys and row clicks. Default: `row.id`, otherwise the index. */
20
20
  readonly rowId?: (row: Readonly<Record<string, unknown>>, index: number) => string;
21
21
  readonly onRowClick?: DataTableProps["onRowClick"];
22
22
  readonly rowActions?: DataTableProps["rowActions"];
23
- /** Empty-Inhalt — Default ist der Standard-Empty-State der Listen. */
23
+ /** Empty content — defaults to the standard list empty state. */
24
24
  readonly emptyState?: ReactNode;
25
25
  readonly toolbarTitle?: ReactNode;
26
26
  readonly toolbarEnd?: ReactNode;
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
- /** Ergebnis-Sektion eines Rechners: SectionCard mit Empty-Zustand (Banner)
3
- * oder Kennzahl-Liste (DetailList) + optionalen Extras (Tabelle, Hinweise).
4
- * Ersetzt die handgebauten `<dl>`/Banner-Blöcke in Custom-Screens. */
2
+ /** Result section for a calculator: SectionCard with an empty state (Banner)
3
+ * or a metric list (DetailList) plus optional extras (table, notes).
4
+ * Replaces hand-built `<dl>`/banner blocks in custom screens. */
5
5
  export declare function ResultPanel({ title, subtitle, empty, emptyText, rows, footer, children, testId, }: {
6
6
  readonly title: string;
7
7
  readonly subtitle?: string;
@@ -12,7 +12,7 @@ export declare function ResultPanel({ title, subtitle, empty, emptyText, rows, f
12
12
  readonly value: ReactNode;
13
13
  readonly emphasize?: boolean;
14
14
  }[];
15
- /** Action-Slot am Karten-Fuß (z.B. „In Finanzierung übernehmen"). */
15
+ /** Action slot at the bottom of the card (e.g. "Move to financing"). */
16
16
  readonly footer?: ReactNode;
17
17
  readonly children?: ReactNode;
18
18
  readonly testId?: string;
@@ -27,18 +27,18 @@ export interface ResultTableFooterRow {
27
27
  readonly value: ReactNode;
28
28
  readonly emphasize?: boolean;
29
29
  }
30
- /** Statische, prop-getriebene Ergebnistabelle für berechnete Zeilen (Tranchen,
31
- * Szenarien). Nimmt dem Screen die `<table>`+tabular-nums-Ketten ab.
32
- * ponytail: bewusst die minimale Read-only-Tabelle — für Sort/Pager/Facets
33
- * stattdessen usePrimitives().DataTable bzw. QueryTable nutzen. */
30
+ /** Static, prop-driven result table for calculated rows (tranches, scenarios).
31
+ * Avoids repeating the `<table>`+tabular-nums pattern in each screen.
32
+ * ponytail: intentionally minimal and read-only—for sorting, paging, or facets,
33
+ * use usePrimitives().DataTable or QueryTable instead. */
34
34
  export declare function ResultTable<Row>({ columns, rows, rowKey, testId, className, card, footer, }: {
35
35
  readonly columns: readonly ResultColumn<Row>[];
36
36
  readonly rows: readonly Row[];
37
37
  readonly rowKey: (row: Row, index: number) => string;
38
38
  readonly testId?: string;
39
39
  readonly className?: string;
40
- /** Rahmen-Look wie die CRUD-Liste (DataTable): gerundeter Border-Container +
41
- * bg-muted-Header-Band. Default = bare (nur die Tabelle, ohne Container). */
40
+ /** Framed appearance like the CRUD list (DataTable): rounded border container +
41
+ * bg-muted header band. Default = bare (table only, without a container). */
42
42
  readonly card?: boolean;
43
43
  /** Summary rows (Subtotal/Tax/Total) rendered as real `<tr>`s in the same
44
44
  * `<table>` instead of a separate flex-div next to it — guarantees
@@ -49,12 +49,12 @@ export declare function ResultTable<Row>({ columns, rows, rowKey, testId, classN
49
49
  export interface ComparisonMetric<Col> {
50
50
  readonly label: string;
51
51
  readonly value: (col: Col, index: number) => ReactNode;
52
- /** Index der besten Spalte für diese Zeile (hervorgehoben); -1 = keine. */
52
+ /** Index of the best column for this row (highlighted); -1 = none. */
53
53
  readonly bestIndex?: (cols: readonly Col[]) => number;
54
54
  }
55
- /** Transponierte Vergleichstabelle: Zeile = Kennzahl, Spalte = Variante, je
56
- * Kennzahl optional die beste Spalte hervorgehoben. Für Szenario-/Angebots-
57
- * Vergleiche, wo ResultTable (Zeile=Datensatz) nicht passt. */
55
+ /** Transposed comparison table: row = metric, column = variant, with the best
56
+ * column optionally highlighted for each metric. For scenario/offer comparisons
57
+ * where ResultTable (row = record) is not suitable. */
58
58
  export declare function ComparisonTable<Col>({ columns, columnHeader, columnKey, metrics, metricLabel, testId, className, card, }: {
59
59
  readonly columns: readonly Col[];
60
60
  readonly columnHeader: (col: Col, index: number) => string;
@@ -63,7 +63,7 @@ export declare function ComparisonTable<Col>({ columns, columnHeader, columnKey,
63
63
  readonly metricLabel: string;
64
64
  readonly testId?: string;
65
65
  readonly className?: string;
66
- /** Rahmen-Look wie die CRUD-Liste (DataTable): gerundeter Border-Container +
67
- * bg-muted-Header-Band. Default = bare. */
66
+ /** Framed appearance like the CRUD list (DataTable): rounded border container +
67
+ * bg-muted header band. Default = bare. */
68
68
  readonly card?: boolean;
69
69
  }): ReactNode;
@@ -3,24 +3,24 @@ import { usePrimitives } from "../../index.js";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { DetailList } from "./detail-list.js";
5
5
  import { SectionCard } from "./section-card.js";
6
- /** Ergebnis-Sektion eines Rechners: SectionCard mit Empty-Zustand (Banner)
7
- * oder Kennzahl-Liste (DetailList) + optionalen Extras (Tabelle, Hinweise).
8
- * Ersetzt die handgebauten `<dl>`/Banner-Blöcke in Custom-Screens. */
6
+ /** Result section for a calculator: SectionCard with an empty state (Banner)
7
+ * or a metric list (DetailList) plus optional extras (table, notes).
8
+ * Replaces hand-built `<dl>`/banner blocks in custom screens. */
9
9
  export function ResultPanel({ title, subtitle, empty, emptyText, rows, footer, children, testId, }) {
10
10
  const { Banner } = usePrimitives();
11
11
  return (_jsx(SectionCard, { title: title, subtitle: subtitle, footer: footer, testId: testId, children: empty === true ? (_jsx(Banner, { variant: "info", padded: true, children: emptyText })) : (_jsxs("div", { className: "flex flex-col gap-4", children: [rows !== undefined && rows.length > 0 && _jsx(DetailList, { rows: rows }), children] })) }));
12
12
  }
13
- /** Statische, prop-getriebene Ergebnistabelle für berechnete Zeilen (Tranchen,
14
- * Szenarien). Nimmt dem Screen die `<table>`+tabular-nums-Ketten ab.
15
- * ponytail: bewusst die minimale Read-only-Tabelle — für Sort/Pager/Facets
16
- * stattdessen usePrimitives().DataTable bzw. QueryTable nutzen. */
13
+ /** Static, prop-driven result table for calculated rows (tranches, scenarios).
14
+ * Avoids repeating the `<table>`+tabular-nums pattern in each screen.
15
+ * ponytail: intentionally minimal and read-only—for sorting, paging, or facets,
16
+ * use usePrimitives().DataTable or QueryTable instead. */
17
17
  export function ResultTable({ columns, rows, rowKey, testId, className, card, footer, }) {
18
18
  const table = (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { "data-testid": testId, className: cn("w-full text-sm", className), children: [_jsx("thead", { className: cn(card === true && "bg-muted"), children: _jsx("tr", { className: "border-b text-left text-muted-foreground", children: columns.map((col) => (_jsx("th", { className: cn("py-1.5 font-medium", card === true && "px-3", col.align === "right" && "text-right"), children: col.header }, col.header))) }) }), _jsxs("tbody", { children: [rows.map((row, i) => (_jsx("tr", { className: "border-b last:border-0", children: columns.map((col) => (_jsx("td", { className: cn("py-1.5", card === true && "px-3", col.align === "right" && "text-right tabular-nums"), children: col.cell(row) }, col.header))) }, rowKey(row, i)))), footer?.map((row, i) => (_jsxs("tr", { className: cn(i === 0 && "border-t", row.emphasize === true && "font-semibold"), children: [_jsxs("td", { colSpan: columns.length > 1 ? Math.max(columns.length - 1, 1) : undefined, className: cn("py-1.5 text-muted-foreground", card === true && "px-3", row.emphasize === true && "text-foreground", columns.length === 1 && "flex items-center justify-between gap-4"), children: [row.label, columns.length === 1 && (_jsx("span", { className: cn("text-right tabular-nums", row.emphasize === true && "text-foreground"), children: row.value }))] }), columns.length > 1 && (_jsx("td", { className: cn("py-1.5 text-right tabular-nums", card === true && "px-3"), children: row.value }))] }, row.label)))] })] }) }));
19
19
  return card === true ? (_jsx("div", { className: "overflow-hidden rounded-lg border bg-card", children: table })) : (table);
20
20
  }
21
- /** Transponierte Vergleichstabelle: Zeile = Kennzahl, Spalte = Variante, je
22
- * Kennzahl optional die beste Spalte hervorgehoben. Für Szenario-/Angebots-
23
- * Vergleiche, wo ResultTable (Zeile=Datensatz) nicht passt. */
21
+ /** Transposed comparison table: row = metric, column = variant, with the best
22
+ * column optionally highlighted for each metric. For scenario/offer comparisons
23
+ * where ResultTable (row = record) is not suitable. */
24
24
  export function ComparisonTable({ columns, columnHeader, columnKey, metrics, metricLabel, testId, className, card, }) {
25
25
  const table = (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { "data-testid": testId, className: cn("w-full min-w-[24rem] text-sm", className), children: [_jsx("thead", { className: cn(card === true && "bg-muted"), children: _jsxs("tr", { className: "border-b text-left text-muted-foreground", children: [_jsx("th", { className: cn("py-1.5 font-medium", card === true && "px-3"), children: metricLabel }), columns.map((col, i) => (_jsx("th", { className: cn("py-1.5 text-right font-medium", card === true && "px-3"), children: columnHeader(col, i) }, columnKey(col, i))))] }) }), _jsx("tbody", { children: metrics.map((metric) => {
26
26
  const best = metric.bestIndex !== undefined ? metric.bestIndex(columns) : -1;
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
- /** Sektion mit Titel + optionalem Action-Slot (Range-Umschalter, Filter) —
3
- * ersetzt die wiederholten `<section className={CARD}>…<h2>`-Blöcke in
4
- * Custom-Screens. Dünner Wrapper über das Card-Primitive. */
2
+ /** Section with a title and optional action slot (range switcher, filter) —
3
+ * replaces repeated `<section className={CARD}>…<h2>` blocks in
4
+ * custom screens. Thin wrapper around the Card primitive. */
5
5
  export declare function SectionCard({ title, subtitle, action, footer, children, testId, }: {
6
6
  readonly title: string;
7
7
  readonly subtitle?: string;
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { usePrimitives } from "../../index.js";
3
- /** Sektion mit Titel + optionalem Action-Slot (Range-Umschalter, Filter) —
4
- * ersetzt die wiederholten `<section className={CARD}>…<h2>`-Blöcke in
5
- * Custom-Screens. Dünner Wrapper über das Card-Primitive. */
3
+ /** Section with a title and optional action slot (range switcher, filter) —
4
+ * replaces repeated `<section className={CARD}>…<h2>` blocks in
5
+ * custom screens. Thin wrapper around the Card primitive. */
6
6
  export function SectionCard({ title, subtitle, action, footer, children, testId, }) {
7
7
  const { Card } = usePrimitives();
8
8
  return (_jsx(Card, { slots: { title, subtitle, headerActions: action, footer }, testId: testId, children: _jsx("div", { className: "flex h-full flex-col gap-4", children: children }) }));
@@ -10,8 +10,8 @@ export declare function Sparkline({ points, className, }: {
10
10
  readonly points: readonly number[];
11
11
  readonly className?: string;
12
12
  }): ReactNode;
13
- /** Icon-tragende Kennzahl-Kachel mit optionalem Delta-Chip, Trend-Zeile
14
- * und Sparkline. `icon` ist ein fertiger Knoten (App liefert ihr SVG). */
13
+ /** Icon-bearing metric tile with an optional delta chip, trend line,
14
+ * and sparkline. `icon` is a ready-made node (the app supplies its SVG). */
15
15
  export declare function StatCard({ icon, label, value, sub, tone, accentColor, delta, trend, spark, testId, children, }: {
16
16
  readonly icon?: ReactNode;
17
17
  readonly label: string;
@@ -41,8 +41,8 @@ export declare function StatStripCell({ icon, label, value, sub, tone, accentCol
41
41
  readonly spark?: readonly number[];
42
42
  readonly testId?: string;
43
43
  }): ReactNode;
44
- /** Kompakte Kennzahl-Kachel (ohne Icon) — für dichte KPI-Raster.
45
- * StatCard ist die icon-tragende Variante. */
44
+ /** Compact metric tile (without an icon) — for dense KPI grids.
45
+ * StatCard is the icon-bearing variant. */
46
46
  export declare function MiniStat({ label, value, tone, emphasize, testId, labelTestId, valueTestId, }: {
47
47
  readonly label: string;
48
48
  readonly value: string;
@@ -15,8 +15,8 @@ const TONE_VALUE = {
15
15
  warn: "text-destructive",
16
16
  negative: "text-status-bad",
17
17
  };
18
- // Inline-SVG-Sparkline (kein Chart-Dep für eine 28px-Kurve): Linie +
19
- // schwacher Flächen-Verlauf, Farbe via currentColor (Caller setzt text-tone).
18
+ // Inline SVG sparkline (no chart dependency for a 28px curve): line +
19
+ // subtle area gradient, colored via currentColor (caller sets text-tone).
20
20
  export function Sparkline({ points, className, }) {
21
21
  if (points.length < 2)
22
22
  return null;
@@ -42,8 +42,8 @@ function StatIconChip({ icon, tone, accentColor, }) {
42
42
  backgroundColor: `color-mix(in srgb, ${accentColor} 12%, transparent)`,
43
43
  }, children: icon }));
44
44
  }
45
- /** Icon-tragende Kennzahl-Kachel mit optionalem Delta-Chip, Trend-Zeile
46
- * und Sparkline. `icon` ist ein fertiger Knoten (App liefert ihr SVG). */
45
+ /** Icon-bearing metric tile with an optional delta chip, trend line,
46
+ * and sparkline. `icon` is a ready-made node (the app supplies its SVG). */
47
47
  export function StatCard({ icon, label, value, sub, tone = "default", accentColor, delta, trend, spark, testId, children, }) {
48
48
  const { Card } = usePrimitives();
49
49
  // StatCard is a reusable small-tile widget (a metrics dashboard grid, not
@@ -57,8 +57,8 @@ export function StatCard({ icon, label, value, sub, tone = "default", accentColo
57
57
  export function StatStripCell({ icon, label, value, sub, tone = "default", accentColor, delta, spark, testId, }) {
58
58
  return (_jsxs("div", { "data-testid": testId, className: "flex min-w-0 flex-col gap-1 px-4 py-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-x-2 gap-y-1", children: [_jsxs("span", { className: "flex min-w-0 items-center gap-2 text-xs font-medium text-muted-foreground", children: [icon !== undefined && _jsx(StatIconChip, { icon: icon, tone: tone, accentColor: accentColor }), _jsx("span", { children: label })] }), delta !== undefined && (_jsxs("span", { className: cn("inline-flex shrink-0 items-center gap-0.5 whitespace-nowrap rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums", TONE_CHIP[delta.tone ?? tone]), children: [delta.direction === "up" ? "↑" : "↓", delta.value] }))] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: cn("text-xl font-semibold tabular-nums", TONE_VALUE[tone]), children: value }), spark !== undefined && (_jsx(Sparkline, { points: spark, className: cn("h-7 w-20 shrink-0", TONE_VALUE[tone]) }))] }), sub !== undefined && _jsx("div", { className: "text-xs text-muted-foreground", children: sub })] }));
59
59
  }
60
- /** Kompakte Kennzahl-Kachel (ohne Icon) — für dichte KPI-Raster.
61
- * StatCard ist die icon-tragende Variante. */
60
+ /** Compact metric tile (without an icon) — for dense KPI grids.
61
+ * StatCard is the icon-bearing variant. */
62
62
  export function MiniStat({ label, value, tone = "default", emphasize = false, testId, labelTestId, valueTestId, }) {
63
63
  const { Card } = usePrimitives();
64
64
  return (_jsxs(Card, { options: { padded: false }, className: cn("p-3", emphasize && "ring-1 ring-primary/30"), testId: testId, children: [_jsx("div", { className: "text-xs text-muted-foreground", "data-testid": labelTestId, children: label }), _jsx("div", { className: cn("mt-0.5 font-semibold tabular-nums", TONE_VALUE[tone], emphasize ? "text-lg" : "text-sm"), "data-testid": valueTestId, children: value })] }));
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { DispatcherError } from "../../headless/index.ts";
3
- /** Leerer-Zustand mit optionalem Icon + CTA — die dashed-Box-Optik der
4
- * entityList-Empty-States, als Standalone-Widget für Custom-Screens. */
3
+ /** Empty state with an optional icon and CTA, using the dashed-box style of
4
+ * entityList empty states as a standalone widget for custom screens. */
5
5
  export declare function EmptyState({ icon, title, description, action, testId, }: {
6
6
  readonly icon?: ReactNode;
7
7
  readonly title: string;
@@ -9,13 +9,13 @@ export declare function EmptyState({ icon, title, description, action, testId, }
9
9
  readonly action?: ReactNode;
10
10
  readonly testId?: string;
11
11
  }): ReactNode;
12
- /** Lade-Zustand: Skeleton-Zeilen in Card-Optik. `rows` steuert die Höhe. */
12
+ /** Loading state with skeleton rows styled like cards; `rows` controls the height. */
13
13
  export declare function LoadingState({ rows, className, testId, }: {
14
14
  readonly rows?: number;
15
15
  readonly className?: string;
16
16
  readonly testId?: string;
17
17
  }): ReactNode;
18
- /** Fehler-Zustand auf Basis des Banner-Primitives, mit Retry-Button. */
18
+ /** Error state based on the Banner primitive, with a retry button. */
19
19
  export declare function ErrorState({ error, onRetry, testId, }: {
20
20
  readonly error: DispatcherError;
21
21
  readonly onRetry?: () => void;
@@ -2,17 +2,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { dispatcherErrorText, usePrimitives, useTranslation } from "../../index.js";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { Skeleton } from "../ui/skeleton.js";
5
- /** Leerer-Zustand mit optionalem Icon + CTA — die dashed-Box-Optik der
6
- * entityList-Empty-States, als Standalone-Widget für Custom-Screens. */
5
+ /** Empty state with an optional icon and CTA, using the dashed-box style of
6
+ * entityList empty states as a standalone widget for custom screens. */
7
7
  export function EmptyState({ icon, title, description, action, testId, }) {
8
8
  return (_jsxs("div", { "data-testid": testId, className: "flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed px-6 py-10 text-center", children: [icon !== undefined && _jsx("div", { className: "text-muted-foreground", children: icon }), _jsx("div", { className: "text-sm font-medium", children: title }), description !== undefined && (_jsx("div", { className: "text-sm text-muted-foreground", children: description })), action !== undefined && _jsx("div", { className: "mt-2", children: action })] }));
9
9
  }
10
- /** Lade-Zustand: Skeleton-Zeilen in Card-Optik. `rows` steuert die Höhe. */
10
+ /** Loading state with skeleton rows styled like cards; `rows` controls the height. */
11
11
  export function LoadingState({ rows = 3, className, testId, }) {
12
12
  const t = useTranslation();
13
13
  return (_jsx("output", { "data-testid": testId, "aria-label": t("kumiko.widget.loading"), className: cn("flex w-full flex-col gap-2", className), children: Array.from({ length: rows }, (_, i) => (_jsx(Skeleton, { className: "h-9 w-full" }, i))) }));
14
14
  }
15
- /** Fehler-Zustand auf Basis des Banner-Primitives, mit Retry-Button. */
15
+ /** Error state based on the Banner primitive, with a retry button. */
16
16
  export function ErrorState({ error, onRetry, testId, }) {
17
17
  const { Banner, Button } = usePrimitives();
18
18
  const t = useTranslation();
@@ -1,10 +1,10 @@
1
- /** Formular-State für Rechner-Screens: ein Draft-Objekt + `patch` für
2
- * Teil-Updates + `field(name)` das die `{ id, name, value, onChange }`-Props
3
- * fertig für die Feld-Widgets (NumberField/MoneyField/PercentField) liefert.
4
- * Ersetzt das pro Screen wiederholte Draft-Interface + patch-Helper.
5
- * `idPrefix` verhindert doppelte DOM-`id`s, wenn mehrere `useDraft`-Formulare
6
- * mit gleichnamigen Feldern auf derselben Seite gemountet werden — `name`
7
- * bleibt der reine Key fürs Form-Payload. */
1
+ /** Form state for calculator screens: a draft object plus `patch` for
2
+ * partial updates, and `field(name)` that provides `{ id, name, value, onChange }`
3
+ * props ready for field widgets (NumberField/MoneyField/PercentField).
4
+ * Replaces the repeated draft interface and patch helper in each screen.
5
+ * `idPrefix` prevents duplicate DOM `id`s when multiple `useDraft` forms with
6
+ * same-named fields are mounted on the same page; `name` remains the plain key
7
+ * for the form payload. */
8
8
  export declare function useDraft<T extends object>(defaults: T, options?: {
9
9
  readonly idPrefix?: string;
10
10
  }): {
@@ -1,11 +1,11 @@
1
1
  import { useCallback, useState } from "react";
2
- /** Formular-State für Rechner-Screens: ein Draft-Objekt + `patch` für
3
- * Teil-Updates + `field(name)` das die `{ id, name, value, onChange }`-Props
4
- * fertig für die Feld-Widgets (NumberField/MoneyField/PercentField) liefert.
5
- * Ersetzt das pro Screen wiederholte Draft-Interface + patch-Helper.
6
- * `idPrefix` verhindert doppelte DOM-`id`s, wenn mehrere `useDraft`-Formulare
7
- * mit gleichnamigen Feldern auf derselben Seite gemountet werden — `name`
8
- * bleibt der reine Key fürs Form-Payload. */
2
+ /** Form state for calculator screens: a draft object plus `patch` for
3
+ * partial updates, and `field(name)` that provides `{ id, name, value, onChange }`
4
+ * props ready for field widgets (NumberField/MoneyField/PercentField).
5
+ * Replaces the repeated draft interface and patch helper in each screen.
6
+ * `idPrefix` prevents duplicate DOM `id`s when multiple `useDraft` forms with
7
+ * same-named fields are mounted on the same page; `name` remains the plain key
8
+ * for the form payload. */
9
9
  export function useDraft(defaults, options) {
10
10
  const idPrefix = options?.idPrefix;
11
11
  const [draft, setDraft] = useState(defaults);