@eifi1/ui-kit 0.22.0 → 0.23.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 (205) hide show
  1. package/README.md +42 -25
  2. package/dist/chart.d.ts +11 -8
  3. package/dist/components/amount-input.d.ts +28 -8
  4. package/dist/components/amount-input.js +3 -1
  5. package/dist/components/amount-input.js.map +1 -1
  6. package/dist/components/autocomplete.d.ts +21 -0
  7. package/dist/components/autocomplete.js +128 -103
  8. package/dist/components/autocomplete.js.map +1 -1
  9. package/dist/components/button-group.d.ts +11 -8
  10. package/dist/components/calculator.d.ts +11 -8
  11. package/dist/components/column-mapper.d.ts +182 -0
  12. package/dist/components/column-mapper.js +375 -0
  13. package/dist/components/column-mapper.js.map +1 -0
  14. package/dist/components/combobox-core.d.ts +39 -2
  15. package/dist/components/combobox-core.js +29 -6
  16. package/dist/components/combobox-core.js.map +1 -1
  17. package/dist/components/combobox.d.ts +80 -2
  18. package/dist/components/combobox.js +448 -311
  19. package/dist/components/combobox.js.map +1 -1
  20. package/dist/components/confirm-dialog.d.ts +11 -8
  21. package/dist/components/confirm-dialog.js +7 -8
  22. package/dist/components/confirm-dialog.js.map +1 -1
  23. package/dist/components/copy-button.d.ts +8 -5
  24. package/dist/components/country-select.d.ts +50 -7
  25. package/dist/components/country-select.js +65 -9
  26. package/dist/components/country-select.js.map +1 -1
  27. package/dist/components/danger-confirm.d.ts +11 -8
  28. package/dist/components/danger-confirm.js +13 -3
  29. package/dist/components/danger-confirm.js.map +1 -1
  30. package/dist/components/date-picker.d.ts +41 -0
  31. package/dist/components/date-picker.js +269 -8
  32. package/dist/components/date-picker.js.map +1 -1
  33. package/dist/components/entity-combobox.d.ts +35 -1
  34. package/dist/components/entity-combobox.js +148 -112
  35. package/dist/components/entity-combobox.js.map +1 -1
  36. package/dist/components/facing-pair.d.ts +11 -8
  37. package/dist/components/field-parts.d.ts +116 -6
  38. package/dist/components/field-parts.js +84 -0
  39. package/dist/components/field-parts.js.map +1 -1
  40. package/dist/components/field-strip.d.ts +105 -0
  41. package/dist/components/field-strip.js +46 -0
  42. package/dist/components/field-strip.js.map +1 -0
  43. package/dist/components/file-button.d.ts +11 -8
  44. package/dist/components/file-dropzone.d.ts +11 -8
  45. package/dist/components/form-actions.d.ts +10 -7
  46. package/dist/components/form-actions.js +8 -2
  47. package/dist/components/form-actions.js.map +1 -1
  48. package/dist/components/iban-input.d.ts +11 -8
  49. package/dist/components/icon-picker.d.ts +10 -1
  50. package/dist/components/icon-picker.js +12 -4
  51. package/dist/components/icon-picker.js.map +1 -1
  52. package/dist/components/language-select.d.ts +11 -8
  53. package/dist/components/money-field.d.ts +14 -8
  54. package/dist/components/money-field.js.map +1 -1
  55. package/dist/components/month-picker.js +2 -1
  56. package/dist/components/month-picker.js.map +1 -1
  57. package/dist/components/multi-entity-combobox.d.ts +26 -1
  58. package/dist/components/multi-entity-combobox.js +143 -102
  59. package/dist/components/multi-entity-combobox.js.map +1 -1
  60. package/dist/components/number-field.d.ts +11 -8
  61. package/dist/components/number-input.d.ts +11 -8
  62. package/dist/components/numpad-sheet.d.ts +11 -8
  63. package/dist/components/phone-input.d.ts +11 -8
  64. package/dist/components/reauth-dialog.d.ts +2 -2
  65. package/dist/components/reauth-dialog.js +6 -8
  66. package/dist/components/reauth-dialog.js.map +1 -1
  67. package/dist/components/series-chart.d.ts +11 -8
  68. package/dist/components/settings-fields.d.ts +11 -8
  69. package/dist/components/share-card.d.ts +10 -7
  70. package/dist/components/swatch-picker.d.ts +17 -1
  71. package/dist/components/swatch-picker.js +10 -4
  72. package/dist/components/swatch-picker.js.map +1 -1
  73. package/dist/components/text-link.d.ts +10 -7
  74. package/dist/components/tile-radio.d.ts +20 -0
  75. package/dist/components/tile-radio.js +25 -8
  76. package/dist/components/tile-radio.js.map +1 -1
  77. package/dist/components/time-input.d.ts +11 -8
  78. package/dist/components/toggle-group.js +2 -2
  79. package/dist/components/toggle-group.js.map +1 -1
  80. package/dist/components/trigger-aria.d.ts +3 -0
  81. package/dist/components/trigger-aria.js +3 -1
  82. package/dist/components/trigger-aria.js.map +1 -1
  83. package/dist/components/ui.d.ts +8 -5
  84. package/dist/components/ui.js +5 -11
  85. package/dist/components/ui.js.map +1 -1
  86. package/dist/feedback/feedback-attachment.d.ts +1 -1
  87. package/dist/feedback/feedback-attachment.js +156 -56
  88. package/dist/feedback/feedback-attachment.js.map +1 -1
  89. package/dist/feedback/feedback-dialog.d.ts +1 -1
  90. package/dist/feedback/feedback-dialog.js.map +1 -1
  91. package/dist/feedback/feedback-inbox.d.ts +3 -2
  92. package/dist/feedback/feedback-inbox.js.map +1 -1
  93. package/dist/feedback/feedback-thread.d.ts +68 -287
  94. package/dist/feedback/feedback-thread.js +8 -1
  95. package/dist/feedback/feedback-thread.js.map +1 -1
  96. package/dist/{kit-labels-R8mIAc9N.d.ts → feedback-BxeQVzwq.d.ts} +405 -22
  97. package/dist/{feedback-attachment-NhUm7Zga.d.ts → feedback-attachment-fGAzZPf0.d.ts} +112 -10
  98. package/dist/feedback.d.ts +66 -2
  99. package/dist/hooks/use-file-drop.d.ts +11 -8
  100. package/dist/i18n/defaults.d.ts +11 -8
  101. package/dist/i18n/defaults.js +3 -1
  102. package/dist/i18n/defaults.js.map +1 -1
  103. package/dist/i18n/german.d.ts +11 -8
  104. package/dist/i18n/german.js +36 -2
  105. package/dist/i18n/german.js.map +1 -1
  106. package/dist/i18n/kit-labels.d.ts +7 -4
  107. package/dist/i18n/kit-labels.js.map +1 -1
  108. package/dist/i18n/languages.d.ts +11 -8
  109. package/dist/i18n/locales/de-CH.d.ts +11 -8
  110. package/dist/i18n/locales/en.d.ts +11 -8
  111. package/dist/i18n/locales/en.js +7 -0
  112. package/dist/i18n/locales/en.js.map +1 -1
  113. package/dist/i18n/locales/es.d.ts +11 -8
  114. package/dist/i18n/locales/es.js +37 -2
  115. package/dist/i18n/locales/es.js.map +1 -1
  116. package/dist/i18n/locales/fr.d.ts +11 -8
  117. package/dist/i18n/locales/fr.js +36 -2
  118. package/dist/i18n/locales/fr.js.map +1 -1
  119. package/dist/i18n/locales/hu.d.ts +11 -8
  120. package/dist/i18n/locales/hu.js +38 -2
  121. package/dist/i18n/locales/hu.js.map +1 -1
  122. package/dist/i18n/locales/it.d.ts +11 -8
  123. package/dist/i18n/locales/it.js +37 -2
  124. package/dist/i18n/locales/it.js.map +1 -1
  125. package/dist/i18n/locales/zh.d.ts +11 -8
  126. package/dist/i18n/locales/zh.js +34 -2
  127. package/dist/i18n/locales/zh.js.map +1 -1
  128. package/dist/i18n/review.d.ts +11 -8
  129. package/dist/i18n/review.js +20 -1
  130. package/dist/i18n/review.js.map +1 -1
  131. package/dist/index.d.ts +7 -3
  132. package/dist/index.js +16 -0
  133. package/dist/index.js.map +1 -1
  134. package/dist/lib/column-mapping.d.ts +81 -0
  135. package/dist/lib/column-mapping.js +108 -0
  136. package/dist/lib/column-mapping.js.map +1 -0
  137. package/dist/lib/table-text.d.ts +109 -1
  138. package/dist/lib/table-text.js +122 -1
  139. package/dist/lib/table-text.js.map +1 -1
  140. package/dist/rhf/fields.d.ts +89 -11
  141. package/dist/rhf/fields.js +124 -0
  142. package/dist/rhf/fields.js.map +1 -1
  143. package/dist/rhf/form.d.ts +11 -8
  144. package/dist/rhf.d.ts +12 -9
  145. package/dist/rhf.js.map +1 -1
  146. package/dist/shell/app-shell.d.ts +10 -7
  147. package/dist/shell/top-bar-brand.d.ts +11 -8
  148. package/dist/shell/topbar-action-menu.d.ts +36 -3
  149. package/dist/shell/topbar-action-menu.js +74 -33
  150. package/dist/shell/topbar-action-menu.js.map +1 -1
  151. package/dist/shell.d.ts +10 -7
  152. package/dist/table-text.d.ts +1 -1
  153. package/dist/wizard/stepper-nav.d.ts +41 -10
  154. package/dist/wizard/stepper-nav.js +4 -0
  155. package/dist/wizard/stepper-nav.js.map +1 -1
  156. package/dist/wizard.d.ts +11 -8
  157. package/package.json +1 -1
  158. package/src/components/amount-input.tsx +20 -1
  159. package/src/components/autocomplete.tsx +172 -111
  160. package/src/components/column-mapper.tsx +666 -0
  161. package/src/components/combobox-core.tsx +82 -9
  162. package/src/components/combobox.tsx +614 -332
  163. package/src/components/confirm-dialog.tsx +12 -8
  164. package/src/components/country-select.tsx +135 -22
  165. package/src/components/danger-confirm.tsx +91 -12
  166. package/src/components/date-picker.tsx +423 -10
  167. package/src/components/entity-combobox.tsx +217 -126
  168. package/src/components/field-parts.tsx +224 -5
  169. package/src/components/field-strip.tsx +149 -0
  170. package/src/components/form-actions.tsx +32 -4
  171. package/src/components/icon-picker.tsx +23 -4
  172. package/src/components/money-field.tsx +3 -0
  173. package/src/components/month-picker.tsx +2 -1
  174. package/src/components/multi-entity-combobox.tsx +207 -120
  175. package/src/components/reauth-dialog.tsx +17 -18
  176. package/src/components/swatch-picker.tsx +29 -5
  177. package/src/components/tile-radio.tsx +74 -13
  178. package/src/components/toggle-group.tsx +2 -2
  179. package/src/components/trigger-aria.ts +5 -0
  180. package/src/components/ui.tsx +7 -33
  181. package/src/feedback/feedback-attachment.tsx +308 -61
  182. package/src/feedback/feedback-dialog.tsx +7 -3
  183. package/src/feedback/feedback-inbox.tsx +3 -2
  184. package/src/feedback/feedback-thread.tsx +47 -4
  185. package/src/i18n/defaults.ts +2 -0
  186. package/src/i18n/german.ts +42 -0
  187. package/src/i18n/kit-labels.tsx +4 -0
  188. package/src/i18n/locales/en.ts +27 -5
  189. package/src/i18n/locales/es.ts +41 -0
  190. package/src/i18n/locales/fr.ts +42 -0
  191. package/src/i18n/locales/hu.ts +37 -0
  192. package/src/i18n/locales/it.ts +41 -0
  193. package/src/i18n/locales/zh.ts +32 -0
  194. package/src/i18n/review.ts +19 -0
  195. package/src/index.ts +18 -0
  196. package/src/lib/column-mapping.ts +234 -0
  197. package/src/lib/table-text.ts +271 -0
  198. package/src/rhf/fields.tsx +254 -0
  199. package/src/rhf.ts +2 -1
  200. package/src/shell/topbar-action-menu.tsx +134 -38
  201. package/src/wizard/stepper-nav.tsx +35 -1
  202. package/dist/components/field-anatomy.d.ts +0 -95
  203. package/dist/components/field-anatomy.js +0 -84
  204. package/dist/components/field-anatomy.js.map +0 -1
  205. package/src/components/field-anatomy.tsx +0 -190
@@ -6,6 +6,8 @@ import { cn } from "../lib/cn.js";
6
6
  import { FieldChevron, FieldLabel, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from "./ui.js";
7
7
  import {
8
8
  ComboboxPanel,
9
+ endHintRowProps,
10
+ offersCreate,
9
11
  useComboboxCore,
10
12
  useComboboxFieldError
11
13
  } from "./combobox-core.js";
@@ -15,42 +17,59 @@ import {
15
17
  useKitLabels,
16
18
  useKitLocale
17
19
  } from "../i18n/kit-labels.js";
18
- function MultiEntityCombobox({
19
- value,
20
- onChange,
21
- options,
22
- loadOptions,
23
- loading,
24
- label,
25
- placeholder,
26
- searchPlaceholder,
27
- emptyLabel,
28
- itemLabel,
29
- clearable,
30
- clearLabel,
31
- closeLabel,
32
- disabled,
33
- onCreate,
34
- createLabel,
35
- className,
36
- invalid,
37
- error,
38
- filter,
39
- minChars,
40
- debounceMs,
41
- loadErrorLabel,
42
- "aria-label": ariaLabel,
43
- // The control's own wiring, taken off `rest` so it lands on the TRIGGER rather than
44
- // the wrapper: `Field`'s render-prop spreads `{ id, aria-describedby, aria-invalid,
45
- // aria-required }`, and on the role-less wrapper div the label's `htmlFor` named
46
- // nothing and the hint and required state described nothing — kastlan's
47
- // communication-page To/Cc/Bcc and lease-tenants-step.tsx read as unnamed pickers.
48
- id,
49
- "aria-describedby": ariaDescribedBy,
50
- "aria-invalid": ariaInvalid,
51
- "aria-required": ariaRequired,
52
- ...rest
53
- }) {
20
+ import {
21
+ EndHintRow,
22
+ FieldCaption,
23
+ LABEL_IN_ROW,
24
+ LockedReason,
25
+ StaticLabelRow,
26
+ useFieldHint,
27
+ useLockReason
28
+ } from "./field-parts.js";
29
+ import { mergeDescribedBy } from "./choice-parts.js";
30
+ import { useCommitReason } from "./write-lock.js";
31
+ function MultiEntityCombobox(props) {
32
+ const {
33
+ value,
34
+ onChange,
35
+ options,
36
+ loadOptions,
37
+ loading,
38
+ label,
39
+ placeholder,
40
+ searchPlaceholder,
41
+ emptyLabel,
42
+ itemLabel,
43
+ clearable,
44
+ clearLabel,
45
+ closeLabel,
46
+ disabled,
47
+ disabledReason,
48
+ commit,
49
+ onCreate,
50
+ createLabel,
51
+ createEmptyLabel,
52
+ createCommit,
53
+ className,
54
+ invalid,
55
+ error,
56
+ hint,
57
+ filter,
58
+ minChars,
59
+ debounceMs,
60
+ loadErrorLabel,
61
+ "aria-label": ariaLabel,
62
+ // The control's own wiring, taken off `rest` so it lands on the TRIGGER rather than
63
+ // the wrapper: `Field`'s render-prop spreads `{ id, aria-describedby, aria-invalid,
64
+ // aria-required }`, and on the role-less wrapper div the label's `htmlFor` named
65
+ // nothing and the hint and required state described nothing — kastlan's
66
+ // communication-page To/Cc/Bcc and lease-tenants-step.tsx read as unnamed pickers.
67
+ id,
68
+ "aria-describedby": ariaDescribedBy,
69
+ "aria-invalid": ariaInvalid,
70
+ "aria-required": ariaRequired,
71
+ ...rest
72
+ } = props;
54
73
  const core = useComboboxCore({
55
74
  options,
56
75
  loadOptions,
@@ -59,10 +78,11 @@ function MultiEntityCombobox({
59
78
  minChars,
60
79
  debounceMs
61
80
  });
81
+ const hintParts = useFieldHint(hint, ariaDescribedBy);
62
82
  const field = useComboboxFieldError(
63
83
  error,
64
84
  invalid || ariaInvalid === true || ariaInvalid === "true",
65
- ariaDescribedBy
85
+ hintParts.describedBy
66
86
  );
67
87
  const labels = useKitLabels("combobox", DEFAULT_COMBOBOX_LABELS, {
68
88
  search: searchPlaceholder,
@@ -72,6 +92,10 @@ function MultiEntityCombobox({
72
92
  });
73
93
  const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
74
94
  const { open, results, resolve, setOpen, query, triggerRef } = core;
95
+ const lock = useLockReason(commit, disabledReason);
96
+ const inert = lock.locked || Boolean(disabled);
97
+ if (lock.locked && open) setOpen(false);
98
+ const createReason = useCommitReason(createCommit, void 0);
75
99
  const listboxId = useId();
76
100
  const valueSet = useMemo(() => new Set(value), [value]);
77
101
  const locale = useKitLocale();
@@ -85,10 +109,17 @@ function MultiEntityCombobox({
85
109
  const chosen = value.map(resolve);
86
110
  return chosen.every(Boolean) ? listFormat.format(chosen.map((o) => o.label)) : labels.selectedCount(value.length);
87
111
  })();
112
+ const withLock = (trigger) => lock.locked ? /* @__PURE__ */ jsx(LockedReason, { lock, className: "block", children: trigger }) : trigger;
88
113
  const q = query.trim();
89
- const showCreate = Boolean(onCreate) && q.length > 0 && !results.some((o) => o.label.toLowerCase() === q.toLowerCase());
90
- const showClear = Boolean(clearable && value.length > 0 && !disabled);
114
+ const showCreate = offersCreate(
115
+ onCreate,
116
+ q,
117
+ results.map((o) => o.label),
118
+ createEmptyLabel
119
+ );
120
+ const showClear = Boolean(clearable && value.length > 0 && !inert);
91
121
  const toggle = (o) => {
122
+ if (lock.locked) return;
92
123
  core.rememberOption(o);
93
124
  if (valueSet.has(o.value)) onChange(value.filter((v) => v !== o.value));
94
125
  else onChange([...value, o.value]);
@@ -99,74 +130,81 @@ function MultiEntityCombobox({
99
130
  // has one. Spread FIRST so the trigger's ARIA and the
100
131
  // handlers that open the panel cannot be clobbered from outside.
101
132
  /* @__PURE__ */ jsxs("div", { ...rest, className: cn("relative", className), children: [
102
- label !== void 0 && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
103
- /* @__PURE__ */ jsxs(
104
- "button",
105
- {
106
- ref: triggerRef,
107
- id,
108
- type: "button",
109
- role: "combobox",
110
- "aria-expanded": open,
111
- "aria-controls": listboxId,
112
- "aria-haspopup": "listbox",
113
- "aria-label": ariaLabel ?? (typeof label === "string" ? common.fieldValue(label, summary) : void 0),
114
- disabled,
115
- "aria-invalid": field.isInvalid || void 0,
116
- "aria-describedby": field.describedBy,
117
- "aria-required": ariaRequired,
118
- onClick: () => !disabled && setOpen((o) => !o),
119
- onKeyDown: (e) => {
120
- if (disabled) return;
121
- if (e.key === "ArrowDown" || e.key === "ArrowUp") {
122
- e.preventDefault();
123
- setOpen(true);
124
- }
125
- },
126
- className: cn(
127
- FIELD_TRIGGER,
128
- "pe-9",
129
- label !== void 0 && FIELD_FLOATING_PAD,
130
- disabled && "cursor-not-allowed opacity-50",
131
- field.isInvalid && FIELD_INVALID
132
- ),
133
- children: [
134
- /* @__PURE__ */ jsx(
135
- "span",
136
- {
137
- className: cn(
138
- "min-w-0 truncate",
139
- // Inherit FIELD_BASE's ink for a value, keep the placeholder tone
140
- // (`--text-placeholder`) — the same rule every field on a form row
141
- // follows (Keksdose dev#477).
142
- !value.length && "text-[var(--text-placeholder)]"
143
- ),
144
- children: summary
133
+ label !== void 0 && hintParts.labelHint === void 0 && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
134
+ /* @__PURE__ */ jsx(EndHintRow, { ...endHintRowProps("hint" in props, label !== void 0, hintParts.labelHint), children: withLock(
135
+ /* @__PURE__ */ jsxs(
136
+ "button",
137
+ {
138
+ ref: triggerRef,
139
+ id,
140
+ type: "button",
141
+ role: "combobox",
142
+ "aria-expanded": open,
143
+ "aria-controls": listboxId,
144
+ "aria-haspopup": "listbox",
145
+ "aria-label": ariaLabel ?? (typeof label === "string" ? common.fieldValue(label, summary) : void 0),
146
+ disabled: lock.locked ? void 0 : disabled,
147
+ "aria-disabled": lock.locked || void 0,
148
+ "aria-invalid": field.isInvalid || void 0,
149
+ "aria-describedby": mergeDescribedBy(field.describedBy, lock.locked && lock.reasonId),
150
+ "aria-required": ariaRequired,
151
+ onClick: () => !inert && setOpen((o) => !o),
152
+ onKeyDown: (e) => {
153
+ if (inert) return;
154
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
155
+ e.preventDefault();
156
+ setOpen(true);
157
+ } else if (showClear && !open && (e.key === "Delete" || e.key === "Backspace")) {
158
+ e.preventDefault();
159
+ onChange([]);
145
160
  }
161
+ },
162
+ className: cn(
163
+ FIELD_TRIGGER,
164
+ "pe-9",
165
+ label !== void 0 && FIELD_FLOATING_PAD,
166
+ inert && "cursor-not-allowed opacity-50",
167
+ field.isInvalid && FIELD_INVALID
146
168
  ),
147
- showClear ? (
148
- /* eslint-disable-next-line jsx-a11y/click-events-have-key-events -- tabIndex -1 inside
149
- the trigger <button>, so it never holds focus and a key handler here could
150
- never fire. A pointer shortcut; the keyboard path is unticking the options
151
- in the open list. */
169
+ children: [
152
170
  /* @__PURE__ */ jsx(
153
171
  "span",
154
172
  {
155
- role: "button",
156
- tabIndex: -1,
157
- "aria-label": labels.clear,
158
- onClick: (e) => {
159
- e.stopPropagation();
160
- onChange([]);
161
- },
162
- className: "absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-[var(--text-placeholder)] hover:text-[var(--text-secondary)]",
163
- children: /* @__PURE__ */ jsx(X, { className: "size-4" })
173
+ className: cn(
174
+ "min-w-0 truncate",
175
+ // Inherit FIELD_BASE's ink for a value, keep the placeholder tone
176
+ // (`--text-placeholder`) — the same rule every field on a form row
177
+ // follows (Keksdose dev#477).
178
+ !value.length && "text-[var(--text-placeholder)]"
179
+ ),
180
+ children: summary
164
181
  }
165
- )
166
- ) : /* @__PURE__ */ jsx(FieldChevron, {})
167
- ]
168
- }
169
- ),
182
+ ),
183
+ showClear ? (
184
+ /* eslint-disable-next-line jsx-a11y/click-events-have-key-events -- tabIndex -1 inside
185
+ the trigger <button>, so it never holds focus and a key handler here could
186
+ never fire. A pointer shortcut; the keyboard paths are Delete on the closed
187
+ trigger and unticking the options in the open list. */
188
+ /* @__PURE__ */ jsx(
189
+ "span",
190
+ {
191
+ role: "button",
192
+ tabIndex: -1,
193
+ "aria-label": labels.clear,
194
+ onClick: (e) => {
195
+ e.stopPropagation();
196
+ onChange([]);
197
+ },
198
+ className: "absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-[var(--text-placeholder)] hover:text-[var(--text-secondary)]",
199
+ children: /* @__PURE__ */ jsx(X, { className: "size-4" })
200
+ }
201
+ )
202
+ ) : /* @__PURE__ */ jsx(FieldChevron, {})
203
+ ]
204
+ }
205
+ )
206
+ ) }),
207
+ label !== void 0 && hintParts.labelHint !== void 0 && /* @__PURE__ */ jsx(StaticLabelRow, { hint: hintParts.labelHint, children: /* @__PURE__ */ jsx(FieldLabel, { className: LABEL_IN_ROW, children: label }) }),
170
208
  /* @__PURE__ */ jsx(
171
209
  ComboboxPanel,
172
210
  {
@@ -182,12 +220,15 @@ function MultiEntityCombobox({
182
220
  onChoose: toggle,
183
221
  showCreate,
184
222
  onCreate: () => {
223
+ if (lock.locked) return;
185
224
  onCreate?.(q);
186
225
  core.setQuery("");
187
226
  },
188
- createContent: labels.create(q)
227
+ createContent: q ? labels.create(q) : createEmptyLabel,
228
+ createDisabledReason: createReason
189
229
  }
190
230
  ),
231
+ /* @__PURE__ */ jsx(FieldCaption, { parts: hintParts }),
191
232
  field.errorEl
192
233
  ] })
193
234
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/multi-entity-combobox.tsx"],"sourcesContent":["import { useId, useMemo, type ComponentPropsWithoutRef, type ReactNode } from \"react\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { FieldChevron, FieldLabel, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from \"./ui\";\nimport {\n ComboboxPanel,\n useComboboxCore,\n useComboboxFieldError,\n type ComboOption,\n} from \"./combobox-core\";\nimport {\n DEFAULT_COMBOBOX_LABELS,\n DEFAULT_COMMON_LABELS,\n useKitLabels,\n useKitLocale,\n} from \"../i18n/kit-labels\";\n\n/** `onChange` is the kit's — \"a selection was made\", carrying values — rather\n * than the div's form event, so the DOM's spelling of it is omitted. */\nexport interface MultiEntityComboboxProps<V extends string | number>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n /** Selected ids. */\n value: V[];\n onChange: (value: V[]) => void;\n /** Already-loaded options (client-side filtered); also resolves selected labels. */\n options?: ComboOption<V>[];\n /** Async option source, debounced + race-safe; a rejection shows\n * `loadErrorLabel`. When set, `options` resolves labels only. */\n loadOptions?: (query: string) => Promise<ComboOption<V>[]>;\n loading?: boolean;\n label?: ReactNode;\n placeholder?: string;\n searchPlaceholder?: string;\n emptyLabel?: string;\n /** Trigger summary when 1+ selected (default: the labels as a locale-formatted\n * list, or `combobox.selectedCount` when a label can't be resolved). */\n itemLabel?: (count: number) => string;\n clearable?: boolean;\n clearLabel?: string;\n /** The phone sheet's close button. Its own prop rather than a reuse of\n * `clearLabel`: \"clear the selection\" and \"close this screen\" are different\n * actions, and on a full-screen sheet the close button is the only way out —\n * so it is the one control here that MUST be in the reader's language. */\n closeLabel?: string;\n disabled?: boolean;\n /** When set, a \"create\" row appears for a non-empty query with no exact match.\n * The panel stays open (adding the new entity to `value` is the caller's job). */\n onCreate?: (query: string) => void;\n createLabel?: (query: string) => string;\n /** Required and unanswered — {@link FIELD_INVALID}. See {@link Input}'s `invalid`. */\n invalid?: boolean;\n /** What is wrong with the value, as {@link Input}'s `error`: rendered under the\n * field, on the trigger's `aria-describedby`, and implies `invalid`. */\n error?: ReactNode;\n /** Narrow `options` client-side by the query. Default `true`; `false` shows them\n * as given (a server-ranked list). */\n filter?: boolean;\n /** Offer nothing, and call no `loadOptions`, below this many characters. Default\n * `0`, i.e. the list loads as the panel opens. */\n minChars?: number;\n /** `loadOptions` debounce. Default 150 ms. */\n debounceMs?: number;\n /** Shown when `loadOptions` rejects. Default: `combobox.loadError`. */\n loadErrorLabel?: string;\n}\n\n/**\n * Multi-value sibling of {@link EntityCombobox}: pick several entities by search,\n * with the same async `loadOptions`/`onCreate` support. Rows show a checkbox and\n * toggle without closing the panel; the trigger summarises the selection.\n */\nexport function MultiEntityCombobox<V extends string | number>({\n value,\n onChange,\n options,\n loadOptions,\n loading,\n label,\n placeholder,\n searchPlaceholder,\n emptyLabel,\n itemLabel,\n clearable,\n clearLabel,\n closeLabel,\n disabled,\n onCreate,\n createLabel,\n className,\n invalid,\n error,\n filter,\n minChars,\n debounceMs,\n loadErrorLabel,\n \"aria-label\": ariaLabel,\n // The control's own wiring, taken off `rest` so it lands on the TRIGGER rather than\n // the wrapper: `Field`'s render-prop spreads `{ id, aria-describedby, aria-invalid,\n // aria-required }`, and on the role-less wrapper div the label's `htmlFor` named\n // nothing and the hint and required state described nothing — kastlan's\n // communication-page To/Cc/Bcc and lease-tenants-step.tsx read as unnamed pickers.\n id,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n \"aria-required\": ariaRequired,\n ...rest\n}: MultiEntityComboboxProps<V>) {\n const core = useComboboxCore<V>({\n options,\n loadOptions,\n loading,\n filter,\n minChars,\n debounceMs,\n });\n const field = useComboboxFieldError(\n error,\n invalid || ariaInvalid === true || ariaInvalid === \"true\",\n ariaDescribedBy,\n );\n // The props are the per-instance overrides, the provider the app-wide ones; a\n // prop left `undefined` falls through to the provider rather than masking it.\n const labels = useKitLabels(\"combobox\", DEFAULT_COMBOBOX_LABELS, {\n search: searchPlaceholder,\n noResults: emptyLabel,\n clear: clearLabel,\n create: createLabel,\n });\n const common = useKitLabels(\"common\", DEFAULT_COMMON_LABELS);\n const { open, results, resolve, setOpen, query, triggerRef } = core;\n // One id per instance, generated here rather than in the core: `aria-controls` on\n // the trigger has to name the list while the list is still closed, so the id\n // belongs to whoever renders both ends of it.\n const listboxId = useId();\n\n const valueSet = useMemo(() => new Set(value), [value]);\n // A list of NAMES, not a sentence, so the narrow conjunction: English gets\n // \"Food, Rent, Travel\" (no \"and\" squeezed into a truncating trigger), German and\n // French still get their \"und\"/\"et\" where the language insists on it, and Japanese\n // and Chinese get the ideographic comma \"、\". The `unit` type looked like the\n // natural fit for a summary, but in ja/zh it concatenates the names with nothing\n // between them at all.\n const locale = useKitLocale();\n const listFormat = useMemo(\n () => new Intl.ListFormat(locale, { type: \"conjunction\", style: \"narrow\" }),\n [locale],\n );\n const summary = (() => {\n if (value.length === 0) return placeholder ?? \"\";\n if (itemLabel) return itemLabel(value.length);\n const chosen = value.map(resolve);\n return chosen.every(Boolean)\n ? listFormat.format(chosen.map((o) => o!.label))\n : labels.selectedCount(value.length);\n })();\n\n const q = query.trim();\n const showCreate =\n Boolean(onCreate) && q.length > 0 && !results.some((o) => o.label.toLowerCase() === q.toLowerCase());\n const showClear = Boolean(clearable && value.length > 0 && !disabled);\n\n const toggle = (o: ComboOption<V>) => {\n core.rememberOption(o);\n if (valueSet.has(o.value)) onChange(value.filter((v) => v !== o.value));\n else onChange([...value, o.value]);\n // Stay open — multi-select keeps adding.\n };\n\n return (\n // `rest` dresses the wrapper, which has no role; the accessible NAME — and the\n // id, description, invalid and required state above — go on the trigger, which\n // has one. Spread FIRST so the trigger's ARIA and the\n // handlers that open the panel cannot be clobbered from outside.\n <div {...rest} className={cn(\"relative\", className)}>\n {label !== undefined && <FieldLabel>{label}</FieldLabel>}\n <button\n ref={triggerRef}\n id={id}\n type=\"button\"\n // A combobox, not a button. The distinction is not pedantry: this control\n // carried `aria-invalid`, which `button` does not support, so a required\n // field left empty painted a rose border and told a reader nothing at all —\n // and ESLint flagged it as exactly that (`role-supports-aria-props`). The\n // fix the audit asked for is the role that describes what this IS: a closed\n // choice that expands into the list named below. `combobox` supports\n // `aria-invalid`, so the border and the announcement finally agree.\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n // The label is a floating <span>, not a <label for>, so without this the\n // trigger's accessible name is whatever value happens to be selected —\n // \"Checking\" with nothing saying it is the account. The label AND the\n // value, because `aria-label` replaces the content rather than adding to\n // it, and a control that announces only its name has lost the answer.\n // A caller's own name wins over the composition: two fields labelled\n // \"Account\" on a transfer form are the from and the to, and only the\n // caller knows which is which.\n aria-label={\n ariaLabel ??\n (typeof label === \"string\" ? common.fieldValue(label, summary) : undefined)\n }\n disabled={disabled}\n aria-invalid={field.isInvalid || undefined}\n aria-describedby={field.describedBy}\n aria-required={ariaRequired}\n onClick={() => !disabled && setOpen((o) => !o)}\n // Down/Up opens the list from the closed trigger, per the APG. Enter and\n // Space already do it through the button's own click.\n onKeyDown={(e) => {\n if (disabled) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n setOpen(true);\n }\n }}\n className={cn(\n FIELD_TRIGGER,\n \"pe-9\",\n label !== undefined && FIELD_FLOATING_PAD,\n disabled && \"cursor-not-allowed opacity-50\",\n field.isInvalid && FIELD_INVALID,\n )}\n >\n <span\n className={cn(\n \"min-w-0 truncate\",\n // Inherit FIELD_BASE's ink for a value, keep the placeholder tone\n // (`--text-placeholder`) — the same rule every field on a form row\n // follows (Keksdose dev#477).\n !value.length && \"text-[var(--text-placeholder)]\",\n )}\n >\n {summary}\n </span>\n {showClear ? (\n /* eslint-disable-next-line jsx-a11y/click-events-have-key-events -- tabIndex -1 inside\n the trigger <button>, so it never holds focus and a key handler here could\n never fire. A pointer shortcut; the keyboard path is unticking the options\n in the open list. */\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label={labels.clear}\n onClick={(e) => {\n e.stopPropagation();\n onChange([]);\n }}\n className=\"absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-[var(--text-placeholder)] hover:text-[var(--text-secondary)]\"\n >\n <X className=\"size-4\" />\n </span>\n ) : (\n <FieldChevron />\n )}\n </button>\n <ComboboxPanel\n core={core}\n listboxId={listboxId}\n multi\n // On a phone the panel becomes a full-screen sheet, which needs the field's\n // own label to say what it is asking for (live #200).\n sheetTitle={label ?? placeholder}\n searchPlaceholder={labels.search}\n emptyLabel={labels.noResults}\n closeLabel={closeLabel}\n loadErrorLabel={loadErrorLabel}\n isSelected={(v) => valueSet.has(v)}\n onChoose={toggle}\n showCreate={showCreate}\n onCreate={() => {\n onCreate?.(q);\n core.setQuery(\"\");\n }}\n createContent={labels.create(q)}\n />\n {field.errorEl}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/multi-entity-combobox.tsx"],"sourcesContent":["import { useId, useMemo, type ComponentPropsWithoutRef, type ReactNode } from \"react\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { FieldChevron, FieldLabel, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from \"./ui\";\nimport {\n ComboboxPanel,\n endHintRowProps,\n offersCreate,\n useComboboxCore,\n useComboboxFieldError,\n type ComboOption,\n} from \"./combobox-core\";\nimport {\n DEFAULT_COMBOBOX_LABELS,\n DEFAULT_COMMON_LABELS,\n useKitLabels,\n useKitLocale,\n} from \"../i18n/kit-labels\";\nimport {\n EndHintRow,\n FieldCaption,\n LABEL_IN_ROW,\n LockedReason,\n StaticLabelRow,\n useFieldHint,\n useLockReason,\n} from \"./field-parts\";\nimport { mergeDescribedBy } from \"./choice-parts\";\nimport { useCommitReason } from \"./write-lock\";\n\n/** `onChange` is the kit's — \"a selection was made\", carrying values — rather\n * than the div's form event, so the DOM's spelling of it is omitted. */\nexport interface MultiEntityComboboxProps<V extends string | number>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n /** Selected ids. */\n value: V[];\n onChange: (value: V[]) => void;\n /** Already-loaded options (client-side filtered); also resolves selected labels. */\n options?: ComboOption<V>[];\n /** Async option source, debounced + race-safe; a rejection shows\n * `loadErrorLabel`. When set, `options` resolves labels only. */\n loadOptions?: (query: string) => Promise<ComboOption<V>[]>;\n loading?: boolean;\n label?: ReactNode;\n placeholder?: string;\n searchPlaceholder?: string;\n emptyLabel?: string;\n /** Trigger summary when 1+ selected (default: the labels as a locale-formatted\n * list, or `combobox.selectedCount` when a label can't be resolved). */\n itemLabel?: (count: number) => string;\n /** Offer a clear \"×\" while anything is chosen; it emits `[]`. A pointer shortcut out\n * of the tab order — the keyboard's way is Delete or Backspace on the CLOSED trigger,\n * or unticking rows in the open list. Not offered while `disabled` or locked. */\n clearable?: boolean;\n clearLabel?: string;\n /** The phone sheet's close button. Its own prop rather than a reuse of\n * `clearLabel`: \"clear the selection\" and \"close this screen\" are different\n * actions, and on a full-screen sheet the close button is the only way out —\n * so it is the one control here that MUST be in the reader's language. */\n closeLabel?: string;\n disabled?: boolean;\n /** Why the selection cannot be changed — {@link EntityCombobox}'s `disabledReason`:\n * focusable and `aria-disabled`, no list, no clear, no `onChange`, the reason in the\n * kit {@link Tooltip}. Wins over `disabled`. */\n disabledReason?: ReactNode;\n /** This picker COMMITS — toggling saves. Locked the `disabledReason` way under a\n * locked {@link WriteLockProvider}. See {@link EntityCombobox}'s `commit`. */\n commit?: boolean;\n /** When set, a \"create\" row appears for a non-empty query with no exact match.\n * The panel stays open (adding the new entity to `value` is the caller's job). */\n onCreate?: (query: string) => void;\n createLabel?: (query: string) => string;\n /** Offer the create row with nothing typed too, worded as this. See\n * {@link EntityCombobox}'s `createEmptyLabel`. */\n createEmptyLabel?: string;\n /** The create row is a write while toggling is not: locked on its own under a locked\n * {@link WriteLockProvider}. See {@link EntityCombobox}'s `createCommit`. */\n createCommit?: boolean;\n /** Required and unanswered — {@link FIELD_INVALID}. See {@link Input}'s `invalid`. */\n invalid?: boolean;\n /** What is wrong with the value, as {@link Input}'s `error`: rendered under the\n * field, on the trigger's `aria-describedby`, and implies `invalid`. */\n error?: ReactNode;\n /**\n * Standing advice — the rest of the Combobox family's `hint` since 0.22, which this\n * one was left without (keksdose K4): plain TEXT is a caption under the field on the\n * trigger's `aria-describedby`, before any error; a {@link FieldHint} \"?\" rides the\n * label line, or with no label sits at the trigger's end edge, outside the box.\n * Passed at all — even `undefined` — the field keeps one box, so a hint coming and\n * going never rebuilds the trigger under the cursor (the 0.22 rule).\n */\n hint?: ReactNode;\n /** Narrow `options` client-side by the query. Default `true`; `false` shows them\n * as given (a server-ranked list). */\n filter?: boolean;\n /** Offer nothing, and call no `loadOptions`, below this many characters. Default\n * `0`, i.e. the list loads as the panel opens. */\n minChars?: number;\n /** `loadOptions` debounce. Default 150 ms. */\n debounceMs?: number;\n /** Shown when `loadOptions` rejects. Default: `combobox.loadError`. */\n loadErrorLabel?: string;\n}\n\n/**\n * Multi-value sibling of {@link EntityCombobox}: pick several entities by search,\n * with the same async `loadOptions`/`onCreate` support. Rows show a checkbox and\n * toggle without closing the panel; the trigger summarises the selection.\n */\nexport function MultiEntityCombobox<V extends string | number>(props: MultiEntityComboboxProps<V>) {\n const {\n value,\n onChange,\n options,\n loadOptions,\n loading,\n label,\n placeholder,\n searchPlaceholder,\n emptyLabel,\n itemLabel,\n clearable,\n clearLabel,\n closeLabel,\n disabled,\n disabledReason,\n commit,\n onCreate,\n createLabel,\n createEmptyLabel,\n createCommit,\n className,\n invalid,\n error,\n hint,\n filter,\n minChars,\n debounceMs,\n loadErrorLabel,\n \"aria-label\": ariaLabel,\n // The control's own wiring, taken off `rest` so it lands on the TRIGGER rather than\n // the wrapper: `Field`'s render-prop spreads `{ id, aria-describedby, aria-invalid,\n // aria-required }`, and on the role-less wrapper div the label's `htmlFor` named\n // nothing and the hint and required state described nothing — kastlan's\n // communication-page To/Cc/Bcc and lease-tenants-step.tsx read as unnamed pickers.\n id,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n \"aria-required\": ariaRequired,\n ...rest\n } = props;\n const core = useComboboxCore<V>({\n options,\n loadOptions,\n loading,\n filter,\n minChars,\n debounceMs,\n });\n const hintParts = useFieldHint(hint, ariaDescribedBy);\n const field = useComboboxFieldError(\n error,\n invalid || ariaInvalid === true || ariaInvalid === \"true\",\n hintParts.describedBy,\n );\n // The props are the per-instance overrides, the provider the app-wide ones; a\n // prop left `undefined` falls through to the provider rather than masking it.\n const labels = useKitLabels(\"combobox\", DEFAULT_COMBOBOX_LABELS, {\n search: searchPlaceholder,\n noResults: emptyLabel,\n clear: clearLabel,\n create: createLabel,\n });\n const common = useKitLabels(\"common\", DEFAULT_COMMON_LABELS);\n const { open, results, resolve, setOpen, query, triggerRef } = core;\n // The lock — see EntityCombobox: the trigger stays reachable and says why.\n const lock = useLockReason(commit, disabledReason);\n const inert = lock.locked || Boolean(disabled);\n if (lock.locked && open) setOpen(false);\n const createReason = useCommitReason(createCommit, undefined);\n // One id per instance, generated here rather than in the core: `aria-controls` on\n // the trigger has to name the list while the list is still closed, so the id\n // belongs to whoever renders both ends of it.\n const listboxId = useId();\n\n const valueSet = useMemo(() => new Set(value), [value]);\n // A list of NAMES, not a sentence, so the narrow conjunction: English gets\n // \"Food, Rent, Travel\" (no \"and\" squeezed into a truncating trigger), German and\n // French still get their \"und\"/\"et\" where the language insists on it, and Japanese\n // and Chinese get the ideographic comma \"、\". The `unit` type looked like the\n // natural fit for a summary, but in ja/zh it concatenates the names with nothing\n // between them at all.\n const locale = useKitLocale();\n const listFormat = useMemo(\n () => new Intl.ListFormat(locale, { type: \"conjunction\", style: \"narrow\" }),\n [locale],\n );\n const summary = (() => {\n if (value.length === 0) return placeholder ?? \"\";\n if (itemLabel) return itemLabel(value.length);\n const chosen = value.map(resolve);\n return chosen.every(Boolean)\n ? listFormat.format(chosen.map((o) => o!.label))\n : labels.selectedCount(value.length);\n })();\n\n // While locked the trigger sits in the reason's Tooltip, as on EntityCombobox.\n const withLock = (trigger: ReactNode) =>\n lock.locked ? (\n <LockedReason lock={lock} className=\"block\">\n {trigger}\n </LockedReason>\n ) : (\n trigger\n );\n\n const q = query.trim();\n const showCreate = offersCreate(\n onCreate,\n q,\n results.map((o) => o.label),\n createEmptyLabel,\n );\n const showClear = Boolean(clearable && value.length > 0 && !inert);\n\n const toggle = (o: ComboOption<V>) => {\n if (lock.locked) return;\n core.rememberOption(o);\n if (valueSet.has(o.value)) onChange(value.filter((v) => v !== o.value));\n else onChange([...value, o.value]);\n // Stay open — multi-select keeps adding.\n };\n\n return (\n // `rest` dresses the wrapper, which has no role; the accessible NAME — and the\n // id, description, invalid and required state above — go on the trigger, which\n // has one. Spread FIRST so the trigger's ARIA and the\n // handlers that open the panel cannot be clobbered from outside.\n <div {...rest} className={cn(\"relative\", className)}>\n {label !== undefined && hintParts.labelHint === undefined && <FieldLabel>{label}</FieldLabel>}\n <EndHintRow {...endHintRowProps(\"hint\" in props, label !== undefined, hintParts.labelHint)}>\n {withLock(\n <button\n ref={triggerRef}\n id={id}\n type=\"button\"\n // A combobox, not a button. The distinction is not pedantry: this control\n // carried `aria-invalid`, which `button` does not support, so a required\n // field left empty painted a rose border and told a reader nothing at all —\n // and ESLint flagged it as exactly that (`role-supports-aria-props`). The\n // fix the audit asked for is the role that describes what this IS: a closed\n // choice that expands into the list named below. `combobox` supports\n // `aria-invalid`, so the border and the announcement finally agree.\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n // The label is a floating <span>, not a <label for>, so without this the\n // trigger's accessible name is whatever value happens to be selected —\n // \"Checking\" with nothing saying it is the account. The label AND the\n // value, because `aria-label` replaces the content rather than adding to\n // it, and a control that announces only its name has lost the answer.\n // A caller's own name wins over the composition: two fields labelled\n // \"Account\" on a transfer form are the from and the to, and only the\n // caller knows which is which.\n aria-label={\n ariaLabel ??\n (typeof label === \"string\" ? common.fieldValue(label, summary) : undefined)\n }\n // Focusable while locked — see EntityCombobox.\n disabled={lock.locked ? undefined : disabled}\n aria-disabled={lock.locked || undefined}\n aria-invalid={field.isInvalid || undefined}\n aria-describedby={mergeDescribedBy(field.describedBy, lock.locked && lock.reasonId)}\n aria-required={ariaRequired}\n onClick={() => !inert && setOpen((o) => !o)}\n // Down/Up opens the list from the closed trigger, per the APG. Enter and\n // Space already do it through the button's own click.\n onKeyDown={(e) => {\n if (inert) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n setOpen(true);\n } else if (showClear && !open && (e.key === \"Delete\" || e.key === \"Backspace\")) {\n // The keyboard's clear: the \"×\" is a pointer shortcut out of the tab\n // order, so without this a cleared-by-mouse field was set-only from the\n // keyboard. The closed trigger only — CountrySelect's rule (0.23).\n e.preventDefault();\n onChange([]);\n }\n }}\n className={cn(\n FIELD_TRIGGER,\n \"pe-9\",\n label !== undefined && FIELD_FLOATING_PAD,\n inert && \"cursor-not-allowed opacity-50\",\n field.isInvalid && FIELD_INVALID,\n )}\n >\n <span\n className={cn(\n \"min-w-0 truncate\",\n // Inherit FIELD_BASE's ink for a value, keep the placeholder tone\n // (`--text-placeholder`) — the same rule every field on a form row\n // follows (Keksdose dev#477).\n !value.length && \"text-[var(--text-placeholder)]\",\n )}\n >\n {summary}\n </span>\n {showClear ? (\n /* eslint-disable-next-line jsx-a11y/click-events-have-key-events -- tabIndex -1 inside\n the trigger <button>, so it never holds focus and a key handler here could\n never fire. A pointer shortcut; the keyboard paths are Delete on the closed\n trigger and unticking the options in the open list. */\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label={labels.clear}\n onClick={(e) => {\n e.stopPropagation();\n onChange([]);\n }}\n className=\"absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-[var(--text-placeholder)] hover:text-[var(--text-secondary)]\"\n >\n <X className=\"size-4\" />\n </span>\n ) : (\n <FieldChevron />\n )}\n </button>,\n )}\n </EndHintRow>\n {/* With a \"?\" the label shares the top strip with it — after the trigger, so the\n \"?\" follows the control in the tab order, as on EntityCombobox. */}\n {label !== undefined && hintParts.labelHint !== undefined && (\n <StaticLabelRow hint={hintParts.labelHint}>\n <FieldLabel className={LABEL_IN_ROW}>{label}</FieldLabel>\n </StaticLabelRow>\n )}\n <ComboboxPanel\n core={core}\n listboxId={listboxId}\n multi\n // On a phone the panel becomes a full-screen sheet, which needs the field's\n // own label to say what it is asking for (live #200).\n sheetTitle={label ?? placeholder}\n searchPlaceholder={labels.search}\n emptyLabel={labels.noResults}\n closeLabel={closeLabel}\n loadErrorLabel={loadErrorLabel}\n isSelected={(v) => valueSet.has(v)}\n onChoose={toggle}\n showCreate={showCreate}\n onCreate={() => {\n if (lock.locked) return;\n onCreate?.(q);\n core.setQuery(\"\");\n }}\n createContent={q ? labels.create(q) : createEmptyLabel}\n createDisabledReason={createReason}\n />\n <FieldCaption parts={hintParts} />\n {field.errorEl}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,13 @@ import * as react from 'react';
2
2
  import { ComponentProps, ReactNode } from 'react';
3
3
  import { NumberInput } from './number-input.js';
4
4
  import './calculator.js';
5
- import '../kit-labels-R8mIAc9N.js';
5
+ import '../feedback-BxeQVzwq.js';
6
+ import '../feedback-attachment-fGAzZPf0.js';
7
+ import '../feedback/feedback-inbox.js';
8
+ import 'lucide-react';
9
+ import './tooltip.js';
10
+ import '../hooks/use-anchored-rect.js';
11
+ import '../lib/clipping.js';
6
12
  import '../data-table-labels-B7OdnM0S.js';
7
13
  import './data-table-sort.js';
8
14
  import './swipeable-row.js';
@@ -10,11 +16,7 @@ import './mini-calendar.js';
10
16
  import './calendar-heatmap.js';
11
17
  import './popover.js';
12
18
  import './chip.js';
13
- import 'lucide-react';
14
19
  import './field-sync.js';
15
- import './tooltip.js';
16
- import '../hooks/use-anchored-rect.js';
17
- import '../lib/clipping.js';
18
20
  import '../wizard/types.js';
19
21
  import '../tour/tour.js';
20
22
  import '../search/command-palette.js';
@@ -35,9 +37,6 @@ import './dialog-frame.js';
35
37
  import './modal.js';
36
38
  import '../hooks/use-search-param-state.js';
37
39
  import './measured-grid.js';
38
- import '../feedback-attachment-NhUm7Zga.js';
39
- import '../feedback/feedback-thread.js';
40
- import '../feedback/feedback-inbox.js';
41
40
  import './account-settings-labels.js';
42
41
  import './floating-panel.js';
43
42
  import './bulk-action-bar.js';
@@ -67,6 +66,10 @@ import './inline-edit-field.js';
67
66
  import '../lib/iban.js';
68
67
  import '../lib/phone.js';
69
68
  import './sign-chip.js';
69
+ import './column-mapper.js';
70
+ import '../lib/column-mapping.js';
71
+ import '../lib/table-text.js';
72
+ import './field-parts.js';
70
73
  import './numpad-sheet.js';
71
74
 
72
75
  type NumberInputProps = ComponentProps<typeof NumberInput>;
@@ -2,7 +2,13 @@ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { CalculatorButtonLabels } from './calculator.js';
4
4
  import { NumberPadSheetLabels } from './numpad-sheet.js';
5
- import '../kit-labels-R8mIAc9N.js';
5
+ import '../feedback-BxeQVzwq.js';
6
+ import '../feedback-attachment-fGAzZPf0.js';
7
+ import '../feedback/feedback-inbox.js';
8
+ import 'lucide-react';
9
+ import './tooltip.js';
10
+ import '../hooks/use-anchored-rect.js';
11
+ import '../lib/clipping.js';
6
12
  import '../data-table-labels-B7OdnM0S.js';
7
13
  import './data-table-sort.js';
8
14
  import './swipeable-row.js';
@@ -10,11 +16,7 @@ import './mini-calendar.js';
10
16
  import './calendar-heatmap.js';
11
17
  import './popover.js';
12
18
  import './chip.js';
13
- import 'lucide-react';
14
19
  import './field-sync.js';
15
- import './tooltip.js';
16
- import '../hooks/use-anchored-rect.js';
17
- import '../lib/clipping.js';
18
20
  import '../wizard/types.js';
19
21
  import '../tour/tour.js';
20
22
  import '../search/command-palette.js';
@@ -35,9 +37,6 @@ import './dialog-frame.js';
35
37
  import './modal.js';
36
38
  import '../hooks/use-search-param-state.js';
37
39
  import './measured-grid.js';
38
- import '../feedback-attachment-NhUm7Zga.js';
39
- import '../feedback/feedback-thread.js';
40
- import '../feedback/feedback-inbox.js';
41
40
  import './account-settings-labels.js';
42
41
  import './floating-panel.js';
43
42
  import './bulk-action-bar.js';
@@ -67,6 +66,10 @@ import './inline-edit-field.js';
67
66
  import '../lib/iban.js';
68
67
  import '../lib/phone.js';
69
68
  import './sign-chip.js';
69
+ import './column-mapper.js';
70
+ import '../lib/column-mapping.js';
71
+ import '../lib/table-text.js';
72
+ import './field-parts.js';
70
73
 
71
74
  interface NumberInputProps {
72
75
  /** The text, DOT-decimal ("1234.5", or a calculation being typed: "12+5"), as
@@ -1,6 +1,12 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { C as CalculatorLabels } from '../kit-labels-R8mIAc9N.js';
3
+ import { C as CalculatorLabels } from '../feedback-BxeQVzwq.js';
4
+ import '../feedback-attachment-fGAzZPf0.js';
5
+ import '../feedback/feedback-inbox.js';
6
+ import 'lucide-react';
7
+ import './tooltip.js';
8
+ import '../hooks/use-anchored-rect.js';
9
+ import '../lib/clipping.js';
4
10
  import '../data-table-labels-B7OdnM0S.js';
5
11
  import './data-table-sort.js';
6
12
  import './swipeable-row.js';
@@ -8,11 +14,7 @@ import './mini-calendar.js';
8
14
  import './calendar-heatmap.js';
9
15
  import './popover.js';
10
16
  import './chip.js';
11
- import 'lucide-react';
12
17
  import './field-sync.js';
13
- import './tooltip.js';
14
- import '../hooks/use-anchored-rect.js';
15
- import '../lib/clipping.js';
16
18
  import '../wizard/types.js';
17
19
  import '../tour/tour.js';
18
20
  import '../search/command-palette.js';
@@ -33,9 +35,6 @@ import './dialog-frame.js';
33
35
  import './modal.js';
34
36
  import '../hooks/use-search-param-state.js';
35
37
  import './measured-grid.js';
36
- import '../feedback-attachment-NhUm7Zga.js';
37
- import '../feedback/feedback-thread.js';
38
- import '../feedback/feedback-inbox.js';
39
38
  import './account-settings-labels.js';
40
39
  import './floating-panel.js';
41
40
  import './bulk-action-bar.js';
@@ -65,6 +64,10 @@ import './inline-edit-field.js';
65
64
  import '../lib/iban.js';
66
65
  import '../lib/phone.js';
67
66
  import './sign-chip.js';
67
+ import './column-mapper.js';
68
+ import '../lib/column-mapping.js';
69
+ import '../lib/table-text.js';
70
+ import './field-parts.js';
68
71
 
69
72
  /**
70
73
  * A full calculator keypad rendered as a bottom sheet — the mobile counterpart to
@@ -1,6 +1,12 @@
1
1
  import 'react';
2
2
  import '../lib/phone.js';
3
- export { a5 as DEFAULT_PHONE_INPUT_LABELS, ba as PhoneInput, bb as PhoneInputLabels, bc as PhoneInputProps } from '../kit-labels-R8mIAc9N.js';
3
+ export { ab as DEFAULT_PHONE_INPUT_LABELS, bq as PhoneInput, br as PhoneInputLabels, bs as PhoneInputProps } from '../feedback-BxeQVzwq.js';
4
+ import '../feedback-attachment-fGAzZPf0.js';
5
+ import '../feedback/feedback-inbox.js';
6
+ import 'lucide-react';
7
+ import './tooltip.js';
8
+ import '../hooks/use-anchored-rect.js';
9
+ import '../lib/clipping.js';
4
10
  import '../data-table-labels-B7OdnM0S.js';
5
11
  import './data-table-sort.js';
6
12
  import './swipeable-row.js';
@@ -8,11 +14,7 @@ import './mini-calendar.js';
8
14
  import './calendar-heatmap.js';
9
15
  import './popover.js';
10
16
  import './chip.js';
11
- import 'lucide-react';
12
17
  import './field-sync.js';
13
- import './tooltip.js';
14
- import '../hooks/use-anchored-rect.js';
15
- import '../lib/clipping.js';
16
18
  import '../wizard/types.js';
17
19
  import '../tour/tour.js';
18
20
  import '../search/command-palette.js';
@@ -33,9 +35,6 @@ import './dialog-frame.js';
33
35
  import './modal.js';
34
36
  import '../hooks/use-search-param-state.js';
35
37
  import './measured-grid.js';
36
- import '../feedback-attachment-NhUm7Zga.js';
37
- import '../feedback/feedback-thread.js';
38
- import '../feedback/feedback-inbox.js';
39
38
  import './account-settings-labels.js';
40
39
  import './floating-panel.js';
41
40
  import './bulk-action-bar.js';
@@ -64,3 +63,7 @@ import './country-select.js';
64
63
  import './inline-edit-field.js';
65
64
  import '../lib/iban.js';
66
65
  import './sign-chip.js';
66
+ import './column-mapper.js';
67
+ import '../lib/column-mapping.js';
68
+ import '../lib/table-text.js';
69
+ import './field-parts.js';
@@ -70,8 +70,8 @@ interface ReauthDialogProps {
70
70
  * `requirePassword` tile. Both are the same three facts — the field is the CURRENT
71
71
  * password (the password manager fills it, never generates one), a wrong one stays in
72
72
  * the dialog with its error, and the APP verifies it — so the promise handling is
73
- * `DangerConfirm`'s own, shared, the field is its `CurrentPasswordInput` spelled out
74
- * with an `error`, and this is the modal form of them.
73
+ * `DangerConfirm`'s own, shared, the field is its `CurrentPasswordInput` with an
74
+ * `error`, and this is the modal form of them.
75
75
  *
76
76
  * A component rather than a `useReauth()` promise: the step that follows the check
77
77
  * (Kurvenschmiede's WebAuthn ceremony) needs what the server answered, and the error
@@ -2,10 +2,10 @@
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useContext, useEffect, useId, useRef, useState } from "react";
4
4
  import { useKitLabels } from "../i18n/kit-labels.js";
5
- import { usePromisePending } from "./danger-confirm.js";
5
+ import { CurrentPasswordInput, usePromisePending } from "./danger-confirm.js";
6
6
  import { DialogFrame } from "./dialog-frame.js";
7
7
  import { ModalCloseContext } from "./modal.js";
8
- import { Button, Input, Spinner } from "./ui.js";
8
+ import { Button, Spinner } from "./ui.js";
9
9
  const DEFAULT_REAUTH_DIALOG_LABELS = {
10
10
  title: "Confirm it\u2019s you",
11
11
  description: "Enter your current password to continue.",
@@ -99,17 +99,15 @@ function ReauthDialog({
99
99
  submit();
100
100
  },
101
101
  children: /* @__PURE__ */ jsx(
102
- Input,
102
+ CurrentPasswordInput,
103
103
  {
104
104
  ref: inputRef,
105
- type: "password",
106
- autoComplete: "current-password",
107
105
  label: labels.password,
108
106
  value: password,
109
- readOnly: busy,
107
+ busy,
110
108
  error: shownError,
111
- onChange: (e) => {
112
- setPassword(e.target.value);
109
+ onValueChange: (next) => {
110
+ setPassword(next);
113
111
  setEdited(true);
114
112
  }
115
113
  }