@eifi1/ui-kit 0.21.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.
- package/README.md +42 -25
- package/dist/chart.d.ts +19 -14
- package/dist/components/account-chips.d.ts +10 -3
- package/dist/components/account-chips.js +5 -2
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/account-settings.d.ts +33 -2
- package/dist/components/account-settings.js +43 -21
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +53 -14
- package/dist/components/amount-input.js +17 -28
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +29 -0
- package/dist/components/autocomplete.js +134 -104
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-group.d.ts +19 -14
- package/dist/components/calculator.d.ts +19 -14
- package/dist/components/checkbox-group.d.ts +104 -0
- package/dist/components/checkbox-group.js +111 -0
- package/dist/components/checkbox-group.js.map +1 -0
- package/dist/components/checkbox.d.ts +19 -0
- package/dist/components/checkbox.js +30 -7
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/chip.d.ts +18 -0
- package/dist/components/chip.js +47 -10
- package/dist/components/chip.js.map +1 -1
- package/dist/components/column-mapper.d.ts +182 -0
- package/dist/components/column-mapper.js +375 -0
- package/dist/components/column-mapper.js.map +1 -0
- package/dist/components/combobox-core.d.ts +39 -2
- package/dist/components/combobox-core.js +29 -6
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +91 -2
- package/dist/components/combobox.js +454 -308
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +69 -161
- package/dist/components/confirm-dialog.js +7 -8
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +16 -11
- package/dist/components/country-select.d.ts +167 -0
- package/dist/components/country-select.js +293 -0
- package/dist/components/country-select.js.map +1 -0
- package/dist/components/currency-select.d.ts +17 -1
- package/dist/components/currency-select.js +56 -23
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +69 -166
- package/dist/components/danger-confirm.js +144 -50
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +1 -2
- package/dist/components/data-table-filter-popover.d.ts +1 -2
- package/dist/components/data-table-filters.d.ts +1 -2
- package/dist/components/data-table-labels.d.ts +4 -97
- package/dist/components/data-table-labels.js +9 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table-pagination.d.ts +3 -1
- package/dist/components/data-table.d.ts +1 -2
- package/dist/components/data-table.js +98 -3
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +66 -5
- package/dist/components/date-picker.js +378 -66
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +42 -1
- package/dist/components/entity-combobox.js +154 -113
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +19 -14
- package/dist/components/field-parts.d.ts +224 -0
- package/dist/components/field-parts.js +156 -0
- package/dist/components/field-parts.js.map +1 -0
- package/dist/components/field-strip.d.ts +105 -0
- package/dist/components/field-strip.js +46 -0
- package/dist/components/field-strip.js.map +1 -0
- package/dist/components/file-button.d.ts +19 -14
- package/dist/components/file-button.js +13 -3
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +41 -15
- package/dist/components/file-dropzone.js +57 -34
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/form-actions.d.ts +18 -13
- package/dist/components/form-actions.js +69 -5
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/iban-input.d.ts +69 -0
- package/dist/components/iban-input.js +125 -0
- package/dist/components/iban-input.js.map +1 -0
- package/dist/components/icon-picker.d.ts +21 -2
- package/dist/components/icon-picker.js +19 -4
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-edit-field.d.ts +167 -0
- package/dist/components/inline-edit-field.js +293 -0
- package/dist/components/inline-edit-field.js.map +1 -0
- package/dist/components/language-select.d.ts +130 -0
- package/dist/components/language-select.js +18 -0
- package/dist/components/language-select.js.map +1 -0
- package/dist/components/line-items.d.ts +25 -3
- package/dist/components/line-items.js +55 -46
- package/dist/components/line-items.js.map +1 -1
- package/dist/components/list.d.ts +25 -0
- package/dist/components/list.js +16 -5
- package/dist/components/list.js.map +1 -1
- package/dist/components/money-field.d.ts +32 -14
- package/dist/components/money-field.js.map +1 -1
- package/dist/components/month-picker.d.ts +52 -4
- package/dist/components/month-picker.js +291 -86
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +26 -1
- package/dist/components/multi-entity-combobox.js +143 -102
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +8 -1
- package/dist/components/multi-select.js +9 -4
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +34 -19
- package/dist/components/number-field.js +6 -20
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +79 -19
- package/dist/components/number-input.js +90 -38
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +19 -14
- package/dist/components/one-time-code-input.d.ts +100 -0
- package/dist/components/one-time-code-input.js +137 -0
- package/dist/components/one-time-code-input.js.map +1 -0
- package/dist/components/phone-input.d.ts +69 -0
- package/dist/components/phone-input.js +171 -0
- package/dist/components/phone-input.js.map +1 -0
- package/dist/components/reauth-dialog.d.ts +2 -2
- package/dist/components/reauth-dialog.js +6 -8
- package/dist/components/reauth-dialog.js.map +1 -1
- package/dist/components/series-chart.d.ts +19 -14
- package/dist/components/settings-fields.d.ts +19 -14
- package/dist/components/share-card.d.ts +16 -11
- package/dist/components/sign-chip.d.ts +66 -0
- package/dist/components/sign-chip.js +39 -0
- package/dist/components/sign-chip.js.map +1 -0
- package/dist/components/swatch-picker.d.ts +43 -2
- package/dist/components/swatch-picker.js +80 -32
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/switch.d.ts +19 -0
- package/dist/components/switch.js +24 -6
- package/dist/components/switch.js.map +1 -1
- package/dist/components/text-link.d.ts +18 -13
- package/dist/components/tile-radio.d.ts +88 -13
- package/dist/components/tile-radio.js +28 -11
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/time-input.d.ts +24 -15
- package/dist/components/time-input.js.map +1 -1
- package/dist/components/toggle-group.d.ts +47 -1
- package/dist/components/toggle-group.js +110 -69
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/trigger-aria.d.ts +3 -0
- package/dist/components/trigger-aria.js +3 -1
- package/dist/components/trigger-aria.js.map +1 -1
- package/dist/components/ui.d.ts +16 -11
- package/dist/components/ui.js +284 -88
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -2
- package/dist/{data-table-3mi2R3so.d.ts → data-table-labels-B7OdnM0S.d.ts} +140 -3
- package/dist/data-table.d.ts +1 -2
- package/dist/data-table.js +2 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +1 -1
- package/dist/feedback/feedback-attachment.js +348 -41
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +1 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +3 -2
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +68 -253
- package/dist/feedback/feedback-thread.js +46 -10
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/{kit-labels-D1J2_jyD.d.ts → feedback-BxeQVzwq.d.ts} +1206 -20
- package/dist/{feedback-attachment-WFiXJ8We.d.ts → feedback-attachment-fGAzZPf0.d.ts} +178 -11
- package/dist/feedback.d.ts +66 -2
- package/dist/hooks/use-file-drop.d.ts +19 -14
- package/dist/i18n/defaults.d.ts +19 -14
- package/dist/i18n/defaults.js +19 -2
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +19 -14
- package/dist/i18n/german.js +84 -5
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +15 -10
- package/dist/i18n/kit-labels.js +8 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +19 -14
- package/dist/i18n/locales/de-CH.d.ts +19 -14
- package/dist/i18n/locales/en.d.ts +19 -14
- package/dist/i18n/locales/en.js +16 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +19 -14
- package/dist/i18n/locales/es.js +83 -5
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +19 -14
- package/dist/i18n/locales/fr.js +82 -5
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +19 -14
- package/dist/i18n/locales/hu.js +85 -5
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +19 -14
- package/dist/i18n/locales/it.js +84 -5
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +19 -14
- package/dist/i18n/locales/zh.js +80 -5
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +19 -14
- package/dist/i18n/review.js +27 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +21 -10
- package/dist/index.js +73 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/column-mapping.d.ts +81 -0
- package/dist/lib/column-mapping.js +108 -0
- package/dist/lib/column-mapping.js.map +1 -0
- package/dist/lib/countries.d.ts +43 -0
- package/dist/lib/countries.js +39 -0
- package/dist/lib/countries.js.map +1 -0
- package/dist/lib/decimal-marks.d.ts +46 -0
- package/dist/lib/decimal-marks.js +40 -0
- package/dist/lib/decimal-marks.js.map +1 -0
- package/dist/lib/iban.d.ts +98 -0
- package/dist/lib/iban.js +154 -0
- package/dist/lib/iban.js.map +1 -0
- package/dist/lib/isin.d.ts +30 -0
- package/dist/lib/isin.js +36 -0
- package/dist/lib/isin.js.map +1 -0
- package/dist/lib/phone.d.ts +69 -0
- package/dist/lib/phone.js +121 -0
- package/dist/lib/phone.js.map +1 -0
- package/dist/lib/table-text.d.ts +109 -1
- package/dist/lib/table-text.js +122 -1
- package/dist/lib/table-text.js.map +1 -1
- package/dist/rhf/fields.d.ts +233 -18
- package/dist/rhf/fields.js +456 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form.d.ts +19 -14
- package/dist/rhf.d.ts +22 -15
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +18 -13
- package/dist/shell/top-bar-brand.d.ts +19 -14
- package/dist/shell/topbar-action-menu.d.ts +36 -3
- package/dist/shell/topbar-action-menu.js +74 -33
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +18 -13
- package/dist/table-text.d.ts +1 -1
- package/dist/tour/tour.js +20 -24
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +49 -16
- package/dist/wizard/stepper-nav.js +4 -0
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard.d.ts +19 -14
- package/package.json +1 -1
- package/src/components/account-chips.tsx +17 -3
- package/src/components/account-settings.tsx +92 -26
- package/src/components/amount-input.tsx +68 -56
- package/src/components/autocomplete.tsx +198 -114
- package/src/components/checkbox-group.tsx +229 -0
- package/src/components/checkbox.tsx +72 -8
- package/src/components/chip.tsx +80 -10
- package/src/components/column-mapper.tsx +666 -0
- package/src/components/combobox-core.tsx +82 -9
- package/src/components/combobox.tsx +661 -340
- package/src/components/confirm-dialog.tsx +12 -8
- package/src/components/country-select.tsx +556 -0
- package/src/components/currency-select.tsx +109 -33
- package/src/components/danger-confirm.tsx +429 -82
- package/src/components/data-table-labels.ts +16 -1
- package/src/components/data-table.tsx +175 -6
- package/src/components/date-picker.tsx +595 -71
- package/src/components/entity-combobox.tsx +235 -124
- package/src/components/field-parts.tsx +403 -0
- package/src/components/field-strip.tsx +149 -0
- package/src/components/file-button.tsx +36 -3
- package/src/components/file-dropzone.tsx +106 -38
- package/src/components/form-actions.tsx +147 -6
- package/src/components/iban-input.tsx +231 -0
- package/src/components/icon-picker.tsx +47 -6
- package/src/components/inline-edit-field.tsx +533 -0
- package/src/components/language-select.tsx +78 -0
- package/src/components/line-items.tsx +35 -2
- package/src/components/list.tsx +55 -6
- package/src/components/money-field.tsx +13 -0
- package/src/components/month-picker.tsx +400 -63
- package/src/components/multi-entity-combobox.tsx +207 -120
- package/src/components/multi-select.tsx +80 -58
- package/src/components/number-field.tsx +28 -46
- package/src/components/number-input.tsx +210 -43
- package/src/components/one-time-code-input.tsx +288 -0
- package/src/components/phone-input.tsx +299 -0
- package/src/components/reauth-dialog.tsx +17 -18
- package/src/components/sign-chip.tsx +103 -0
- package/src/components/swatch-picker.tsx +143 -31
- package/src/components/switch.tsx +58 -7
- package/src/components/tile-radio.tsx +145 -29
- package/src/components/time-input.tsx +8 -1
- package/src/components/toggle-group.tsx +206 -73
- package/src/components/trigger-aria.ts +5 -0
- package/src/components/ui.tsx +479 -138
- package/src/data-table.ts +2 -1
- package/src/feedback/feedback-attachment.tsx +597 -46
- package/src/feedback/feedback-dialog.tsx +9 -3
- package/src/feedback/feedback-inbox.tsx +3 -2
- package/src/feedback/feedback-thread.tsx +113 -9
- package/src/i18n/defaults.ts +18 -1
- package/src/i18n/german.ts +89 -0
- package/src/i18n/kit-labels.tsx +82 -2
- package/src/i18n/locales/en.ts +36 -4
- package/src/i18n/locales/es.ts +87 -0
- package/src/i18n/locales/fr.ts +87 -0
- package/src/i18n/locales/hu.ts +83 -0
- package/src/i18n/locales/it.ts +88 -0
- package/src/i18n/locales/zh.ts +76 -0
- package/src/i18n/review.ts +26 -0
- package/src/index.ts +71 -3
- package/src/lib/column-mapping.ts +234 -0
- package/src/lib/countries.ts +91 -0
- package/src/lib/decimal-marks.ts +99 -0
- package/src/lib/iban.ts +171 -0
- package/src/lib/isin.ts +62 -0
- package/src/lib/phone.ts +211 -0
- package/src/lib/table-text.ts +271 -0
- package/src/rhf/fields.tsx +860 -9
- package/src/rhf.ts +3 -1
- package/src/shell/topbar-action-menu.tsx +134 -38
- package/src/tour/tour.tsx +66 -28
- package/src/wizard/stepper-nav.tsx +35 -1
|
@@ -16,6 +16,16 @@ import {
|
|
|
16
16
|
useOptionSource
|
|
17
17
|
} from "./combobox-core.js";
|
|
18
18
|
import { DEFAULT_COMBOBOX_LABELS, useKitLabels } from "../i18n/kit-labels.js";
|
|
19
|
+
import {
|
|
20
|
+
EndHintRow,
|
|
21
|
+
FieldCaption,
|
|
22
|
+
LABEL_IN_ROW,
|
|
23
|
+
LockedReason,
|
|
24
|
+
StaticLabelRow,
|
|
25
|
+
useFieldHint,
|
|
26
|
+
useLockReason
|
|
27
|
+
} from "./field-parts.js";
|
|
28
|
+
import { mergeDescribedBy } from "./choice-parts.js";
|
|
19
29
|
function AutocompleteInner({
|
|
20
30
|
value,
|
|
21
31
|
onChange,
|
|
@@ -31,6 +41,7 @@ function AutocompleteInner({
|
|
|
31
41
|
icon,
|
|
32
42
|
invalid,
|
|
33
43
|
error,
|
|
44
|
+
hint,
|
|
34
45
|
status,
|
|
35
46
|
emptyLabel,
|
|
36
47
|
loadErrorLabel,
|
|
@@ -41,6 +52,8 @@ function AutocompleteInner({
|
|
|
41
52
|
inputClassName,
|
|
42
53
|
id,
|
|
43
54
|
disabled,
|
|
55
|
+
disabledReason,
|
|
56
|
+
commit,
|
|
44
57
|
onKeyDown,
|
|
45
58
|
onFocus,
|
|
46
59
|
onBlur,
|
|
@@ -59,7 +72,8 @@ function AutocompleteInner({
|
|
|
59
72
|
noResults: emptyLabel,
|
|
60
73
|
loadError: loadErrorLabel
|
|
61
74
|
});
|
|
62
|
-
const
|
|
75
|
+
const hintParts = useFieldHint(hint, ariaDescribedBy);
|
|
76
|
+
const field = useComboboxFieldError(error, invalid, hintParts.describedBy);
|
|
63
77
|
const [ownOpen, setOwnOpen] = useState(false);
|
|
64
78
|
const open = openProp ?? ownOpen;
|
|
65
79
|
const setOpen = (next) => {
|
|
@@ -67,7 +81,9 @@ function AutocompleteInner({
|
|
|
67
81
|
if (next !== open) onOpenChange?.(next);
|
|
68
82
|
};
|
|
69
83
|
const [active, setActive] = useState(-1);
|
|
70
|
-
const
|
|
84
|
+
const lock = useLockReason(commit, disabledReason);
|
|
85
|
+
const locked = lock.locked;
|
|
86
|
+
const live = open && !disabled && !locked;
|
|
71
87
|
const { results, busy, failed, tooShort } = useOptionSource({
|
|
72
88
|
options,
|
|
73
89
|
loadOptions,
|
|
@@ -90,7 +106,7 @@ function AutocompleteInner({
|
|
|
90
106
|
setActive(-1);
|
|
91
107
|
};
|
|
92
108
|
const take = (o) => {
|
|
93
|
-
if (o.disabled) return;
|
|
109
|
+
if (o.disabled || locked) return;
|
|
94
110
|
if (fillOnSelect) onChange(o.label);
|
|
95
111
|
onSelect?.(o);
|
|
96
112
|
close();
|
|
@@ -99,114 +115,128 @@ function AutocompleteInner({
|
|
|
99
115
|
const small = size === "sm" && !hasLabel;
|
|
100
116
|
const nativeSize = typeof size === "number" ? size : void 0;
|
|
101
117
|
const labelledBy = ariaLabel === void 0 ? ariaLabelledBy ?? (hasLabel ? labelId : void 0) : void 0;
|
|
118
|
+
const withLock = (box) => locked ? /* @__PURE__ */ jsx(LockedReason, { lock, className: "block", children: box }) : box;
|
|
102
119
|
return (
|
|
103
120
|
// `relative`: the floating label and the live region's `sr-only` both need a
|
|
104
121
|
// local containing block.
|
|
105
122
|
/* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
|
|
106
|
-
hasLabel && /* @__PURE__ */ jsx(ComboboxFieldLabel, { id: labelId, htmlFor: fieldId, children: label }),
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
setOpen(true);
|
|
157
|
-
setActive(-1);
|
|
158
|
-
},
|
|
159
|
-
onKeyDown: (e) => {
|
|
160
|
-
if (e.key === "Escape" && expanded) {
|
|
161
|
-
e.preventDefault();
|
|
162
|
-
e.stopPropagation();
|
|
123
|
+
hasLabel && hintParts.labelHint === void 0 && /* @__PURE__ */ jsx(ComboboxFieldLabel, { id: labelId, htmlFor: fieldId, children: label }),
|
|
124
|
+
/* @__PURE__ */ jsx(EndHintRow, { hint: hasLabel ? void 0 : hintParts.labelHint, children: withLock(
|
|
125
|
+
/* @__PURE__ */ jsxs("div", { ref: fieldRef, className: cn("relative", locked && "cursor-not-allowed"), children: [
|
|
126
|
+
icon && /* @__PURE__ */ jsx(
|
|
127
|
+
"span",
|
|
128
|
+
{
|
|
129
|
+
"aria-hidden": true,
|
|
130
|
+
className: cn(
|
|
131
|
+
"pointer-events-none absolute flex text-[var(--text-muted)]",
|
|
132
|
+
small ? "start-2 [&>svg]:size-3.5" : "start-2.5 [&>svg]:size-4",
|
|
133
|
+
// Labelled, the icon sits on the VALUE's line — the one line box below
|
|
134
|
+
// FIELD_FLOATING_PAD's `pt-4` and the 1px border — not on the middle of
|
|
135
|
+
// the box. Centred on the box it rose into the top strip and sat on the
|
|
136
|
+
// label's first letters, which float at the same start inset. On the
|
|
137
|
+
// value line it is beside what it describes, and the label keeps the
|
|
138
|
+
// start edge every other label in the form's column shares.
|
|
139
|
+
hasLabel ? "top-[calc(1rem+1px)] h-5 items-center" : "top-1/2 -translate-y-1/2"
|
|
140
|
+
),
|
|
141
|
+
children: icon
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
/* @__PURE__ */ jsx(
|
|
145
|
+
"input",
|
|
146
|
+
{
|
|
147
|
+
...rest,
|
|
148
|
+
ref,
|
|
149
|
+
id: fieldId,
|
|
150
|
+
size: nativeSize,
|
|
151
|
+
type: "text",
|
|
152
|
+
value,
|
|
153
|
+
disabled: locked ? void 0 : disabled,
|
|
154
|
+
readOnly: locked || rest.readOnly,
|
|
155
|
+
"aria-disabled": locked || rest["aria-disabled"],
|
|
156
|
+
role: "combobox",
|
|
157
|
+
"aria-autocomplete": "list",
|
|
158
|
+
"aria-expanded": expanded,
|
|
159
|
+
"aria-controls": listboxId,
|
|
160
|
+
"aria-activedescendant": activeId,
|
|
161
|
+
"aria-label": ariaLabel,
|
|
162
|
+
"aria-labelledby": labelledBy,
|
|
163
|
+
"aria-invalid": field.isInvalid || rest["aria-invalid"] || void 0,
|
|
164
|
+
"aria-describedby": mergeDescribedBy(field.describedBy, locked && lock.reasonId),
|
|
165
|
+
autoComplete: "off",
|
|
166
|
+
onFocus: (e) => {
|
|
167
|
+
onFocus?.(e);
|
|
168
|
+
if (locked) return;
|
|
169
|
+
setOpen(true);
|
|
170
|
+
},
|
|
171
|
+
onBlur: (e) => {
|
|
172
|
+
onBlur?.(e);
|
|
163
173
|
close();
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (
|
|
174
|
+
},
|
|
175
|
+
onChange: (e) => {
|
|
176
|
+
if (locked) return;
|
|
177
|
+
onChange(e.target.value);
|
|
178
|
+
setOpen(true);
|
|
179
|
+
setActive(-1);
|
|
180
|
+
},
|
|
181
|
+
onKeyDown: (e) => {
|
|
182
|
+
if (locked) {
|
|
183
|
+
if (e.key === "Enter") e.preventDefault();
|
|
184
|
+
else onKeyDown?.(e);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (e.key === "Escape" && expanded) {
|
|
178
188
|
e.preventDefault();
|
|
179
|
-
|
|
189
|
+
e.stopPropagation();
|
|
190
|
+
close();
|
|
191
|
+
return;
|
|
180
192
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
193
|
+
onKeyDown?.(e);
|
|
194
|
+
if (e.defaultPrevented) return;
|
|
195
|
+
if (e.key === "ArrowDown") {
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
if (!open) setOpen(true);
|
|
198
|
+
else setActive((i) => stepEnabled(results, i, 1));
|
|
199
|
+
} else if (e.key === "ArrowUp") {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
if (!open) setOpen(true);
|
|
202
|
+
else setActive((i) => stepEnabled(results, i < 0 ? results.length : i, -1));
|
|
203
|
+
} else if (e.key === "Enter") {
|
|
204
|
+
if (expanded && activeId) {
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
take(results[active]);
|
|
207
|
+
}
|
|
208
|
+
} else if (e.key === "Tab") {
|
|
209
|
+
close();
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
className: cn(
|
|
213
|
+
FIELD_BASE,
|
|
214
|
+
hasLabel && FIELD_FLOATING_PAD,
|
|
215
|
+
// Select's `SELECT_SM` box: a fixed 28px, so the caller's line height
|
|
216
|
+
// cannot grow it.
|
|
217
|
+
small && "h-7 py-0 pe-2 ps-2 text-xs",
|
|
218
|
+
icon ? small ? "ps-7" : "ps-8" : void 0,
|
|
219
|
+
busy && (small ? "pe-7" : "pe-9"),
|
|
220
|
+
field.isInvalid && FIELD_INVALID,
|
|
221
|
+
inputClassName
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
busy && live && // Decorative: the live region below already says "Loading…".
|
|
226
|
+
/* @__PURE__ */ jsx(
|
|
227
|
+
"span",
|
|
228
|
+
{
|
|
229
|
+
className: cn(
|
|
230
|
+
"pointer-events-none absolute top-1/2 flex -translate-y-1/2",
|
|
231
|
+
small ? "end-2" : "end-2.5"
|
|
232
|
+
),
|
|
233
|
+
children: /* @__PURE__ */ jsx(Spinner, { label: null, className: small ? "h-3.5 w-3.5" : "h-4 w-4" })
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
] })
|
|
237
|
+
) }),
|
|
238
|
+
hasLabel && hintParts.labelHint !== void 0 && /* @__PURE__ */ jsx(StaticLabelRow, { hint: hintParts.labelHint, children: /* @__PURE__ */ jsx(ComboboxFieldLabel, { id: labelId, htmlFor: fieldId, className: LABEL_IN_ROW, children: label }) }),
|
|
239
|
+
/* @__PURE__ */ jsx(FieldCaption, { parts: hintParts }),
|
|
210
240
|
field.errorEl,
|
|
211
241
|
/* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: !live ? null : statusLine !== null ? statusLine : results.length > 0 ? labels.resultCount(results.length) : null }),
|
|
212
242
|
expanded && rect && typeof document !== "undefined" && createPortal(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/autocomplete.tsx"],"sourcesContent":["import { Fragment, forwardRef, useId, useRef, useState } from \"react\";\nimport type {\n ComponentPropsWithoutRef,\n ForwardedRef,\n ReactElement,\n ReactNode,\n RefAttributes,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../lib/cn\";\nimport { FIELD_BASE, FIELD_FLOATING_PAD, FIELD_INVALID, Spinner } from \"./ui\";\nimport { useAnchoredPanel } from \"../hooks/use-anchored-panel\";\nimport { useAnchorDir } from \"./use-anchor-dir\";\nimport {\n ComboboxFieldLabel,\n DISABLED_ROW_CLASS,\n isOptionEnabled,\n stepEnabled,\n useActiveOptionScroll,\n useComboboxFieldError,\n useOptionSource,\n type ComboOption,\n} from \"./combobox-core\";\nimport { DEFAULT_COMBOBOX_LABELS, useKitLabels } from \"../i18n/kit-labels\";\n\n/**\n * `value`/`onChange` are the TEXT's, and `onSelect` is \"a suggestion was taken\" —\n * not the DOM's text-selection event — so the input's own spellings of those three\n * are omitted. Everything else reaches the `<input>`, the way it does on {@link Input}.\n */\nexport interface AutocompleteProps<V extends string | number = string>\n extends Omit<\n ComponentPropsWithoutRef<\"input\">,\n \"value\" | \"defaultValue\" | \"onChange\" | \"onSelect\" | \"children\" | \"type\" | \"size\"\n > {\n /** What is in the field. Controlled, and never reset by the component: opening,\n * closing and a failed lookup all leave it exactly as typed. */\n value: string;\n /** Every keystroke — and, with `fillOnSelect`, the label of a taken suggestion. */\n onChange: (text: string) => void;\n /** Suggestions the caller already has (e.g. from its own query hook). Narrowed by\n * the text unless `filter={false}`. An option with `disabled: true` is listed but\n * cannot be taken — see {@link ComboOption.disabled}. */\n options?: ComboOption<V>[];\n /** Or: fetch them. Debounced (`debounceMs`), race-safe, only at `minChars` and up,\n * never while the field is idle; a rejection shows `loadErrorLabel` and empties\n * the list rather than leaving the previous text's rows under it. */\n loadOptions?: (query: string) => Promise<ComboOption<V>[]>;\n /** Narrow `options` by label/sublabel substring. Default `true`. Pass `false` for\n * a list a server has already searched and ranked — it is shown as given. */\n filter?: boolean;\n /** External loading flag (a caller-side fetch), OR-ed with `loadOptions`'. */\n loading?: boolean;\n /** Below this many characters nothing is offered or fetched. Default 1: an empty\n * field asks nothing — focusing it is not a search. */\n minChars?: number;\n /** Quiet time before `loadOptions` runs. Default 300 ms — an ordinary typist's\n * inter-key interval is 150–250 ms, so the pickers' 150 fires on nearly every\n * letter, which a rate-limited geocoder cannot afford. */\n debounceMs?: number;\n /**\n * Whether the list MAY show — controlled. Omit (or pass `undefined`) and the field\n * decides: open while focused, until Escape, Tab or a taken row. `false` keeps it\n * shut whatever the user does, and stops `loadOptions` asking — keksdose's address\n * search, with its confirm map up, where it used to pass `minChars={Infinity}`.\n * `true` shows it even unfocused.\n *\n * Even open, the list only APPEARS when it has something to show (rows, or a\n * status line); `aria-expanded` follows what appears, not this flag.\n */\n open?: boolean;\n /** The field wants the list open or shut — focus, typing, ↓/↑ open it; blur,\n * Escape, Tab and taking a row shut it. Called on every change, controlled or not. */\n onOpenChange?: (open: boolean) => void;\n /**\n * `\"sm\"`: the 28px, 12px-type field of {@link Select}'s `size=\"sm\"`, with the icon,\n * spinner and list rows scaled to match — for a card or toolbar whose buttons are\n * small. `\"md\"` (default) is the form field. Unlabelled only, as on `Select`: a\n * floating label needs the tall box, so a labelled field ignores `\"sm\"`.\n *\n * A NUMBER is still the native `size` attribute (the width in characters), passed\n * straight through.\n */\n size?: \"sm\" | \"md\" | number;\n /** A suggestion was taken (click, or Enter on the highlighted row). */\n onSelect?: (option: ComboOption<V>) => void;\n /**\n * Put the taken suggestion's label into the field (`onChange(label)`). Default\n * `true` — the free-text case, where the text IS the value and a suggestion only\n * completes it (an address field). Pass `false` where taking a row is an ACTION\n * and the field is only the search that found it; the text then stays as typed.\n */\n fillOnSelect?: boolean;\n /** A floating label, as on {@link Combobox} — a real `<label for>` on the input.\n * Names the field (`aria-labelledby`) unless an `aria-label` is given. */\n label?: ReactNode;\n /** Leading decoration inside the field (a pin, a magnifier). Decorative: the\n * label names the field. An `<svg>` child is sized by the field — 16px, or 14px\n * at `size=\"sm\"` — so a lucide icon needs no class of its own. */\n icon?: ReactNode;\n /** Required and unanswered — {@link FIELD_INVALID}. */\n invalid?: boolean;\n /** What is wrong with the VALUE, as {@link Input}'s `error`: under the field, on\n * its `aria-describedby`, implies `invalid`. Not a failed lookup — that is\n * `loadErrorLabel`, shown in the list. */\n error?: ReactNode;\n /**\n * The caller's own line in the list, replacing the automatic one (loading / failed\n * / no results). For what only the caller knows: \"offline\", \"the address service\n * is switched off\", a privacy note, the hint a caller-fetched list needs below its\n * own minimum. While set, the list opens even with no rows. Announced politely.\n */\n status?: ReactNode;\n /** Default: `combobox.noResults` from the {@link UiKitProvider}, else English. */\n emptyLabel?: string;\n /** Default: `combobox.loadError`. */\n loadErrorLabel?: string;\n /** Classes for the `<input>` itself; `className` styles the wrapper. */\n inputClassName?: string;\n}\n\nfunction AutocompleteInner<V extends string | number = string>(\n {\n value,\n onChange,\n options,\n loadOptions,\n filter,\n loading,\n minChars = 1,\n debounceMs = 300,\n onSelect,\n fillOnSelect = true,\n label,\n icon,\n invalid,\n error,\n status,\n emptyLabel,\n loadErrorLabel,\n open: openProp,\n onOpenChange,\n size,\n className,\n inputClassName,\n id,\n disabled,\n onKeyDown,\n onFocus,\n onBlur,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n ...rest\n }: AutocompleteProps<V>,\n ref: ForwardedRef<HTMLInputElement>,\n) {\n const generated = useId();\n const fieldId = id ?? generated;\n // Off the GENERATED id: a caller's `id` is theirs to collide with.\n const listboxId = `${generated}-listbox`;\n const labelId = `${generated}-label`;\n const optionId = (index: number) => `${generated}-option-${index}`;\n const fieldRef = useRef<HTMLDivElement>(null);\n const labels = useKitLabels(\"combobox\", DEFAULT_COMBOBOX_LABELS, {\n noResults: emptyLabel,\n loadError: loadErrorLabel,\n });\n const field = useComboboxFieldError(error, invalid, ariaDescribedBy);\n\n /** The user's intent: the field is focused and the list has not been dismissed.\n * Whether anything SHOWS is decided below, from what there is to show. */\n const [ownOpen, setOwnOpen] = useState(false);\n // Controlled when the caller passes a boolean. The own state is kept up to date\n // either way, so a caller that controls only SOMETIMES (`open={confirming ? false :\n // undefined}`) hands back a field that is exactly as open as focus says it is.\n const open = openProp ?? ownOpen;\n const setOpen = (next: boolean) => {\n setOwnOpen(next);\n if (next !== open) onOpenChange?.(next);\n };\n const [active, setActive] = useState(-1);\n const live = open && !disabled;\n const { results, busy, failed, tooShort } = useOptionSource<V>({\n options,\n loadOptions,\n loading,\n filter,\n minChars,\n debounceMs,\n query: value,\n active: live,\n });\n\n const hasStatus = status !== undefined && status !== null && status !== false && status !== \"\";\n // The visible line under the rows. Nothing below `minChars` unless the caller has\n // something to say — an empty field opening a box that says \"type more\" is noise.\n const statusLine: ReactNode = hasStatus\n ? status\n : tooShort\n ? null\n : busy && results.length === 0\n ? labels.loading\n : failed\n ? labels.loadError\n : !busy && results.length === 0\n ? labels.noResults\n : null;\n const expanded = live && (results.length > 0 || statusLine !== null);\n // A disabled row is never the keyboard's — not even when a list that changed under\n // the highlight put one there.\n const activeId = expanded && isOptionEnabled(results[active]) ? optionId(active) : undefined;\n useActiveOptionScroll(activeId);\n const { rect, top, maxHeight } = useAnchoredPanel(fieldRef, expanded, { preferredHeight: 256 });\n const dir = useAnchorDir(fieldRef, expanded);\n\n const close = () => {\n setOpen(false);\n setActive(-1);\n };\n const take = (o: ComboOption<V>) => {\n if (o.disabled) return;\n if (fillOnSelect) onChange(o.label);\n onSelect?.(o);\n close();\n };\n\n const hasLabel = label !== undefined;\n // `size=\"sm\"` is for an UNLABELLED field, as on Select: the floating label needs the\n // tall box. A number is the native attribute.\n const small = size === \"sm\" && !hasLabel;\n const nativeSize = typeof size === \"number\" ? size : undefined;\n // The caller's name wins; else the floating label, by reference so a non-string\n // label still names the field.\n const labelledBy =\n ariaLabel === undefined ? (ariaLabelledBy ?? (hasLabel ? labelId : undefined)) : undefined;\n\n return (\n // `relative`: the floating label and the live region's `sr-only` both need a\n // local containing block.\n <div className={cn(\"relative\", className)}>\n {/* A real <label for> (lenkbank), and still `aria-labelledby`'s target, so the\n name — and the listbox's, which borrows it — is exactly what it was. */}\n {hasLabel && (\n <ComboboxFieldLabel id={labelId} htmlFor={fieldId}>\n {label}\n </ComboboxFieldLabel>\n )}\n <div ref={fieldRef} className=\"relative\">\n {icon && (\n <span\n aria-hidden\n className={cn(\n \"pointer-events-none absolute flex text-[var(--text-muted)]\",\n small ? \"start-2 [&>svg]:size-3.5\" : \"start-2.5 [&>svg]:size-4\",\n // Labelled, the icon sits on the VALUE's line — the one line box below\n // FIELD_FLOATING_PAD's `pt-4` and the 1px border — not on the middle of\n // the box. Centred on the box it rose into the top strip and sat on the\n // label's first letters, which float at the same start inset. On the\n // value line it is beside what it describes, and the label keeps the\n // start edge every other label in the form's column shares.\n hasLabel\n ? \"top-[calc(1rem+1px)] h-5 items-center\"\n : \"top-1/2 -translate-y-1/2\",\n )}\n >\n {icon}\n </span>\n )}\n <input\n {...rest}\n ref={ref}\n id={fieldId}\n size={nativeSize}\n type=\"text\"\n value={value}\n disabled={disabled}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={expanded}\n // Required by the role, and set while closed too, as on the siblings.\n aria-controls={listboxId}\n aria-activedescendant={activeId}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n aria-invalid={field.isInvalid || rest[\"aria-invalid\"] || undefined}\n aria-describedby={field.describedBy}\n autoComplete=\"off\"\n onFocus={(e) => {\n onFocus?.(e);\n // A seeded field (keksdose's `initialQuery`) is looked up as it is\n // focused; an empty one asks nothing, because of `minChars`.\n setOpen(true);\n }}\n onBlur={(e) => {\n onBlur?.(e);\n close();\n }}\n onChange={(e) => {\n onChange(e.target.value);\n setOpen(true);\n setActive(-1);\n }}\n onKeyDown={(e) => {\n // An Escape that closes the OPEN list is the list's, and is consumed before\n // the caller sees it. A caller whose Escape means \"close the panel\" (keksdose's\n // address search) otherwise closed the whole panel when the user only meant\n // to dismiss the suggestions — the opposite of what the docs promised.\n if (e.key === \"Escape\" && expanded) {\n e.preventDefault();\n e.stopPropagation();\n close();\n return;\n }\n onKeyDown?.(e);\n if (e.defaultPrevented) return;\n // Disabled rows are passed over; at either end the highlight stays put.\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n if (!open) setOpen(true);\n else setActive((i) => stepEnabled(results, i, 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n if (!open) setOpen(true);\n // From \"nothing highlighted\", Up goes to the bottom, as the APG has it.\n else setActive((i) => stepEnabled(results, i < 0 ? results.length : i, -1));\n } else if (e.key === \"Enter\") {\n // No row highlighted: the text is the answer, and a form's own submit\n // is left alone.\n if (expanded && activeId) {\n e.preventDefault();\n take(results[active]);\n }\n } else if (e.key === \"Tab\") {\n close();\n }\n }}\n className={cn(\n FIELD_BASE,\n hasLabel && FIELD_FLOATING_PAD,\n // Select's `SELECT_SM` box: a fixed 28px, so the caller's line height\n // cannot grow it.\n small && \"h-7 py-0 pe-2 ps-2 text-xs\",\n icon ? (small ? \"ps-7\" : \"ps-8\") : undefined,\n busy && (small ? \"pe-7\" : \"pe-9\"),\n field.isInvalid && FIELD_INVALID,\n inputClassName,\n )}\n />\n {busy && live && (\n // Decorative: the live region below already says \"Loading…\".\n <span\n className={cn(\n \"pointer-events-none absolute top-1/2 flex -translate-y-1/2\",\n small ? \"end-2\" : \"end-2.5\",\n )}\n >\n <Spinner label={null} className={small ? \"h-3.5 w-3.5\" : \"h-4 w-4\"} />\n </span>\n )}\n </div>\n {field.errorEl}\n {/* The live region, kept mounted so a change IS an announcement: focus stays\n in the field, and without it a reader typed into a geocoder and heard only\n their own letters. The panel's visible line is aria-hidden in favour of\n this, which also carries the row count the eye reads off the list. */}\n <div role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {!live\n ? null\n : statusLine !== null\n ? statusLine\n : results.length > 0\n ? labels.resultCount(results.length)\n : null}\n </div>\n {expanded &&\n rect &&\n typeof document !== \"undefined\" &&\n createPortal(\n <div\n // Every press inside the list keeps focus in the field — rows, the status\n // line, the scrollbar — or the input's blur would close the list first.\n role=\"presentation\"\n // Portalled out of the form's `dir`; the field's is put back. The list is\n // exactly the field's width, so `left` places it in either direction.\n dir={dir}\n onMouseDown={(e) => e.preventDefault()}\n className=\"fixed z-50 flex flex-col overflow-hidden rounded-md border border-[var(--border)] bg-[var(--bg-surface)] shadow-lg\"\n style={{ top, left: rect.left, width: rect.width, maxHeight }}\n >\n {results.length > 0 && (\n <ul\n id={listboxId}\n role=\"listbox\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n className=\"min-h-0 flex-1 overflow-y-auto py-1\"\n >\n {results.map((o, i) => {\n const startsGroup = o.group != null && o.group !== results[i - 1]?.group;\n return (\n // Keyed by group AND value, as in the core panel: an option may\n // appear once per group.\n <Fragment key={`${o.group ?? \"\"}|${String(o.value)}`}>\n {startsGroup && (\n <li\n role=\"presentation\"\n className=\"px-3 pb-0.5 pt-2 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1\"\n >\n {o.group}\n </li>\n )}\n <li role=\"presentation\">\n <button\n type=\"button\"\n id={optionId(i)}\n role=\"option\"\n // CHOSEN, never \"highlighted\" — the family's rule. This\n // field holds no value, so the only row that can be chosen\n // is the one whose label the text already is.\n aria-selected={fillOnSelect && o.label === value}\n // Listed, announced as unavailable, never taken: `take`\n // refuses it and the arrows pass it over.\n aria-disabled={o.disabled || undefined}\n tabIndex={-1}\n onClick={() => take(o)}\n onMouseEnter={() => {\n if (!o.disabled) setActive(i);\n }}\n className={cn(\n \"flex w-full items-center gap-2 px-3 text-start\",\n small ? \"py-1 text-xs\" : \"py-1.5 text-sm\",\n o.disabled\n ? DISABLED_ROW_CLASS\n : i === active\n ? \"bg-[var(--bg-active)]\"\n : \"hover:bg-[var(--bg-hover)]\",\n o.group != null && \"ps-6\",\n )}\n >\n {o.icon && (\n <span aria-hidden className=\"shrink-0 text-[var(--text-muted)]\">\n {o.icon}\n </span>\n )}\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[var(--text-primary)]\">\n {o.label}\n </span>\n {o.sublabel && (\n <span\n className={cn(\n \"block truncate text-[var(--text-placeholder)]\",\n small ? \"text-[11px]\" : \"text-xs\",\n )}\n >\n {o.sublabel}\n </span>\n )}\n </span>\n </button>\n </li>\n </Fragment>\n );\n })}\n </ul>\n )}\n {statusLine !== null && (\n // Visible, not live — the region above speaks for it.\n <div\n aria-hidden\n className={cn(\n small ? \"px-3 py-1.5 text-xs\" : \"px-3 py-2 text-sm\",\n failed && !hasStatus ? \"text-[var(--danger)]\" : \"text-[var(--text-muted)]\",\n results.length > 0 && \"border-t border-[var(--border)] text-xs\",\n )}\n >\n {statusLine}\n </div>\n )}\n </div>,\n document.body,\n )}\n </div>\n );\n}\n\nconst AutocompleteBase = forwardRef(AutocompleteInner);\nAutocompleteBase.displayName = \"Autocomplete\";\n\n/**\n * An inline, async-capable text field with a suggestion list under it — the\n * WAI-ARIA APG \"editable combobox with list autocomplete\".\n *\n * Two jobs, one control:\n * - **free text** (kastlan's address field): the text is the value, the list only\n * offers completions, and taking one fills the field (`fillOnSelect`, default);\n * - **search-then-act** (keksdose's address search): the text is a query, taking a\n * row calls `onSelect` and nothing is held (`fillOnSelect={false}`).\n *\n * How it differs from its siblings: {@link Combobox} is free text over a STATIC\n * string pool and opens on focus; {@link EntityCombobox} is a trigger holding an id.\n * This one keeps no value of its own, never resets the text, asks nothing below\n * `minChars`, and reports a failed lookup instead of showing stale rows.\n *\n * Focus never leaves the `<input>`: `aria-activedescendant` names the highlighted\n * row, `aria-controls` the list, and a polite live region says what the list now\n * holds. Keyboard: ↓/↑ move (↓ opens) over every row but a `disabled` one, Enter\n * takes the highlighted row (with none,\n * Enter is left to the form), Escape closes, Tab closes and moves on; Home/End stay\n * with the caret. An Escape that closes an open list is consumed and never reaches the\n * caller; with the list closed it does. For every other key a caller's `onKeyDown`\n * runs first and may `preventDefault()` to\n * keep a key for itself.\n *\n * The list is portalled and anchored under the field on every screen size: the\n * field already carries the keyboard, and `useAnchoredPanel` keeps the list clear\n * of it on a phone. There is no full-screen sheet as {@link Combobox} has.\n\n * Generic over the option value (`ComboOption<V>`); the ref is the `<input>`'s.\n */\nexport const Autocomplete = AutocompleteBase as <V extends string | number = string>(\n props: AutocompleteProps<V> & RefAttributes<HTMLInputElement>,\n) => ReactElement | null;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/autocomplete.tsx"],"sourcesContent":["import { Fragment, forwardRef, useId, useRef, useState } from \"react\";\nimport type {\n ComponentPropsWithoutRef,\n ForwardedRef,\n ReactElement,\n ReactNode,\n RefAttributes,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../lib/cn\";\nimport { FIELD_BASE, FIELD_FLOATING_PAD, FIELD_INVALID, Spinner } from \"./ui\";\nimport { useAnchoredPanel } from \"../hooks/use-anchored-panel\";\nimport { useAnchorDir } from \"./use-anchor-dir\";\nimport {\n ComboboxFieldLabel,\n DISABLED_ROW_CLASS,\n isOptionEnabled,\n stepEnabled,\n useActiveOptionScroll,\n useComboboxFieldError,\n useOptionSource,\n type ComboOption,\n} from \"./combobox-core\";\nimport { DEFAULT_COMBOBOX_LABELS, useKitLabels } 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\";\n\n/**\n * `value`/`onChange` are the TEXT's, and `onSelect` is \"a suggestion was taken\" —\n * not the DOM's text-selection event — so the input's own spellings of those three\n * are omitted. Everything else reaches the `<input>`, the way it does on {@link Input}.\n */\nexport interface AutocompleteProps<V extends string | number = string>\n extends Omit<\n ComponentPropsWithoutRef<\"input\">,\n \"value\" | \"defaultValue\" | \"onChange\" | \"onSelect\" | \"children\" | \"type\" | \"size\"\n > {\n /** What is in the field. Controlled, and never reset by the component: opening,\n * closing and a failed lookup all leave it exactly as typed. */\n value: string;\n /** Every keystroke — and, with `fillOnSelect`, the label of a taken suggestion. */\n onChange: (text: string) => void;\n /** Suggestions the caller already has (e.g. from its own query hook). Narrowed by\n * the text unless `filter={false}`. An option with `disabled: true` is listed but\n * cannot be taken — see {@link ComboOption.disabled}. */\n options?: ComboOption<V>[];\n /** Or: fetch them. Debounced (`debounceMs`), race-safe, only at `minChars` and up,\n * never while the field is idle; a rejection shows `loadErrorLabel` and empties\n * the list rather than leaving the previous text's rows under it. */\n loadOptions?: (query: string) => Promise<ComboOption<V>[]>;\n /** Narrow `options` by label/sublabel substring. Default `true`. Pass `false` for\n * a list a server has already searched and ranked — it is shown as given. */\n filter?: boolean;\n /** External loading flag (a caller-side fetch), OR-ed with `loadOptions`'. */\n loading?: boolean;\n /** Below this many characters nothing is offered or fetched. Default 1: an empty\n * field asks nothing — focusing it is not a search. */\n minChars?: number;\n /** Quiet time before `loadOptions` runs. Default 300 ms — an ordinary typist's\n * inter-key interval is 150–250 ms, so the pickers' 150 fires on nearly every\n * letter, which a rate-limited geocoder cannot afford. */\n debounceMs?: number;\n /**\n * Whether the list MAY show — controlled. Omit (or pass `undefined`) and the field\n * decides: open while focused, until Escape, Tab or a taken row. `false` keeps it\n * shut whatever the user does, and stops `loadOptions` asking — keksdose's address\n * search, with its confirm map up, where it used to pass `minChars={Infinity}`.\n * `true` shows it even unfocused.\n *\n * Even open, the list only APPEARS when it has something to show (rows, or a\n * status line); `aria-expanded` follows what appears, not this flag.\n */\n open?: boolean;\n /** The field wants the list open or shut — focus, typing, ↓/↑ open it; blur,\n * Escape, Tab and taking a row shut it. Called on every change, controlled or not. */\n onOpenChange?: (open: boolean) => void;\n /**\n * `\"sm\"`: the 28px, 12px-type field of {@link Select}'s `size=\"sm\"`, with the icon,\n * spinner and list rows scaled to match — for a card or toolbar whose buttons are\n * small. `\"md\"` (default) is the form field. Unlabelled only, as on `Select`: a\n * floating label needs the tall box, so a labelled field ignores `\"sm\"`.\n *\n * A NUMBER is still the native `size` attribute (the width in characters), passed\n * straight through.\n */\n size?: \"sm\" | \"md\" | number;\n /** A suggestion was taken (click, or Enter on the highlighted row). */\n onSelect?: (option: ComboOption<V>) => void;\n /**\n * Put the taken suggestion's label into the field (`onChange(label)`). Default\n * `true` — the free-text case, where the text IS the value and a suggestion only\n * completes it (an address field). Pass `false` where taking a row is an ACTION\n * and the field is only the search that found it; the text then stays as typed.\n */\n fillOnSelect?: boolean;\n /** A floating label, as on {@link Combobox} — a real `<label for>` on the input.\n * Names the field (`aria-labelledby`) unless an `aria-label` is given. */\n label?: ReactNode;\n /** Leading decoration inside the field (a pin, a magnifier). Decorative: the\n * label names the field. An `<svg>` child is sized by the field — 16px, or 14px\n * at `size=\"sm\"` — so a lucide icon needs no class of its own. */\n icon?: ReactNode;\n /** Required and unanswered — {@link FIELD_INVALID}. */\n invalid?: boolean;\n /** What is wrong with the VALUE, as {@link Input}'s `error`: under the field, on\n * its `aria-describedby`, implies `invalid`. Not a failed lookup — that is\n * `loadErrorLabel`, shown in the list. */\n error?: ReactNode;\n /**\n * Standing advice — {@link Combobox}'s `hint`, so this field reads like every other\n * (keksdose K4): plain TEXT is a caption under the field on the input's\n * `aria-describedby`, before any error; a {@link FieldHint} \"?\" rides the label line,\n * or with no label sits at the field's end edge, outside the box. Not the list's\n * `status` line, which talks about the lookup, not the field.\n */\n hint?: ReactNode;\n /**\n * The caller's own line in the list, replacing the automatic one (loading / failed\n * / no results). For what only the caller knows: \"offline\", \"the address service\n * is switched off\", a privacy note, the hint a caller-fetched list needs below its\n * own minimum. While set, the list opens even with no rows. Announced politely.\n */\n status?: ReactNode;\n /** Default: `combobox.noResults` from the {@link UiKitProvider}, else English. */\n emptyLabel?: string;\n /** Default: `combobox.loadError`. */\n loadErrorLabel?: string;\n /** Classes for the `<input>` itself; `className` styles the wrapper. */\n inputClassName?: string;\n /**\n * Why the field cannot be changed — {@link Button}'s `disabledReason`, the Combobox\n * family's write lock (keksdose G2, 0.23), for a field whose pick SAVES: an address\n * search whose taken row writes the address, a lookup that links a record.\n *\n * With a reason the input stays focusable and `aria-disabled`, is `readOnly` (the\n * settled grey FIELD_BASE gives a `[readonly]` field), opens no list and asks no\n * `loadOptions` — whatever `open` says — and nothing reaches `onChange`, `onSelect` or\n * `onOpenChange(true)`. Enter is swallowed, so a locked field does not submit the form\n * around it, and a caller's `onKeyDown` does not hear it; every other key still\n * reaches the caller (an Escape that closes its panel) and the caret. The reason is in\n * the kit {@link Tooltip} and on the input's `aria-describedby`. Wins over `disabled`.\n */\n disabledReason?: ReactNode;\n /**\n * This field COMMITS. Under a locked {@link WriteLockProvider} it is locked the\n * `disabledReason` way with the lock's reason (which wins over its own). A search\n * whose result is only draft state — the form's Save writes it — leaves this off and\n * stays live under the lock. No provider, or an unlocked one: no effect.\n */\n commit?: boolean;\n}\n\nfunction AutocompleteInner<V extends string | number = string>(\n {\n value,\n onChange,\n options,\n loadOptions,\n filter,\n loading,\n minChars = 1,\n debounceMs = 300,\n onSelect,\n fillOnSelect = true,\n label,\n icon,\n invalid,\n error,\n hint,\n status,\n emptyLabel,\n loadErrorLabel,\n open: openProp,\n onOpenChange,\n size,\n className,\n inputClassName,\n id,\n disabled,\n disabledReason,\n commit,\n onKeyDown,\n onFocus,\n onBlur,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n ...rest\n }: AutocompleteProps<V>,\n ref: ForwardedRef<HTMLInputElement>,\n) {\n const generated = useId();\n const fieldId = id ?? generated;\n // Off the GENERATED id: a caller's `id` is theirs to collide with.\n const listboxId = `${generated}-listbox`;\n const labelId = `${generated}-label`;\n const optionId = (index: number) => `${generated}-option-${index}`;\n const fieldRef = useRef<HTMLDivElement>(null);\n const labels = useKitLabels(\"combobox\", DEFAULT_COMBOBOX_LABELS, {\n noResults: emptyLabel,\n loadError: loadErrorLabel,\n });\n const hintParts = useFieldHint(hint, ariaDescribedBy);\n const field = useComboboxFieldError(error, invalid, hintParts.describedBy);\n\n /** The user's intent: the field is focused and the list has not been dismissed.\n * Whether anything SHOWS is decided below, from what there is to show. */\n const [ownOpen, setOwnOpen] = useState(false);\n // Controlled when the caller passes a boolean. The own state is kept up to date\n // either way, so a caller that controls only SOMETIMES (`open={confirming ? false :\n // undefined}`) hands back a field that is exactly as open as focus says it is.\n const open = openProp ?? ownOpen;\n const setOpen = (next: boolean) => {\n setOwnOpen(next);\n if (next !== open) onOpenChange?.(next);\n };\n const [active, setActive] = useState(-1);\n // The lock: focusable, `readOnly`, no list — see `disabledReason`. Folded into `live`,\n // so a locked field asks nothing and shows nothing even with `open` held true.\n const lock = useLockReason(commit, disabledReason);\n const locked = lock.locked;\n const live = open && !disabled && !locked;\n const { results, busy, failed, tooShort } = useOptionSource<V>({\n options,\n loadOptions,\n loading,\n filter,\n minChars,\n debounceMs,\n query: value,\n active: live,\n });\n\n const hasStatus = status !== undefined && status !== null && status !== false && status !== \"\";\n // The visible line under the rows. Nothing below `minChars` unless the caller has\n // something to say — an empty field opening a box that says \"type more\" is noise.\n const statusLine: ReactNode = hasStatus\n ? status\n : tooShort\n ? null\n : busy && results.length === 0\n ? labels.loading\n : failed\n ? labels.loadError\n : !busy && results.length === 0\n ? labels.noResults\n : null;\n const expanded = live && (results.length > 0 || statusLine !== null);\n // A disabled row is never the keyboard's — not even when a list that changed under\n // the highlight put one there.\n const activeId = expanded && isOptionEnabled(results[active]) ? optionId(active) : undefined;\n useActiveOptionScroll(activeId);\n const { rect, top, maxHeight } = useAnchoredPanel(fieldRef, expanded, { preferredHeight: 256 });\n const dir = useAnchorDir(fieldRef, expanded);\n\n const close = () => {\n setOpen(false);\n setActive(-1);\n };\n const take = (o: ComboOption<V>) => {\n if (o.disabled || locked) return;\n if (fillOnSelect) onChange(o.label);\n onSelect?.(o);\n close();\n };\n\n const hasLabel = label !== undefined;\n // `size=\"sm\"` is for an UNLABELLED field, as on Select: the floating label needs the\n // tall box. A number is the native attribute.\n const small = size === \"sm\" && !hasLabel;\n const nativeSize = typeof size === \"number\" ? size : undefined;\n // The caller's name wins; else the floating label, by reference so a non-string\n // label still names the field.\n const labelledBy =\n ariaLabel === undefined ? (ariaLabelledBy ?? (hasLabel ? labelId : undefined)) : undefined;\n // While locked the field sits in the reason's Tooltip — in a fragment with a hidden\n // copy of the reason, Button's anatomy; `block` so a full-width field stays full width.\n const withLock = (box: ReactNode) =>\n locked ? (\n <LockedReason lock={lock} className=\"block\">\n {box}\n </LockedReason>\n ) : (\n box\n );\n\n return (\n // `relative`: the floating label and the live region's `sr-only` both need a\n // local containing block.\n <div className={cn(\"relative\", className)}>\n {/* A real <label for> (lenkbank), and still `aria-labelledby`'s target, so the\n name — and the listbox's, which borrows it — is exactly what it was. */}\n {hasLabel && hintParts.labelHint === undefined && (\n <ComboboxFieldLabel id={labelId} htmlFor={fieldId}>\n {label}\n </ComboboxFieldLabel>\n )}\n <EndHintRow hint={hasLabel ? undefined : hintParts.labelHint}>\n {withLock(\n <div ref={fieldRef} className={cn(\"relative\", locked && \"cursor-not-allowed\")}>\n {icon && (\n <span\n aria-hidden\n className={cn(\n \"pointer-events-none absolute flex text-[var(--text-muted)]\",\n small ? \"start-2 [&>svg]:size-3.5\" : \"start-2.5 [&>svg]:size-4\",\n // Labelled, the icon sits on the VALUE's line — the one line box below\n // FIELD_FLOATING_PAD's `pt-4` and the 1px border — not on the middle of\n // the box. Centred on the box it rose into the top strip and sat on the\n // label's first letters, which float at the same start inset. On the\n // value line it is beside what it describes, and the label keeps the\n // start edge every other label in the form's column shares.\n hasLabel\n ? \"top-[calc(1rem+1px)] h-5 items-center\"\n : \"top-1/2 -translate-y-1/2\",\n )}\n >\n {icon}\n </span>\n )}\n <input\n {...rest}\n ref={ref}\n id={fieldId}\n size={nativeSize}\n type=\"text\"\n value={value}\n // Locked: focusable, `readOnly`, `aria-disabled` — see `disabledReason`.\n disabled={locked ? undefined : disabled}\n readOnly={locked || rest.readOnly}\n aria-disabled={locked || rest[\"aria-disabled\"]}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={expanded}\n // Required by the role, and set while closed too, as on the siblings.\n aria-controls={listboxId}\n aria-activedescendant={activeId}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n aria-invalid={field.isInvalid || rest[\"aria-invalid\"] || undefined}\n aria-describedby={mergeDescribedBy(field.describedBy, locked && lock.reasonId)}\n autoComplete=\"off\"\n onFocus={(e) => {\n onFocus?.(e);\n // A locked field takes focus to say why, and opens nothing.\n if (locked) return;\n // A seeded field (keksdose's `initialQuery`) is looked up as it is\n // focused; an empty one asks nothing, because of `minChars`.\n setOpen(true);\n }}\n onBlur={(e) => {\n onBlur?.(e);\n close();\n }}\n onChange={(e) => {\n if (locked) return;\n onChange(e.target.value);\n setOpen(true);\n setActive(-1);\n }}\n onKeyDown={(e) => {\n // Locked: Enter is swallowed (no form submit, no caller's \"search now\");\n // every other key is the caller's and the caret's. No list to drive.\n if (locked) {\n if (e.key === \"Enter\") e.preventDefault();\n else onKeyDown?.(e);\n return;\n }\n // An Escape that closes the OPEN list is the list's, and is consumed before\n // the caller sees it. A caller whose Escape means \"close the panel\" (keksdose's\n // address search) otherwise closed the whole panel when the user only meant\n // to dismiss the suggestions — the opposite of what the docs promised.\n if (e.key === \"Escape\" && expanded) {\n e.preventDefault();\n e.stopPropagation();\n close();\n return;\n }\n onKeyDown?.(e);\n if (e.defaultPrevented) return;\n // Disabled rows are passed over; at either end the highlight stays put.\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n if (!open) setOpen(true);\n else setActive((i) => stepEnabled(results, i, 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n if (!open) setOpen(true);\n // From \"nothing highlighted\", Up goes to the bottom, as the APG has it.\n else setActive((i) => stepEnabled(results, i < 0 ? results.length : i, -1));\n } else if (e.key === \"Enter\") {\n // No row highlighted: the text is the answer, and a form's own submit\n // is left alone.\n if (expanded && activeId) {\n e.preventDefault();\n take(results[active]);\n }\n } else if (e.key === \"Tab\") {\n close();\n }\n }}\n className={cn(\n FIELD_BASE,\n hasLabel && FIELD_FLOATING_PAD,\n // Select's `SELECT_SM` box: a fixed 28px, so the caller's line height\n // cannot grow it.\n small && \"h-7 py-0 pe-2 ps-2 text-xs\",\n icon ? (small ? \"ps-7\" : \"ps-8\") : undefined,\n busy && (small ? \"pe-7\" : \"pe-9\"),\n field.isInvalid && FIELD_INVALID,\n inputClassName,\n )}\n />\n {busy && live && (\n // Decorative: the live region below already says \"Loading…\".\n <span\n className={cn(\n \"pointer-events-none absolute top-1/2 flex -translate-y-1/2\",\n small ? \"end-2\" : \"end-2.5\",\n )}\n >\n <Spinner label={null} className={small ? \"h-3.5 w-3.5\" : \"h-4 w-4\"} />\n </span>\n )}\n </div>,\n )}\n </EndHintRow>\n {/* With a \"?\" the label shares the top strip with it, after the field so the \"?\"\n follows the control in the tab order (as on Input and Select). */}\n {hasLabel && hintParts.labelHint !== undefined && (\n <StaticLabelRow hint={hintParts.labelHint}>\n <ComboboxFieldLabel id={labelId} htmlFor={fieldId} className={LABEL_IN_ROW}>\n {label}\n </ComboboxFieldLabel>\n </StaticLabelRow>\n )}\n <FieldCaption parts={hintParts} />\n {field.errorEl}\n {/* The live region, kept mounted so a change IS an announcement: focus stays\n in the field, and without it a reader typed into a geocoder and heard only\n their own letters. The panel's visible line is aria-hidden in favour of\n this, which also carries the row count the eye reads off the list. */}\n <div role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {!live\n ? null\n : statusLine !== null\n ? statusLine\n : results.length > 0\n ? labels.resultCount(results.length)\n : null}\n </div>\n {expanded &&\n rect &&\n typeof document !== \"undefined\" &&\n createPortal(\n <div\n // Every press inside the list keeps focus in the field — rows, the status\n // line, the scrollbar — or the input's blur would close the list first.\n role=\"presentation\"\n // Portalled out of the form's `dir`; the field's is put back. The list is\n // exactly the field's width, so `left` places it in either direction.\n dir={dir}\n onMouseDown={(e) => e.preventDefault()}\n className=\"fixed z-50 flex flex-col overflow-hidden rounded-md border border-[var(--border)] bg-[var(--bg-surface)] shadow-lg\"\n style={{ top, left: rect.left, width: rect.width, maxHeight }}\n >\n {results.length > 0 && (\n <ul\n id={listboxId}\n role=\"listbox\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n className=\"min-h-0 flex-1 overflow-y-auto py-1\"\n >\n {results.map((o, i) => {\n const startsGroup = o.group != null && o.group !== results[i - 1]?.group;\n return (\n // Keyed by group AND value, as in the core panel: an option may\n // appear once per group.\n <Fragment key={`${o.group ?? \"\"}|${String(o.value)}`}>\n {startsGroup && (\n <li\n role=\"presentation\"\n className=\"px-3 pb-0.5 pt-2 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1\"\n >\n {o.group}\n </li>\n )}\n <li role=\"presentation\">\n <button\n type=\"button\"\n id={optionId(i)}\n role=\"option\"\n // CHOSEN, never \"highlighted\" — the family's rule. This\n // field holds no value, so the only row that can be chosen\n // is the one whose label the text already is.\n aria-selected={fillOnSelect && o.label === value}\n // Listed, announced as unavailable, never taken: `take`\n // refuses it and the arrows pass it over.\n aria-disabled={o.disabled || undefined}\n tabIndex={-1}\n onClick={() => take(o)}\n onMouseEnter={() => {\n if (!o.disabled) setActive(i);\n }}\n className={cn(\n \"flex w-full items-center gap-2 px-3 text-start\",\n small ? \"py-1 text-xs\" : \"py-1.5 text-sm\",\n o.disabled\n ? DISABLED_ROW_CLASS\n : i === active\n ? \"bg-[var(--bg-active)]\"\n : \"hover:bg-[var(--bg-hover)]\",\n o.group != null && \"ps-6\",\n )}\n >\n {o.icon && (\n <span aria-hidden className=\"shrink-0 text-[var(--text-muted)]\">\n {o.icon}\n </span>\n )}\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[var(--text-primary)]\">\n {o.label}\n </span>\n {o.sublabel && (\n <span\n className={cn(\n \"block truncate text-[var(--text-placeholder)]\",\n small ? \"text-[11px]\" : \"text-xs\",\n )}\n >\n {o.sublabel}\n </span>\n )}\n </span>\n </button>\n </li>\n </Fragment>\n );\n })}\n </ul>\n )}\n {statusLine !== null && (\n // Visible, not live — the region above speaks for it.\n <div\n aria-hidden\n className={cn(\n small ? \"px-3 py-1.5 text-xs\" : \"px-3 py-2 text-sm\",\n failed && !hasStatus ? \"text-[var(--danger)]\" : \"text-[var(--text-muted)]\",\n results.length > 0 && \"border-t border-[var(--border)] text-xs\",\n )}\n >\n {statusLine}\n </div>\n )}\n </div>,\n document.body,\n )}\n </div>\n );\n}\n\nconst AutocompleteBase = forwardRef(AutocompleteInner);\nAutocompleteBase.displayName = \"Autocomplete\";\n\n/**\n * An inline, async-capable text field with a suggestion list under it — the\n * WAI-ARIA APG \"editable combobox with list autocomplete\".\n *\n * Two jobs, one control:\n * - **free text** (kastlan's address field): the text is the value, the list only\n * offers completions, and taking one fills the field (`fillOnSelect`, default);\n * - **search-then-act** (keksdose's address search): the text is a query, taking a\n * row calls `onSelect` and nothing is held (`fillOnSelect={false}`).\n *\n * How it differs from its siblings: {@link Combobox} is free text over a STATIC\n * string pool and opens on focus; {@link EntityCombobox} is a trigger holding an id.\n * This one keeps no value of its own, never resets the text, asks nothing below\n * `minChars`, and reports a failed lookup instead of showing stale rows.\n *\n * Focus never leaves the `<input>`: `aria-activedescendant` names the highlighted\n * row, `aria-controls` the list, and a polite live region says what the list now\n * holds. Keyboard: ↓/↑ move (↓ opens) over every row but a `disabled` one, Enter\n * takes the highlighted row (with none,\n * Enter is left to the form), Escape closes, Tab closes and moves on; Home/End stay\n * with the caret. An Escape that closes an open list is consumed and never reaches the\n * caller; with the list closed it does. For every other key a caller's `onKeyDown`\n * runs first and may `preventDefault()` to\n * keep a key for itself.\n *\n * The list is portalled and anchored under the field on every screen size: the\n * field already carries the keyboard, and `useAnchoredPanel` keeps the list clear\n * of it on a phone. There is no full-screen sheet as {@link Combobox} has.\n\n * Generic over the option value (`ComboOption<V>`); the ref is the `<input>`'s.\n */\nexport const Autocomplete = AutocompleteBase as <V extends string | number = string>(\n props: AutocompleteProps<V> & RefAttributes<HTMLInputElement>,\n) => ReactElement | null;\n"],"mappings":"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","names":[]}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentPropsWithoutRef, ReactNode, Ref, MouseEvent, ReactElement } from 'react';
|
|
3
|
-
import { f as ButtonVariant, d as ButtonSize } from '../
|
|
4
|
-
import '
|
|
3
|
+
import { f as ButtonVariant, d as ButtonSize } 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';
|
|
10
|
+
import '../data-table-labels-B7OdnM0S.js';
|
|
11
|
+
import './data-table-sort.js';
|
|
12
|
+
import './swipeable-row.js';
|
|
5
13
|
import './mini-calendar.js';
|
|
6
14
|
import './calendar-heatmap.js';
|
|
7
15
|
import './popover.js';
|
|
8
16
|
import './chip.js';
|
|
9
|
-
import 'lucide-react';
|
|
10
17
|
import './field-sync.js';
|
|
11
|
-
import './tooltip.js';
|
|
12
|
-
import '../hooks/use-anchored-rect.js';
|
|
13
|
-
import '../lib/clipping.js';
|
|
14
18
|
import '../wizard/types.js';
|
|
15
19
|
import '../tour/tour.js';
|
|
16
20
|
import '../search/command-palette.js';
|
|
@@ -24,7 +28,6 @@ import './sparkline.js';
|
|
|
24
28
|
import './stat-tile.js';
|
|
25
29
|
import './signature-pad.js';
|
|
26
30
|
import './password-strength.js';
|
|
27
|
-
import './danger-confirm.js';
|
|
28
31
|
import './swatch-picker.js';
|
|
29
32
|
import './tile-radio.js';
|
|
30
33
|
import './icon-picker.js';
|
|
@@ -32,11 +35,7 @@ import './dialog-frame.js';
|
|
|
32
35
|
import './modal.js';
|
|
33
36
|
import '../hooks/use-search-param-state.js';
|
|
34
37
|
import './measured-grid.js';
|
|
35
|
-
import '../feedback-attachment-WFiXJ8We.js';
|
|
36
|
-
import '../feedback/feedback-thread.js';
|
|
37
|
-
import '../feedback/feedback-inbox.js';
|
|
38
38
|
import './account-settings-labels.js';
|
|
39
|
-
import './confirm-dialog.js';
|
|
40
39
|
import './floating-panel.js';
|
|
41
40
|
import './bulk-action-bar.js';
|
|
42
41
|
import './list.js';
|
|
@@ -55,14 +54,20 @@ import './write-lock.js';
|
|
|
55
54
|
import './legal.js';
|
|
56
55
|
import './account-chips.js';
|
|
57
56
|
import '../lib/format.js';
|
|
58
|
-
import '../data-table-3mi2R3so.js';
|
|
59
|
-
import './data-table-sort.js';
|
|
60
|
-
import './swipeable-row.js';
|
|
61
57
|
import './reauth-dialog.js';
|
|
62
58
|
import './server-wake.js';
|
|
63
59
|
import '../lib/server-wake.js';
|
|
64
60
|
import './translation-review-labels.js';
|
|
65
61
|
import '../lib/translation-review.js';
|
|
62
|
+
import './country-select.js';
|
|
63
|
+
import './inline-edit-field.js';
|
|
64
|
+
import '../lib/iban.js';
|
|
65
|
+
import '../lib/phone.js';
|
|
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';
|
|
66
71
|
|
|
67
72
|
interface ButtonGroupProps extends Omit<ComponentPropsWithoutRef<"div">, "role"> {
|
|
68
73
|
/** `horizontal` (default): side by side, in reading order. `vertical`: stacked —
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { C as CalculatorLabels } from '../
|
|
3
|
-
import '
|
|
2
|
+
import { C as CalculatorLabels } from '../feedback-BxeQVzwq.js';
|
|
3
|
+
import '../feedback-attachment-fGAzZPf0.js';
|
|
4
|
+
import '../feedback/feedback-inbox.js';
|
|
5
|
+
import 'lucide-react';
|
|
6
|
+
import './tooltip.js';
|
|
7
|
+
import '../hooks/use-anchored-rect.js';
|
|
8
|
+
import '../lib/clipping.js';
|
|
9
|
+
import '../data-table-labels-B7OdnM0S.js';
|
|
10
|
+
import './data-table-sort.js';
|
|
11
|
+
import './swipeable-row.js';
|
|
4
12
|
import './mini-calendar.js';
|
|
5
13
|
import './calendar-heatmap.js';
|
|
6
14
|
import './popover.js';
|
|
7
15
|
import './chip.js';
|
|
8
|
-
import 'lucide-react';
|
|
9
16
|
import './field-sync.js';
|
|
10
|
-
import './tooltip.js';
|
|
11
|
-
import '../hooks/use-anchored-rect.js';
|
|
12
|
-
import '../lib/clipping.js';
|
|
13
17
|
import '../wizard/types.js';
|
|
14
18
|
import '../tour/tour.js';
|
|
15
19
|
import '../search/command-palette.js';
|
|
@@ -23,7 +27,6 @@ import './sparkline.js';
|
|
|
23
27
|
import './stat-tile.js';
|
|
24
28
|
import './signature-pad.js';
|
|
25
29
|
import './password-strength.js';
|
|
26
|
-
import './danger-confirm.js';
|
|
27
30
|
import './swatch-picker.js';
|
|
28
31
|
import './tile-radio.js';
|
|
29
32
|
import './icon-picker.js';
|
|
@@ -31,11 +34,7 @@ import './dialog-frame.js';
|
|
|
31
34
|
import './modal.js';
|
|
32
35
|
import '../hooks/use-search-param-state.js';
|
|
33
36
|
import './measured-grid.js';
|
|
34
|
-
import '../feedback-attachment-WFiXJ8We.js';
|
|
35
|
-
import '../feedback/feedback-thread.js';
|
|
36
|
-
import '../feedback/feedback-inbox.js';
|
|
37
37
|
import './account-settings-labels.js';
|
|
38
|
-
import './confirm-dialog.js';
|
|
39
38
|
import './floating-panel.js';
|
|
40
39
|
import './bulk-action-bar.js';
|
|
41
40
|
import './list.js';
|
|
@@ -54,14 +53,20 @@ import './write-lock.js';
|
|
|
54
53
|
import './legal.js';
|
|
55
54
|
import './account-chips.js';
|
|
56
55
|
import '../lib/format.js';
|
|
57
|
-
import '../data-table-3mi2R3so.js';
|
|
58
|
-
import './data-table-sort.js';
|
|
59
|
-
import './swipeable-row.js';
|
|
60
56
|
import './reauth-dialog.js';
|
|
61
57
|
import './server-wake.js';
|
|
62
58
|
import '../lib/server-wake.js';
|
|
63
59
|
import './translation-review-labels.js';
|
|
64
60
|
import '../lib/translation-review.js';
|
|
61
|
+
import './country-select.js';
|
|
62
|
+
import './inline-edit-field.js';
|
|
63
|
+
import '../lib/iban.js';
|
|
64
|
+
import '../lib/phone.js';
|
|
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';
|
|
65
70
|
|
|
66
71
|
/** Screen-reader names for the calculator panel's own controls — any part of the
|
|
67
72
|
* kit's `calculator` namespace. Once three optional keys of its own; widened, not
|