@devslab/dds-react 0.25.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/choice-CWXdcWkH.js +295 -0
- package/dist/choice-CWXdcWkH.js.map +1 -0
- package/dist/combobox.js +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/choice.d.ts.map +1 -1
- package/dist/select-picker.js +1 -1
- package/dist/{time-picker-BQ7BT6-u.js → time-picker-BNmQMQdq.js} +2 -2
- package/dist/{time-picker-BQ7BT6-u.js.map → time-picker-BNmQMQdq.js.map} +1 -1
- package/dist/time-picker.js +1 -1
- package/package.json +4 -4
- package/dist/choice-N-5K_ggs.js +0 -309
- package/dist/choice-N-5K_ggs.js.map +0 -1
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { n as e, r as t, t as n } from "./choice-types-kSaEnZPr.js";
|
|
2
|
+
import { useEffect as r, useMemo as i, useRef as a, useState as o } from "react";
|
|
3
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
4
|
+
import { Portal as l } from "@ark-ui/react/portal";
|
|
5
|
+
import { Combobox as u, createListCollection as d } from "@ark-ui/react/combobox";
|
|
6
|
+
import { Select as f } from "@ark-ui/react/select";
|
|
7
|
+
import { defaultRangeExtractor as p, useVirtualizer as m } from "@tanstack/react-virtual";
|
|
8
|
+
//#region src/internal/choice.tsx
|
|
9
|
+
function h(h) {
|
|
10
|
+
t(h.items);
|
|
11
|
+
let [g, _] = o(h.defaultValue ?? ""), v = h.value ?? g, y = h.items.find((e) => e.value === v) ?? (h.selectedOption?.value === v ? h.selectedOption : void 0), b = y?.label ?? v, [x, S] = o(h.defaultInputValue ?? b), C = h.inputValue ?? x, w = (e) => {
|
|
12
|
+
S(e), h.onDraftChange?.(e);
|
|
13
|
+
}, [T, E] = o(!1), [D, O] = o(null), k = a(null), A = a(null), j = a(null), [M, N] = o(null);
|
|
14
|
+
r(() => {
|
|
15
|
+
let e = k.current;
|
|
16
|
+
e && N(e.closest("[role=\"dialog\"], [role=\"alertdialog\"]") ?? e.ownerDocument.body);
|
|
17
|
+
}, []);
|
|
18
|
+
let P = a(null), F = a(!1), I = a({
|
|
19
|
+
value: v,
|
|
20
|
+
label: b
|
|
21
|
+
}), L = a(null), R = (e) => h.items.find((t) => t.value === e)?.label ?? (h.selectedOption?.value === e ? h.selectedOption.label : e), z = {
|
|
22
|
+
...n,
|
|
23
|
+
...h.messages
|
|
24
|
+
}, B = h.disabled || h.readOnly, V = (e) => {
|
|
25
|
+
(L.current?.from !== C || L.current.to !== e) && (L.current = null, h.inputValue === void 0 && w(e), h.onInputValueChange?.(e));
|
|
26
|
+
}, H = (e) => {
|
|
27
|
+
e !== C && (L.current?.from !== C || L.current.to !== e) && (L.current = {
|
|
28
|
+
from: C,
|
|
29
|
+
to: e
|
|
30
|
+
}, h.inputValue === void 0 ? w(e) : h.onInputValueChange?.(e));
|
|
31
|
+
}, U = (e) => {
|
|
32
|
+
h.value === void 0 && _(e), h.onValueChange?.(e);
|
|
33
|
+
};
|
|
34
|
+
r(() => {
|
|
35
|
+
(I.current.value !== v || I.current.label !== b) && (I.current = {
|
|
36
|
+
value: v,
|
|
37
|
+
label: b
|
|
38
|
+
}, H(b));
|
|
39
|
+
}, [v, b]), r(() => {
|
|
40
|
+
e() && v && !y && console.warn(`DDS choice: no label supplied for selected ID ${JSON.stringify(v)}; pass selectedOption when the selection is outside items.`);
|
|
41
|
+
}, [v, y]), r(() => {
|
|
42
|
+
let e = A.current?.form;
|
|
43
|
+
if (!e) return;
|
|
44
|
+
let t = (e) => setTimeout(() => {
|
|
45
|
+
if (e.defaultPrevented) return;
|
|
46
|
+
h.onFormReset?.();
|
|
47
|
+
let t = h.value ?? h.defaultValue ?? "", n = R(t);
|
|
48
|
+
I.current = {
|
|
49
|
+
value: t,
|
|
50
|
+
label: n
|
|
51
|
+
}, h.value === void 0 && _(t);
|
|
52
|
+
let r = h.defaultInputValue ?? n;
|
|
53
|
+
L.current = null, h.inputValue === void 0 ? w(r) : H(r), E(!1), k.current instanceof HTMLInputElement && (k.current.value = h.inputValue ?? r), A.current && (A.current.value = t);
|
|
54
|
+
});
|
|
55
|
+
return e.addEventListener("reset", t), () => e.removeEventListener("reset", t);
|
|
56
|
+
}, [
|
|
57
|
+
h.defaultValue,
|
|
58
|
+
h.defaultInputValue,
|
|
59
|
+
h.value,
|
|
60
|
+
h.inputValue,
|
|
61
|
+
h.items,
|
|
62
|
+
h.selectedOption,
|
|
63
|
+
h.form
|
|
64
|
+
]);
|
|
65
|
+
let W = i(() => h.searchable && h.filterMode !== "external" && C !== b ? h.items.filter((e) => h.matchItem ? h.matchItem(e, C) : e.label.toLocaleLowerCase().includes(C.toLocaleLowerCase())) : h.items, [
|
|
66
|
+
h.items,
|
|
67
|
+
h.searchable,
|
|
68
|
+
h.filterMode,
|
|
69
|
+
C,
|
|
70
|
+
b,
|
|
71
|
+
h.matchItem
|
|
72
|
+
]), G = i(() => d({
|
|
73
|
+
items: W,
|
|
74
|
+
itemToString: (e) => e.label,
|
|
75
|
+
itemToValue: (e) => e.value,
|
|
76
|
+
isItemDisabled: (e) => !!e.disabled
|
|
77
|
+
}), [W]), K = !!h.virtualization, q = h.virtualization ? h.virtualization.itemHeight : void 0, J = Number.isFinite(q) ? Math.max(40, q) : 40, Y = W.findIndex((e) => e.value === D), X = m({
|
|
78
|
+
count: W.length,
|
|
79
|
+
getScrollElement: () => j.current,
|
|
80
|
+
estimateSize: () => J,
|
|
81
|
+
overscan: h.virtualization ? h.virtualization.overscan ?? 5 : 5,
|
|
82
|
+
enabled: K && T,
|
|
83
|
+
initialRect: {
|
|
84
|
+
width: 0,
|
|
85
|
+
height: 320
|
|
86
|
+
},
|
|
87
|
+
rangeExtractor: (e) => {
|
|
88
|
+
let t = p(e);
|
|
89
|
+
return Y >= 0 && !t.includes(Y) && t.push(Y), t.sort((e, t) => e - t);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
r(() => {
|
|
93
|
+
O(null), K && T && X.scrollToIndex(Math.max(0, W.findIndex((e) => e.value === v)), { align: h.centerSelected ? "center" : "auto" });
|
|
94
|
+
}, [W, T]), r(() => {
|
|
95
|
+
let e = j.current;
|
|
96
|
+
if (!h.centerSelected || !T || K || !e) return;
|
|
97
|
+
let t = requestAnimationFrame(() => {
|
|
98
|
+
let t = e.querySelector("[data-part=\"item\"][data-state=\"checked\"]");
|
|
99
|
+
if (!t) return;
|
|
100
|
+
let n = e.getBoundingClientRect(), r = t.getBoundingClientRect();
|
|
101
|
+
e.scrollTop += r.top - n.top - (e.clientHeight - r.height) / 2;
|
|
102
|
+
});
|
|
103
|
+
return () => cancelAnimationFrame(t);
|
|
104
|
+
}, [
|
|
105
|
+
T,
|
|
106
|
+
h.centerSelected,
|
|
107
|
+
K
|
|
108
|
+
]);
|
|
109
|
+
let Z = h.searchable ? u : f, Q = K ? X.getVirtualItems().map((e) => ({
|
|
110
|
+
index: e.index,
|
|
111
|
+
start: e.start
|
|
112
|
+
})) : W.map((e, t) => ({
|
|
113
|
+
index: t,
|
|
114
|
+
start: 0
|
|
115
|
+
}));
|
|
116
|
+
K && Y >= 0 && !Q.some((e) => e.index === Y) && Q.push({
|
|
117
|
+
index: Y,
|
|
118
|
+
start: Y * J
|
|
119
|
+
});
|
|
120
|
+
let $ = h.loading ? z.loading : h.error ? typeof h.error == "string" ? h.error : z.error : W.length === 0 ? z.empty : "", ee = {
|
|
121
|
+
collection: G,
|
|
122
|
+
value: v ? [v] : [],
|
|
123
|
+
open: T && !B,
|
|
124
|
+
disabled: h.disabled,
|
|
125
|
+
readOnly: h.readOnly,
|
|
126
|
+
invalid: h.invalid,
|
|
127
|
+
onOpenChange: (e) => {
|
|
128
|
+
B || E(e.open);
|
|
129
|
+
},
|
|
130
|
+
onValueChange: (e) => {
|
|
131
|
+
if (B || F.current) return;
|
|
132
|
+
let t = e.value[0] ?? "";
|
|
133
|
+
t !== v && U(t);
|
|
134
|
+
},
|
|
135
|
+
onHighlightChange: (e) => O(e.highlightedValue),
|
|
136
|
+
scrollToIndexFn: K ? ({ index: e }) => X.scrollToIndex(e, { align: "auto" }) : void 0,
|
|
137
|
+
positioning: {
|
|
138
|
+
placement: "bottom-start",
|
|
139
|
+
sameWidth: !0,
|
|
140
|
+
gutter: 4,
|
|
141
|
+
strategy: M?.matches("[role=\"dialog\"], [role=\"alertdialog\"]") ? "fixed" : "absolute",
|
|
142
|
+
hideWhenDetached: !!M?.matches("[role=\"dialog\"], [role=\"alertdialog\"]")
|
|
143
|
+
}
|
|
144
|
+
}, te = h.searchable ? {
|
|
145
|
+
inputValue: C,
|
|
146
|
+
onInputValueChange: (e) => {
|
|
147
|
+
let t = P.current === e.inputValue && e.reason === "input-change" && k.current?.ownerDocument.activeElement !== k.current;
|
|
148
|
+
P.current = null, !t && !B && e.inputValue !== C && V(e.inputValue);
|
|
149
|
+
},
|
|
150
|
+
selectionBehavior: "preserve",
|
|
151
|
+
...h.autoHighlight ? { inputBehavior: "autohighlight" } : {}
|
|
152
|
+
} : {};
|
|
153
|
+
return /* @__PURE__ */ c(Z.Root, {
|
|
154
|
+
...ee,
|
|
155
|
+
...te,
|
|
156
|
+
id: h.id,
|
|
157
|
+
ids: h.id ? h.searchable ? { input: h.id } : { trigger: h.id } : void 0,
|
|
158
|
+
className: h.rootClass ? `dds-choice ${h.rootClass}` : "dds-choice",
|
|
159
|
+
"data-label-placement": h.labelPlacement ?? "outside",
|
|
160
|
+
"data-has-value": v || C ? "" : void 0,
|
|
161
|
+
children: [
|
|
162
|
+
h.label && /* @__PURE__ */ s(Z.Label, {
|
|
163
|
+
className: "dds-choice-label",
|
|
164
|
+
onClick: () => k.current?.focus(),
|
|
165
|
+
children: h.label
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ c(Z.Control, {
|
|
168
|
+
className: "dds-choice-control",
|
|
169
|
+
children: [
|
|
170
|
+
h.searchable ? /* @__PURE__ */ s(u.Input, {
|
|
171
|
+
ref: (e) => {
|
|
172
|
+
k.current = e;
|
|
173
|
+
},
|
|
174
|
+
className: "dds-choice-input",
|
|
175
|
+
"aria-label": h["aria-label"],
|
|
176
|
+
"aria-labelledby": h["aria-labelledby"],
|
|
177
|
+
"aria-describedby": h["aria-describedby"],
|
|
178
|
+
"aria-required": h.required,
|
|
179
|
+
placeholder: h.placeholder,
|
|
180
|
+
inputMode: h.inputMode,
|
|
181
|
+
onCompositionStart: () => {
|
|
182
|
+
F.current = !0;
|
|
183
|
+
},
|
|
184
|
+
onCompositionEnd: () => {
|
|
185
|
+
F.current = !1;
|
|
186
|
+
},
|
|
187
|
+
onKeyDown: (e) => {
|
|
188
|
+
F.current && e.key === "Enter" && (e.preventDefault(), e.stopPropagation());
|
|
189
|
+
},
|
|
190
|
+
onBlur: (e) => {
|
|
191
|
+
if (h.commitDraft) {
|
|
192
|
+
P.current = e.currentTarget.value;
|
|
193
|
+
let t = B ? null : h.commitDraft(e.currentTarget.value);
|
|
194
|
+
t !== null && t !== v ? (U(t), H(R(t))) : H(b);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
v && H(b);
|
|
198
|
+
}
|
|
199
|
+
}) : null,
|
|
200
|
+
/* @__PURE__ */ s(Z.Trigger, {
|
|
201
|
+
ref: (e) => {
|
|
202
|
+
h.searchable || (k.current = e);
|
|
203
|
+
},
|
|
204
|
+
className: "dds-choice-trigger",
|
|
205
|
+
"aria-label": h.searchable ? z.open : h["aria-label"],
|
|
206
|
+
"aria-labelledby": h["aria-labelledby"],
|
|
207
|
+
"aria-describedby": h["aria-describedby"],
|
|
208
|
+
"aria-required": h.required,
|
|
209
|
+
children: h.searchable ? h.triggerContent ?? "⌄" : /* @__PURE__ */ s("span", {
|
|
210
|
+
className: "dds-choice-value",
|
|
211
|
+
children: b || h.placeholder || z.open
|
|
212
|
+
})
|
|
213
|
+
}),
|
|
214
|
+
h.clearable && !B && (v || C) ? /* @__PURE__ */ s("button", {
|
|
215
|
+
className: "dds-choice-clear",
|
|
216
|
+
type: "button",
|
|
217
|
+
"aria-label": z.clear,
|
|
218
|
+
onPointerDown: (e) => e.preventDefault(),
|
|
219
|
+
onClick: () => {
|
|
220
|
+
U(""), V(""), E(!1), k.current?.focus();
|
|
221
|
+
},
|
|
222
|
+
children: "×"
|
|
223
|
+
}) : null
|
|
224
|
+
]
|
|
225
|
+
}),
|
|
226
|
+
/* @__PURE__ */ s("input", {
|
|
227
|
+
ref: A,
|
|
228
|
+
className: "dds-choice-validation",
|
|
229
|
+
tabIndex: -1,
|
|
230
|
+
"aria-hidden": "true",
|
|
231
|
+
name: h.name,
|
|
232
|
+
form: h.form,
|
|
233
|
+
value: v,
|
|
234
|
+
required: h.required,
|
|
235
|
+
disabled: h.disabled,
|
|
236
|
+
onChange: () => {},
|
|
237
|
+
onInvalid: (e) => {
|
|
238
|
+
e.preventDefault(), k.current?.focus();
|
|
239
|
+
}
|
|
240
|
+
}),
|
|
241
|
+
/* @__PURE__ */ c("div", {
|
|
242
|
+
className: "dds-choice-status",
|
|
243
|
+
role: "status",
|
|
244
|
+
"aria-live": "polite",
|
|
245
|
+
children: [$, h.error && h.onRetry ? /* @__PURE__ */ s("button", {
|
|
246
|
+
className: "dds-choice-retry",
|
|
247
|
+
type: "button",
|
|
248
|
+
onClick: h.onRetry,
|
|
249
|
+
children: z.retry
|
|
250
|
+
}) : null]
|
|
251
|
+
}),
|
|
252
|
+
M && /* @__PURE__ */ s(l, {
|
|
253
|
+
container: { current: M },
|
|
254
|
+
children: /* @__PURE__ */ s(Z.Positioner, {
|
|
255
|
+
className: "dds-choice-positioner",
|
|
256
|
+
children: /* @__PURE__ */ s(Z.Content, {
|
|
257
|
+
ref: j,
|
|
258
|
+
className: "dds-choice-content",
|
|
259
|
+
children: /* @__PURE__ */ s("div", {
|
|
260
|
+
style: K ? {
|
|
261
|
+
height: X.getTotalSize(),
|
|
262
|
+
position: "relative"
|
|
263
|
+
} : void 0,
|
|
264
|
+
children: Q.map((e) => {
|
|
265
|
+
let t = W[e.index];
|
|
266
|
+
return /* @__PURE__ */ c(Z.Item, {
|
|
267
|
+
item: t,
|
|
268
|
+
className: "dds-choice-item",
|
|
269
|
+
"aria-posinset": e.index + 1,
|
|
270
|
+
"aria-setsize": W.length,
|
|
271
|
+
style: K ? {
|
|
272
|
+
position: "absolute",
|
|
273
|
+
top: 0,
|
|
274
|
+
left: 0,
|
|
275
|
+
width: "100%",
|
|
276
|
+
height: J,
|
|
277
|
+
transform: `translateY(${e.start}px)`
|
|
278
|
+
} : void 0,
|
|
279
|
+
children: [/* @__PURE__ */ s(Z.ItemText, { children: t.label }), t.description ? /* @__PURE__ */ s("span", {
|
|
280
|
+
className: "dds-choice-description",
|
|
281
|
+
children: t.description
|
|
282
|
+
}) : null]
|
|
283
|
+
}, t.value);
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
})
|
|
289
|
+
]
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
//#endregion
|
|
293
|
+
export { h as t };
|
|
294
|
+
|
|
295
|
+
//# sourceMappingURL=choice-CWXdcWkH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice-CWXdcWkH.js","names":[],"sources":["../src/internal/choice.tsx"],"sourcesContent":["import { Combobox as C, createListCollection } from \"@ark-ui/react/combobox\";\nimport { Select as S } from \"@ark-ui/react/select\";\nimport { Portal } from \"@ark-ui/react/portal\";\nimport { defaultRangeExtractor, useVirtualizer } from \"@tanstack/react-virtual\";\nimport { useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport {\n choiceMessages,\n choiceWarningsEnabled,\n validateOptions,\n type ChoiceOption,\n type ComboboxProps,\n} from \"../choice-types\";\n\n/**\n * Options for DDS components built on Choice (TimePicker). They are not part\n * of the public Combobox/SelectPicker props; every default keeps the existing\n * Combobox and SelectPicker behavior. Mirrors the Solid Choice internals.\n */\nexport interface ChoiceInternals {\n searchable: boolean;\n /** Replaces the default case-insensitive label substring filter. */\n matchItem?: (item: ChoiceOption, query: string) => boolean;\n /** On blur, the value the typed text stands for, \"\" to clear, or null to restore the label. */\n commitDraft?: (text: string) => string | null;\n /** Content of the searchable trigger button (default \"⌄\"). */\n triggerContent?: ReactNode;\n rootClass?: string;\n invalid?: boolean;\n /** Highlight the first match while typing so Enter picks it. */\n autoHighlight?: boolean;\n /** Scroll the selected option to the middle of the list when it opens. */\n centerSelected?: boolean;\n inputMode?: HTMLAttributes<HTMLInputElement>[\"inputMode\"];\n /** Called before a native form reset restores the value. */\n onFormReset?: () => void;\n /** Observes every change of the uncontrolled input text, including restores. */\n onDraftChange?: (text: string) => void;\n}\n\nexport function Choice(props: ComboboxProps & ChoiceInternals) {\n validateOptions(props.items);\n const [internal, setInternal] = useState(props.defaultValue ?? \"\");\n const value = props.value ?? internal;\n const selected =\n props.items.find((item) => item.value === value) ??\n (props.selectedOption?.value === value ? props.selectedOption : undefined);\n const label = selected?.label ?? value;\n const [draft, setDraft] = useState(props.defaultInputValue ?? label);\n const inputValue = props.inputValue ?? draft;\n const changeDraft = (next: string) => {\n setDraft(next);\n props.onDraftChange?.(next);\n };\n const [open, setOpen] = useState(false),\n [highlight, setHighlight] = useState<string | null>(null);\n const visibleRef = useRef<HTMLInputElement | HTMLButtonElement>(null),\n validationRef = useRef<HTMLInputElement>(null),\n scrollRef = useRef<HTMLDivElement>(null);\n const [portalMount, setPortalMount] = useState<HTMLElement | null>(null);\n useEffect(() => {\n const control = visibleRef.current;\n if (control) {\n // Modal isolation hides body siblings. Keep nested choices in the modal's\n // DOM subtree so their options remain available to assistive technology.\n setPortalMount(\n control.closest<HTMLElement>('[role=\"dialog\"], [role=\"alertdialog\"]') ??\n control.ownerDocument.body,\n );\n }\n }, []);\n // Text the blur already committed; Ark may still report that keystroke afterwards.\n const consumedOnBlur = useRef<string | null>(null);\n const composing = useRef(false),\n previousSelection = useRef({ value, label });\n const pendingRestore = useRef<{ from: string; to: string } | null>(null);\n const resolveLabel = (id: string) =>\n props.items.find((item) => item.value === id)?.label ??\n (props.selectedOption?.value === id ? props.selectedOption.label : id);\n const messages = { ...choiceMessages, ...props.messages };\n const blocked = props.disabled || props.readOnly;\n const setInput = (next: string) => {\n if (\n pendingRestore.current?.from === inputValue &&\n pendingRestore.current.to === next\n )\n return;\n pendingRestore.current = null;\n if (props.inputValue === undefined) changeDraft(next);\n props.onInputValueChange?.(next);\n };\n const restoreInput = (next: string) => {\n if (next === inputValue) return;\n if (\n pendingRestore.current?.from === inputValue &&\n pendingRestore.current.to === next\n )\n return;\n pendingRestore.current = { from: inputValue, to: next };\n if (props.inputValue === undefined) changeDraft(next);\n else props.onInputValueChange?.(next);\n };\n const setValue = (next: string) => {\n if (props.value === undefined) setInternal(next);\n props.onValueChange?.(next);\n };\n useEffect(() => {\n if (\n previousSelection.current.value !== value ||\n previousSelection.current.label !== label\n ) {\n previousSelection.current = { value, label };\n restoreInput(label);\n }\n }, [value, label]);\n useEffect(() => {\n if (choiceWarningsEnabled() && value && !selected)\n console.warn(\n `DDS choice: no label supplied for selected ID ${JSON.stringify(value)}; pass selectedOption when the selection is outside items.`,\n );\n }, [value, selected]);\n useEffect(() => {\n const form = validationRef.current?.form;\n if (!form) return;\n // A task, not a microtask: after a reset-button click, microtasks run\n // before the browser resets the controls and would be overwritten.\n const reset = (event: Event) =>\n setTimeout(() => {\n if (event.defaultPrevented) return;\n props.onFormReset?.();\n const resetValue = props.value ?? props.defaultValue ?? \"\";\n const resetLabel = resolveLabel(resetValue);\n previousSelection.current = { value: resetValue, label: resetLabel };\n if (props.value === undefined) setInternal(resetValue);\n const resetQuery = props.defaultInputValue ?? resetLabel;\n pendingRestore.current = null;\n if (props.inputValue === undefined) changeDraft(resetQuery);\n else restoreInput(resetQuery);\n setOpen(false);\n if (visibleRef.current instanceof HTMLInputElement)\n visibleRef.current.value = props.inputValue ?? resetQuery;\n if (validationRef.current) validationRef.current.value = resetValue;\n });\n form.addEventListener(\"reset\", reset);\n return () => form.removeEventListener(\"reset\", reset);\n }, [\n props.defaultValue,\n props.defaultInputValue,\n props.value,\n props.inputValue,\n props.items,\n props.selectedOption,\n props.form,\n ]);\n const items = useMemo(\n () =>\n props.searchable &&\n props.filterMode !== \"external\" &&\n inputValue !== label\n ? props.items.filter((item) =>\n props.matchItem\n ? props.matchItem(item, inputValue)\n : item.label\n .toLocaleLowerCase()\n .includes(inputValue.toLocaleLowerCase()),\n )\n : props.items,\n [props.items, props.searchable, props.filterMode, inputValue, label, props.matchItem],\n );\n const collection = useMemo(\n () =>\n createListCollection({\n items,\n itemToString: (item) => item.label,\n itemToValue: (item) => item.value,\n isItemDisabled: (item) => !!item.disabled,\n }),\n [items],\n );\n const virtual = !!props.virtualization;\n const configuredHeight = props.virtualization\n ? props.virtualization.itemHeight\n : undefined;\n const height = Number.isFinite(configuredHeight)\n ? Math.max(40, configuredHeight!)\n : 40;\n const activeIndex = items.findIndex((item) => item.value === highlight);\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => height,\n overscan: props.virtualization ? (props.virtualization.overscan ?? 5) : 5,\n enabled: virtual && open,\n initialRect: { width: 0, height: 320 },\n rangeExtractor: (range) => {\n const indexes = defaultRangeExtractor(range);\n if (activeIndex >= 0 && !indexes.includes(activeIndex))\n indexes.push(activeIndex);\n return indexes.sort((a, b) => a - b);\n },\n });\n useEffect(() => {\n setHighlight(null);\n if (virtual && open)\n virtualizer.scrollToIndex(\n Math.max(\n 0,\n items.findIndex((item) => item.value === value),\n ),\n { align: props.centerSelected ? \"center\" : \"auto\" },\n );\n }, [items, open]);\n useEffect(() => {\n const content = scrollRef.current;\n if (!props.centerSelected || !open || virtual || !content) return;\n // Ark only scrolls the highlighted option to the nearest edge.\n const frame = requestAnimationFrame(() => {\n const chosen = content.querySelector<HTMLElement>(\n '[data-part=\"item\"][data-state=\"checked\"]',\n );\n if (!chosen) return;\n const list = content.getBoundingClientRect(),\n row = chosen.getBoundingClientRect();\n content.scrollTop +=\n row.top - list.top - (content.clientHeight - row.height) / 2;\n });\n return () => cancelAnimationFrame(frame);\n }, [open, props.centerSelected, virtual]);\n const Parts = props.searchable ? C : S;\n const rows = virtual\n ? virtualizer\n .getVirtualItems()\n .map((row) => ({ index: row.index, start: row.start }))\n : items.map((_, index) => ({ index, start: 0 }));\n // Keep the active row mounted even before the scroll element has a measured range.\n if (\n virtual &&\n activeIndex >= 0 &&\n !rows.some((row) => row.index === activeIndex)\n )\n rows.push({ index: activeIndex, start: activeIndex * height });\n const status = props.loading\n ? messages.loading\n : props.error\n ? typeof props.error === \"string\"\n ? props.error\n : messages.error\n : items.length === 0\n ? messages.empty\n : \"\";\n const rootProps = {\n collection,\n value: value ? [value] : [],\n open: open && !blocked,\n disabled: props.disabled,\n readOnly: props.readOnly,\n invalid: props.invalid,\n onOpenChange: (details: { open: boolean }) => {\n if (!blocked) setOpen(details.open);\n },\n onValueChange: (details: { value: string[] }) => {\n if (blocked || composing.current) return;\n const next = details.value[0] ?? \"\";\n if (next !== value) setValue(next);\n },\n onHighlightChange: (details: { highlightedValue: string | null }) =>\n setHighlight(details.highlightedValue),\n scrollToIndexFn: virtual\n ? ({ index }: { index: number }) =>\n virtualizer.scrollToIndex(index, { align: \"auto\" })\n : undefined,\n positioning: {\n placement: \"bottom-start\" as const,\n sameWidth: true,\n gutter: 4,\n strategy: portalMount?.matches('[role=\"dialog\"], [role=\"alertdialog\"]')\n ? (\"fixed\" as const)\n : (\"absolute\" as const),\n hideWhenDetached: !!portalMount?.matches(\n '[role=\"dialog\"], [role=\"alertdialog\"]',\n ),\n },\n };\n const inputProps = props.searchable\n ? {\n inputValue,\n onInputValueChange: (details: {\n inputValue: string;\n reason?: string;\n }) => {\n const stale =\n consumedOnBlur.current === details.inputValue &&\n details.reason === \"input-change\" &&\n visibleRef.current?.ownerDocument.activeElement !== visibleRef.current;\n consumedOnBlur.current = null;\n if (stale) return;\n if (!blocked && details.inputValue !== inputValue)\n setInput(details.inputValue);\n },\n selectionBehavior: \"preserve\" as const,\n ...(props.autoHighlight\n ? { inputBehavior: \"autohighlight\" as const }\n : {}),\n }\n : {};\n return (\n <Parts.Root\n {...rootProps}\n {...inputProps}\n id={props.id}\n // A consumer id lands on the control a <label htmlFor> targets (text box,\n // or SelectPicker's button), not on Zag's prefixed part IDs.\n ids={\n props.id\n ? props.searchable\n ? { input: props.id }\n : { trigger: props.id }\n : undefined\n }\n className={props.rootClass ? `dds-choice ${props.rootClass}` : \"dds-choice\"}\n data-label-placement={props.labelPlacement ?? \"outside\"}\n data-has-value={value || inputValue ? \"\" : undefined}\n >\n {props.label && (\n <Parts.Label\n className=\"dds-choice-label\"\n onClick={() => visibleRef.current?.focus()}\n >\n {props.label}\n </Parts.Label>\n )}\n <Parts.Control className=\"dds-choice-control\">\n {props.searchable ? (\n <C.Input\n ref={(node) => {\n visibleRef.current = node;\n }}\n className=\"dds-choice-input\"\n aria-label={props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={props.required}\n placeholder={props.placeholder}\n inputMode={props.inputMode}\n onCompositionStart={() => {\n composing.current = true;\n }}\n onCompositionEnd={() => {\n composing.current = false;\n }}\n onKeyDown={(event) => {\n if (composing.current && event.key === \"Enter\") {\n event.preventDefault();\n event.stopPropagation();\n }\n }}\n onBlur={(event) => {\n if (props.commitDraft) {\n // The DOM holds the latest keystroke; Ark's input state may still be queued.\n consumedOnBlur.current = event.currentTarget.value;\n const next = blocked\n ? null\n : props.commitDraft(event.currentTarget.value);\n if (next !== null && next !== value) {\n setValue(next);\n restoreInput(resolveLabel(next));\n } else restoreInput(label);\n return;\n }\n if (value) restoreInput(label);\n }}\n />\n ) : null}\n <Parts.Trigger\n ref={(node) => {\n if (!props.searchable) visibleRef.current = node;\n }}\n className=\"dds-choice-trigger\"\n aria-label={props.searchable ? messages.open : props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={props.required}\n >\n {props.searchable ? (\n (props.triggerContent ?? \"⌄\")\n ) : (\n <span className=\"dds-choice-value\">\n {label || props.placeholder || messages.open}\n </span>\n )}\n </Parts.Trigger>\n {props.clearable && !blocked && (value || inputValue) ? (\n <button\n className=\"dds-choice-clear\"\n type=\"button\"\n aria-label={messages.clear}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n setValue(\"\");\n setInput(\"\");\n setOpen(false);\n visibleRef.current?.focus();\n }}\n >\n ×\n </button>\n ) : null}\n </Parts.Control>\n {/* The native validation input stores one ID, never a second option collection.\n Hidden by choice.css; no style attribute, which a style-src-attr CSP blocks. */}\n <input\n ref={validationRef}\n className=\"dds-choice-validation\"\n tabIndex={-1}\n aria-hidden=\"true\"\n name={props.name}\n form={props.form}\n value={value}\n required={props.required}\n disabled={props.disabled}\n onChange={() => {}}\n onInvalid={(event) => {\n event.preventDefault();\n visibleRef.current?.focus();\n }}\n />\n <div className=\"dds-choice-status\" role=\"status\" aria-live=\"polite\">\n {status}\n {props.error && props.onRetry ? (\n <button\n className=\"dds-choice-retry\"\n type=\"button\"\n onClick={props.onRetry}\n >\n {messages.retry}\n </button>\n ) : null}\n </div>\n {portalMount && (\n <Portal container={{ current: portalMount }}>\n <Parts.Positioner className=\"dds-choice-positioner\">\n {/* choice.css gives the list its 320px cap and scrolling. */}\n <Parts.Content\n ref={scrollRef}\n className=\"dds-choice-content\"\n >\n <div\n style={\n virtual\n ? {\n height: virtualizer.getTotalSize(),\n position: \"relative\",\n }\n : undefined\n }\n >\n {rows.map((row) => {\n const item = items[row.index]!;\n return (\n <Parts.Item\n key={item.value}\n item={item}\n className=\"dds-choice-item\"\n aria-posinset={row.index + 1}\n aria-setsize={items.length}\n style={\n virtual\n ? {\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height,\n transform: `translateY(${row.start}px)`,\n }\n : undefined\n }\n >\n <Parts.ItemText>{item.label}</Parts.ItemText>\n {item.description ? (\n <span className=\"dds-choice-description\">\n {item.description}\n </span>\n ) : null}\n </Parts.Item>\n );\n })}\n </div>\n </Parts.Content>\n </Parts.Positioner>\n </Portal>\n )}\n </Parts.Root>\n );\n}\n"],"mappings":"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"}
|
package/dist/combobox.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { SelectPicker as m } from "./select-picker.js";
|
|
|
8
8
|
import { DropdownMenu as h } from "./dropdown-menu.js";
|
|
9
9
|
import { Popover as g } from "./popover.js";
|
|
10
10
|
import { Calendar as _ } from "./calendar.js";
|
|
11
|
-
import { t as v } from "./time-picker-
|
|
11
|
+
import { t as v } from "./time-picker-BNmQMQdq.js";
|
|
12
12
|
import { SegmentedControl as y, validateSegmentedItems as b } from "./segmented-control.js";
|
|
13
13
|
import { NumberInput as x, normalizeNumberText as S, numberInputMessages as ee } from "./number-input.js";
|
|
14
14
|
import { createContext as C, forwardRef as w, useCallback as T, useContext as E, useEffect as D, useId as O, useMemo as k, useRef as A, useState as j } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice.d.ts","sourceRoot":"","sources":["../../src/internal/choice.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwC,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClG,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3D,+FAA+F;IAC/F,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,8DAA8D;IAC9D,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1D,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,gFAAgF;IAChF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;
|
|
1
|
+
{"version":3,"file":"choice.d.ts","sourceRoot":"","sources":["../../src/internal/choice.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwC,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClG,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3D,+FAA+F;IAC/F,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,8DAA8D;IAC9D,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1D,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,gFAAgF;IAChF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,+BAsc5D"}
|
package/dist/select-picker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./choice-
|
|
1
|
+
import { t as e } from "./choice-CWXdcWkH.js";
|
|
2
2
|
import { useMemo as t, useState as n } from "react";
|
|
3
3
|
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
4
4
|
//#region src/time-only.ts
|
|
@@ -97,4 +97,4 @@ function _({ value: i, defaultValue: a, onValueChange: s, step: c, placeholder:
|
|
|
97
97
|
//#endregion
|
|
98
98
|
export { _ as t };
|
|
99
99
|
|
|
100
|
-
//# sourceMappingURL=time-picker-
|
|
100
|
+
//# sourceMappingURL=time-picker-BNmQMQdq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-picker-BQ7BT6-u.js","names":[],"sources":["../src/time-only.ts","../src/time-picker.tsx"],"sourcesContent":["// Time-of-day values are 24-hour \"HH:MM\" strings; \"\" is empty. Servers may send\n// \"HH:MM:SS\" — it is accepted and shown as HH:MM, but never rewritten until the\n// user picks a time.\nconst API_TIME = /^([01]\\d|2[0-3]):([0-5]\\d)(?::[0-5]\\d(?:\\.\\d+)?)?$/;\n\n/** Canonical \"HH:MM\" for an API value, or null when it is not a time. */\nexport function normalizeTime(value: string): string | null {\n const match = API_TIME.exec(value);\n return match ? `${match[1]}:${match[2]}` : null;\n}\n\nconst pad = (value: number) => String(value).padStart(2, \"0\");\nconst fromParts = (hour: number, minute: number) =>\n hour <= 23 && minute <= 59 ? `${pad(hour)}:${pad(minute)}` : null;\n\n/**\n * What a person typed, read as a complete time: \"9:05\", \"09:05\", \"09:05:00\",\n * \"0905\", or \"905\" when the first two digits cannot be an hour. Full-width\n * colons and dots count as colons. Partial text (\"10\", \"10:4\", and \"103\",\n * which is still on its way to 10:30) is not a time.\n */\nexport function parseTypedTime(text: string): string | null {\n const value = text.trim().replace(/[:.]/g, \":\");\n const separated = /^(\\d{1,2}):(\\d{2})(?::\\d{2})?$/.exec(value);\n if (separated) return fromParts(Number(separated[1]), Number(separated[2]));\n if (/^\\d{4}$/.test(value))\n return fromParts(Number(value.slice(0, 2)), Number(value.slice(2)));\n if (/^\\d{3}$/.test(value) && Number(value.slice(0, 2)) > 23)\n return fromParts(Number(value[0]), Number(value.slice(1)));\n return null;\n}\n\n/** 00:00 up to the last step before 24:00. Steps below one minute become one; a non-number becomes 10. */\nexport function timeOptions(step: number) {\n const minutes = Number.isFinite(step) ? Math.max(1, Math.floor(step)) : 10;\n const values: string[] = [];\n for (let at = 0; at < 24 * 60; at += minutes)\n values.push(`${pad(Math.floor(at / 60))}:${pad(at % 60)}`);\n return values;\n}\n\n/**\n * Whether a \"HH:MM\" option matches partial typing. Digits read as the start of\n * the time (\"10\" → 10:00–10:59, \"1030\" → 10:30); an odd digit count or an\n * impossible hour also tries a leading zero (\"9\" → 09:xx, \"930\" → 09:30).\n * With a colon the hour may be one digit (\"9:3\" → 09:30–09:39).\n */\nexport function matchesTimeQuery(option: string, query: string) {\n const text = query.trim().replace(/[:.]/g, \":\");\n if (text === \"\") return true;\n const typed = parseTypedTime(text);\n if (typed) return option === typed;\n if (text.includes(\":\")) {\n const [hour = \"\", minute = \"\", ...rest] = text.split(\":\");\n if (rest.length || !/^\\d{1,2}$/.test(hour) || !/^\\d{0,2}$/.test(minute))\n return false;\n return option.startsWith(`${hour.padStart(2, \"0\")}:${minute}`);\n }\n if (!/^\\d{1,4}$/.test(text)) return false;\n const digits = option.replace(\":\", \"\");\n if (digits.startsWith(text)) return true;\n return (\n (text.length % 2 === 1 || Number(text.slice(0, 2)) > 23) &&\n digits.startsWith(`0${text}`)\n );\n}\n\nexport interface TimeMessages {\n /** Accessible name of the clock button that opens the list. */\n open?: string;\n /** Accessible name of the clear button. */\n clear?: string;\n /** Status when nothing in the list matches the typed text. */\n empty?: string;\n}\nexport function timeMessages(locale: string, messages: TimeMessages = {}) {\n const ko = /^ko(?:-|$)/i.test(locale);\n return {\n open: ko ? \"시간 목록 열기\" : \"Open time list\",\n clear: ko ? \"시간 지우기\" : \"Clear time\",\n empty: ko ? \"맞는 시간이 없습니다\" : \"No matching time\",\n ...messages,\n };\n}\n","import { useMemo, useState } from \"react\";\nimport type { ChoiceOption } from \"./choice-types\";\nimport { Choice } from \"./internal/choice\";\nimport {\n matchesTimeQuery,\n normalizeTime,\n parseTypedTime,\n timeMessages,\n timeOptions,\n type TimeMessages,\n} from \"./time-only\";\nexport type { TimeMessages } from \"./time-only\";\n\nexport interface TimePickerProps {\n /** 24-hour \"HH:MM\" (\"\" is empty). \"HH:MM:SS\" is accepted and shown as HH:MM. */\n value?: string;\n defaultValue?: string;\n /** Receives \"HH:MM\" or \"\" — only when the person picks, types or clears a time. */\n onValueChange?: (value: string) => void;\n /** Minutes between listed times, from 00:00 (default 10). Typed times off the step are still accepted. */\n step?: number;\n label?: string;\n labelPlacement?: \"outside\" | \"inside\" | \"hidden\";\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n id?: string;\n name?: string;\n form?: string;\n placeholder?: string;\n clearable?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n invalid?: boolean;\n /** Chooses the built-in Korean or English text (default \"ko-KR\"). */\n locale?: string;\n messages?: TimeMessages;\n}\n\n/** Above this many rows the list is virtualized (1-minute steps list 1,440 times). */\nconst VIRTUALIZE_AFTER = 300;\n\n// The dds-icons \"clock\" glyph, inlined like DatePicker's calendar so this\n// subpath does not pull in the whole icon set.\nconst clockIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18z\" />\n <path d=\"M12 7v5l3 2\" />\n </svg>\n);\n\nconst matchItem = (item: ChoiceOption, query: string) =>\n matchesTimeQuery(item.value, query);\nconst commitDraft = (text: string) =>\n text.trim() === \"\" ? \"\" : parseTypedTime(text);\n\n/**\n * A time-of-day field: type a time or pick one from the list. Built on the\n * same Ark combobox as Combobox, so list, keyboard and form behavior match.\n */\nexport function TimePicker({\n value,\n defaultValue,\n onValueChange,\n step,\n placeholder,\n invalid,\n locale,\n messages,\n ...shared\n}: TimePickerProps) {\n const initial = normalizeTime(defaultValue ?? \"\") ?? \"\";\n const [internal, setInternal] = useState(initial);\n const raw = value ?? internal;\n const canonical = raw === \"\" ? \"\" : normalizeTime(raw);\n // A value that is not a time is shown as it came, marked invalid, and never rewritten.\n const current = canonical ?? raw;\n const [draft, setDraft] = useState(current);\n const typed = parseTypedTime(draft);\n const items = useMemo<ChoiceOption[]>(() => {\n const values = new Set(timeOptions(step ?? 10));\n if (canonical) values.add(canonical);\n if (typed) values.add(typed);\n return [...values].sort().map((time) => ({ value: time, label: time }));\n }, [step, canonical, typed]);\n return (\n <Choice\n {...shared}\n searchable\n rootClass=\"dds-time-picker\"\n items={items}\n value={current}\n // Only read when the value is not a listed time (an invalid server value).\n selectedOption={{ value: current, label: current }}\n onValueChange={(next) => {\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n }}\n onFormReset={() => {\n if (value === undefined) setInternal(initial);\n }}\n // Choice owns the text (a React round-trip per keystroke drops fast typing); mirror it.\n onDraftChange={setDraft}\n matchItem={matchItem}\n commitDraft={commitDraft}\n triggerContent={clockIcon}\n autoHighlight\n centerSelected\n inputMode=\"numeric\"\n virtualization={items.length > VIRTUALIZE_AFTER ? {} : false}\n messages={timeMessages(locale ?? \"ko-KR\", messages)}\n placeholder={placeholder ?? \"HH:MM\"}\n invalid={invalid === true || canonical === null}\n />\n );\n}\n"],"mappings":";;;;AAGA,IAAM,IAAW;AAGjB,SAAgB,EAAc,GAA8B;CAC1D,IAAM,IAAQ,EAAS,KAAK,CAAK;CACjC,OAAO,IAAQ,GAAG,EAAM,GAAG,GAAG,EAAM,OAAO;AAC7C;AAEA,IAAM,KAAO,MAAkB,OAAO,CAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GACtD,KAAa,GAAc,MAC/B,KAAQ,MAAM,KAAU,KAAK,GAAG,EAAI,CAAI,EAAE,GAAG,EAAI,CAAM,MAAM;AAQ/D,SAAgB,EAAe,GAA6B;CAC1D,IAAM,IAAQ,EAAK,KAAK,CAAC,CAAC,QAAQ,SAAS,GAAG,GACxC,IAAY,iCAAiC,KAAK,CAAK;CAM7D,OALI,IAAkB,EAAU,OAAO,EAAU,EAAE,GAAG,OAAO,EAAU,EAAE,CAAC,IACtE,UAAU,KAAK,CAAK,IACf,EAAU,OAAO,EAAM,MAAM,GAAG,CAAC,CAAC,GAAG,OAAO,EAAM,MAAM,CAAC,CAAC,CAAC,IAChE,UAAU,KAAK,CAAK,KAAK,OAAO,EAAM,MAAM,GAAG,CAAC,CAAC,IAAI,KAChD,EAAU,OAAO,EAAM,EAAE,GAAG,OAAO,EAAM,MAAM,CAAC,CAAC,CAAC,IACpD;AACT;AAGA,SAAgB,EAAY,GAAc;CACxC,IAAM,IAAU,OAAO,SAAS,CAAI,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,CAAI,CAAC,IAAI,IAClE,IAAmB,CAAC;CAC1B,KAAK,IAAI,IAAK,GAAG,IAAK,MAAS,KAAM,GACnC,EAAO,KAAK,GAAG,EAAI,KAAK,MAAM,IAAK,EAAE,CAAC,EAAE,GAAG,EAAI,IAAK,EAAE,GAAG;CAC3D,OAAO;AACT;AAQA,SAAgB,EAAiB,GAAgB,GAAe;CAC9D,IAAM,IAAO,EAAM,KAAK,CAAC,CAAC,QAAQ,SAAS,GAAG;CAC9C,IAAI,MAAS,IAAI,OAAO;CACxB,IAAM,IAAQ,EAAe,CAAI;CACjC,IAAI,GAAO,OAAO,MAAW;CAC7B,IAAI,EAAK,SAAS,GAAG,GAAG;EACtB,IAAM,CAAC,IAAO,IAAI,IAAS,IAAI,GAAG,KAAQ,EAAK,MAAM,GAAG;EAGxD,OAFI,EAAK,UAAU,CAAC,YAAY,KAAK,CAAI,KAAK,CAAC,YAAY,KAAK,CAAM,IAC7D,KACF,EAAO,WAAW,GAAG,EAAK,SAAS,GAAG,GAAG,EAAE,GAAG,GAAQ;CAC/D;CACA,IAAI,CAAC,YAAY,KAAK,CAAI,GAAG,OAAO;CACpC,IAAM,IAAS,EAAO,QAAQ,KAAK,EAAE;CAErC,OADI,EAAO,WAAW,CAAI,IAAU,MAEjC,EAAK,SAAS,KAAM,KAAK,OAAO,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,OACrD,EAAO,WAAW,IAAI,GAAM;AAEhC;AAUA,SAAgB,EAAa,GAAgB,IAAyB,CAAC,GAAG;CACxE,IAAM,IAAK,cAAc,KAAK,CAAM;CACpC,OAAO;EACL,MAAM,IAAK,aAAa;EACxB,OAAO,IAAK,WAAW;EACvB,OAAO,IAAK,gBAAgB;EAC5B,GAAG;CACL;AACF;;;AC1CA,IAAM,IAAmB,KAInB,IACJ,kBAAC,OAAD;CACE,OAAM;CACN,QAAO;CACP,SAAQ;CACR,MAAK;CACL,QAAO;CACP,aAAY;CACZ,eAAc;CACd,gBAAe;CACf,eAAY;CATd,UAAA,CAWE,kBAAC,QAAD,EAAM,GAAE,wCAAyC,CAAA,GACjD,kBAAC,QAAD,EAAM,GAAE,cAAe,CAAA,CACpB;IAGD,KAAa,GAAoB,MACrC,EAAiB,EAAK,OAAO,CAAK,GAC9B,KAAe,MACnB,EAAK,KAAK,MAAM,KAAK,KAAK,EAAe,CAAI;AAM/C,SAAgB,EAAW,EACzB,UACA,iBACA,kBACA,SACA,gBACA,YACA,WACA,aACA,GAAG,KACe;CAClB,IAAM,IAAU,EAAc,KAAgB,EAAE,KAAK,IAC/C,CAAC,GAAU,KAAe,EAAS,CAAO,GAC1C,IAAM,KAAS,GACf,IAAY,MAAQ,KAAK,KAAK,EAAc,CAAG,GAE/C,IAAU,KAAa,GACvB,CAAC,GAAO,KAAY,EAAS,CAAO,GACpC,IAAQ,EAAe,CAAK,GAC5B,IAAQ,QAA8B;EAC1C,IAAM,IAAS,IAAI,IAAI,EAAY,KAAQ,EAAE,CAAC;EAG9C,OAFI,KAAW,EAAO,IAAI,CAAS,GAC/B,KAAO,EAAO,IAAI,CAAK,GACpB,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,OAAU;GAAE,OAAO;GAAM,OAAO;EAAK,EAAE;CACxE,GAAG;EAAC;EAAM;EAAW;CAAK,CAAC;CAC3B,OACE,kBAAC,GAAD;EACE,GAAI;EACJ,YAAA;EACA,WAAU;EACH;EACP,OAAO;EAEP,gBAAgB;GAAE,OAAO;GAAS,OAAO;EAAQ;EACjD,gBAAgB,MAAS;GAEvB,AADI,MAAU,KAAA,KAAW,EAAY,CAAI,GACzC,IAAgB,CAAI;EACtB;EACA,mBAAmB;GACjB,AAAI,MAAU,KAAA,KAAW,EAAY,CAAO;EAC9C;EAEA,eAAe;EACJ;EACE;EACb,gBAAgB;EAChB,eAAA;EACA,gBAAA;EACA,WAAU;EACV,gBAAgB,EAAM,SAAS,KAAmB,CAAC;EACnD,UAAU,EAAa,KAAU,SAAS,CAAQ;EAClD,aAAa,KAAe;EAC5B,SAAS,MAAY,MAAQ,MAAc;CAC5C,CAAA;AAEL"}
|
|
1
|
+
{"version":3,"file":"time-picker-BNmQMQdq.js","names":[],"sources":["../src/time-only.ts","../src/time-picker.tsx"],"sourcesContent":["// Time-of-day values are 24-hour \"HH:MM\" strings; \"\" is empty. Servers may send\n// \"HH:MM:SS\" — it is accepted and shown as HH:MM, but never rewritten until the\n// user picks a time.\nconst API_TIME = /^([01]\\d|2[0-3]):([0-5]\\d)(?::[0-5]\\d(?:\\.\\d+)?)?$/;\n\n/** Canonical \"HH:MM\" for an API value, or null when it is not a time. */\nexport function normalizeTime(value: string): string | null {\n const match = API_TIME.exec(value);\n return match ? `${match[1]}:${match[2]}` : null;\n}\n\nconst pad = (value: number) => String(value).padStart(2, \"0\");\nconst fromParts = (hour: number, minute: number) =>\n hour <= 23 && minute <= 59 ? `${pad(hour)}:${pad(minute)}` : null;\n\n/**\n * What a person typed, read as a complete time: \"9:05\", \"09:05\", \"09:05:00\",\n * \"0905\", or \"905\" when the first two digits cannot be an hour. Full-width\n * colons and dots count as colons. Partial text (\"10\", \"10:4\", and \"103\",\n * which is still on its way to 10:30) is not a time.\n */\nexport function parseTypedTime(text: string): string | null {\n const value = text.trim().replace(/[:.]/g, \":\");\n const separated = /^(\\d{1,2}):(\\d{2})(?::\\d{2})?$/.exec(value);\n if (separated) return fromParts(Number(separated[1]), Number(separated[2]));\n if (/^\\d{4}$/.test(value))\n return fromParts(Number(value.slice(0, 2)), Number(value.slice(2)));\n if (/^\\d{3}$/.test(value) && Number(value.slice(0, 2)) > 23)\n return fromParts(Number(value[0]), Number(value.slice(1)));\n return null;\n}\n\n/** 00:00 up to the last step before 24:00. Steps below one minute become one; a non-number becomes 10. */\nexport function timeOptions(step: number) {\n const minutes = Number.isFinite(step) ? Math.max(1, Math.floor(step)) : 10;\n const values: string[] = [];\n for (let at = 0; at < 24 * 60; at += minutes)\n values.push(`${pad(Math.floor(at / 60))}:${pad(at % 60)}`);\n return values;\n}\n\n/**\n * Whether a \"HH:MM\" option matches partial typing. Digits read as the start of\n * the time (\"10\" → 10:00–10:59, \"1030\" → 10:30); an odd digit count or an\n * impossible hour also tries a leading zero (\"9\" → 09:xx, \"930\" → 09:30).\n * With a colon the hour may be one digit (\"9:3\" → 09:30–09:39).\n */\nexport function matchesTimeQuery(option: string, query: string) {\n const text = query.trim().replace(/[:.]/g, \":\");\n if (text === \"\") return true;\n const typed = parseTypedTime(text);\n if (typed) return option === typed;\n if (text.includes(\":\")) {\n const [hour = \"\", minute = \"\", ...rest] = text.split(\":\");\n if (rest.length || !/^\\d{1,2}$/.test(hour) || !/^\\d{0,2}$/.test(minute))\n return false;\n return option.startsWith(`${hour.padStart(2, \"0\")}:${minute}`);\n }\n if (!/^\\d{1,4}$/.test(text)) return false;\n const digits = option.replace(\":\", \"\");\n if (digits.startsWith(text)) return true;\n return (\n (text.length % 2 === 1 || Number(text.slice(0, 2)) > 23) &&\n digits.startsWith(`0${text}`)\n );\n}\n\nexport interface TimeMessages {\n /** Accessible name of the clock button that opens the list. */\n open?: string;\n /** Accessible name of the clear button. */\n clear?: string;\n /** Status when nothing in the list matches the typed text. */\n empty?: string;\n}\nexport function timeMessages(locale: string, messages: TimeMessages = {}) {\n const ko = /^ko(?:-|$)/i.test(locale);\n return {\n open: ko ? \"시간 목록 열기\" : \"Open time list\",\n clear: ko ? \"시간 지우기\" : \"Clear time\",\n empty: ko ? \"맞는 시간이 없습니다\" : \"No matching time\",\n ...messages,\n };\n}\n","import { useMemo, useState } from \"react\";\nimport type { ChoiceOption } from \"./choice-types\";\nimport { Choice } from \"./internal/choice\";\nimport {\n matchesTimeQuery,\n normalizeTime,\n parseTypedTime,\n timeMessages,\n timeOptions,\n type TimeMessages,\n} from \"./time-only\";\nexport type { TimeMessages } from \"./time-only\";\n\nexport interface TimePickerProps {\n /** 24-hour \"HH:MM\" (\"\" is empty). \"HH:MM:SS\" is accepted and shown as HH:MM. */\n value?: string;\n defaultValue?: string;\n /** Receives \"HH:MM\" or \"\" — only when the person picks, types or clears a time. */\n onValueChange?: (value: string) => void;\n /** Minutes between listed times, from 00:00 (default 10). Typed times off the step are still accepted. */\n step?: number;\n label?: string;\n labelPlacement?: \"outside\" | \"inside\" | \"hidden\";\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n id?: string;\n name?: string;\n form?: string;\n placeholder?: string;\n clearable?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n invalid?: boolean;\n /** Chooses the built-in Korean or English text (default \"ko-KR\"). */\n locale?: string;\n messages?: TimeMessages;\n}\n\n/** Above this many rows the list is virtualized (1-minute steps list 1,440 times). */\nconst VIRTUALIZE_AFTER = 300;\n\n// The dds-icons \"clock\" glyph, inlined like DatePicker's calendar so this\n// subpath does not pull in the whole icon set.\nconst clockIcon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18z\" />\n <path d=\"M12 7v5l3 2\" />\n </svg>\n);\n\nconst matchItem = (item: ChoiceOption, query: string) =>\n matchesTimeQuery(item.value, query);\nconst commitDraft = (text: string) =>\n text.trim() === \"\" ? \"\" : parseTypedTime(text);\n\n/**\n * A time-of-day field: type a time or pick one from the list. Built on the\n * same Ark combobox as Combobox, so list, keyboard and form behavior match.\n */\nexport function TimePicker({\n value,\n defaultValue,\n onValueChange,\n step,\n placeholder,\n invalid,\n locale,\n messages,\n ...shared\n}: TimePickerProps) {\n const initial = normalizeTime(defaultValue ?? \"\") ?? \"\";\n const [internal, setInternal] = useState(initial);\n const raw = value ?? internal;\n const canonical = raw === \"\" ? \"\" : normalizeTime(raw);\n // A value that is not a time is shown as it came, marked invalid, and never rewritten.\n const current = canonical ?? raw;\n const [draft, setDraft] = useState(current);\n const typed = parseTypedTime(draft);\n const items = useMemo<ChoiceOption[]>(() => {\n const values = new Set(timeOptions(step ?? 10));\n if (canonical) values.add(canonical);\n if (typed) values.add(typed);\n return [...values].sort().map((time) => ({ value: time, label: time }));\n }, [step, canonical, typed]);\n return (\n <Choice\n {...shared}\n searchable\n rootClass=\"dds-time-picker\"\n items={items}\n value={current}\n // Only read when the value is not a listed time (an invalid server value).\n selectedOption={{ value: current, label: current }}\n onValueChange={(next) => {\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n }}\n onFormReset={() => {\n if (value === undefined) setInternal(initial);\n }}\n // Choice owns the text (a React round-trip per keystroke drops fast typing); mirror it.\n onDraftChange={setDraft}\n matchItem={matchItem}\n commitDraft={commitDraft}\n triggerContent={clockIcon}\n autoHighlight\n centerSelected\n inputMode=\"numeric\"\n virtualization={items.length > VIRTUALIZE_AFTER ? {} : false}\n messages={timeMessages(locale ?? \"ko-KR\", messages)}\n placeholder={placeholder ?? \"HH:MM\"}\n invalid={invalid === true || canonical === null}\n />\n );\n}\n"],"mappings":"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"}
|
package/dist/time-picker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "./time-picker-
|
|
1
|
+
import { t as e } from "./time-picker-BNmQMQdq.js";
|
|
2
2
|
export { e as TimePicker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devslab/dds-react",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "Accessible React primitives for the DevsLab Design System",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -99,9 +99,9 @@
|
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
101
|
"@ark-ui/react": "5.39.3",
|
|
102
|
-
"@devslab/dds-css": "0.25.
|
|
103
|
-
"@devslab/dds-icons": "0.25.
|
|
104
|
-
"@devslab/dds-tokens": "0.25.
|
|
102
|
+
"@devslab/dds-css": "0.25.1",
|
|
103
|
+
"@devslab/dds-icons": "0.25.1",
|
|
104
|
+
"@devslab/dds-tokens": "0.25.1",
|
|
105
105
|
"@tanstack/react-virtual": "3.14.21"
|
|
106
106
|
},
|
|
107
107
|
"peerDependencies": {
|
package/dist/choice-N-5K_ggs.js
DELETED
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import { n as e, r as t, t as n } from "./choice-types-kSaEnZPr.js";
|
|
2
|
-
import { useEffect as r, useMemo as i, useRef as a, useState as o } from "react";
|
|
3
|
-
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
4
|
-
import { Portal as l } from "@ark-ui/react/portal";
|
|
5
|
-
import { Combobox as u, createListCollection as d } from "@ark-ui/react/combobox";
|
|
6
|
-
import { Select as f } from "@ark-ui/react/select";
|
|
7
|
-
import { defaultRangeExtractor as p, useVirtualizer as m } from "@tanstack/react-virtual";
|
|
8
|
-
//#region src/internal/choice.tsx
|
|
9
|
-
var h = {
|
|
10
|
-
position: "absolute",
|
|
11
|
-
width: 1,
|
|
12
|
-
height: 1,
|
|
13
|
-
padding: 0,
|
|
14
|
-
border: 0,
|
|
15
|
-
clipPath: "inset(50%)",
|
|
16
|
-
overflow: "hidden",
|
|
17
|
-
whiteSpace: "nowrap"
|
|
18
|
-
};
|
|
19
|
-
function g(g) {
|
|
20
|
-
t(g.items);
|
|
21
|
-
let [_, v] = o(g.defaultValue ?? ""), y = g.value ?? _, b = g.items.find((e) => e.value === y) ?? (g.selectedOption?.value === y ? g.selectedOption : void 0), x = b?.label ?? y, [S, C] = o(g.defaultInputValue ?? x), w = g.inputValue ?? S, T = (e) => {
|
|
22
|
-
C(e), g.onDraftChange?.(e);
|
|
23
|
-
}, [E, D] = o(!1), [O, k] = o(null), A = a(null), j = a(null), M = a(null), [N, P] = o(null);
|
|
24
|
-
r(() => {
|
|
25
|
-
let e = A.current;
|
|
26
|
-
e && P(e.closest("[role=\"dialog\"], [role=\"alertdialog\"]") ?? e.ownerDocument.body);
|
|
27
|
-
}, []);
|
|
28
|
-
let F = a(null), I = a(!1), L = a({
|
|
29
|
-
value: y,
|
|
30
|
-
label: x
|
|
31
|
-
}), R = a(null), z = (e) => g.items.find((t) => t.value === e)?.label ?? (g.selectedOption?.value === e ? g.selectedOption.label : e), B = {
|
|
32
|
-
...n,
|
|
33
|
-
...g.messages
|
|
34
|
-
}, V = g.disabled || g.readOnly, H = (e) => {
|
|
35
|
-
(R.current?.from !== w || R.current.to !== e) && (R.current = null, g.inputValue === void 0 && T(e), g.onInputValueChange?.(e));
|
|
36
|
-
}, U = (e) => {
|
|
37
|
-
e !== w && (R.current?.from !== w || R.current.to !== e) && (R.current = {
|
|
38
|
-
from: w,
|
|
39
|
-
to: e
|
|
40
|
-
}, g.inputValue === void 0 ? T(e) : g.onInputValueChange?.(e));
|
|
41
|
-
}, W = (e) => {
|
|
42
|
-
g.value === void 0 && v(e), g.onValueChange?.(e);
|
|
43
|
-
};
|
|
44
|
-
r(() => {
|
|
45
|
-
(L.current.value !== y || L.current.label !== x) && (L.current = {
|
|
46
|
-
value: y,
|
|
47
|
-
label: x
|
|
48
|
-
}, U(x));
|
|
49
|
-
}, [y, x]), r(() => {
|
|
50
|
-
e() && y && !b && console.warn(`DDS choice: no label supplied for selected ID ${JSON.stringify(y)}; pass selectedOption when the selection is outside items.`);
|
|
51
|
-
}, [y, b]), r(() => {
|
|
52
|
-
let e = j.current?.form;
|
|
53
|
-
if (!e) return;
|
|
54
|
-
let t = (e) => setTimeout(() => {
|
|
55
|
-
if (e.defaultPrevented) return;
|
|
56
|
-
g.onFormReset?.();
|
|
57
|
-
let t = g.value ?? g.defaultValue ?? "", n = z(t);
|
|
58
|
-
L.current = {
|
|
59
|
-
value: t,
|
|
60
|
-
label: n
|
|
61
|
-
}, g.value === void 0 && v(t);
|
|
62
|
-
let r = g.defaultInputValue ?? n;
|
|
63
|
-
R.current = null, g.inputValue === void 0 ? T(r) : U(r), D(!1), A.current instanceof HTMLInputElement && (A.current.value = g.inputValue ?? r), j.current && (j.current.value = t);
|
|
64
|
-
});
|
|
65
|
-
return e.addEventListener("reset", t), () => e.removeEventListener("reset", t);
|
|
66
|
-
}, [
|
|
67
|
-
g.defaultValue,
|
|
68
|
-
g.defaultInputValue,
|
|
69
|
-
g.value,
|
|
70
|
-
g.inputValue,
|
|
71
|
-
g.items,
|
|
72
|
-
g.selectedOption,
|
|
73
|
-
g.form
|
|
74
|
-
]);
|
|
75
|
-
let G = i(() => g.searchable && g.filterMode !== "external" && w !== x ? g.items.filter((e) => g.matchItem ? g.matchItem(e, w) : e.label.toLocaleLowerCase().includes(w.toLocaleLowerCase())) : g.items, [
|
|
76
|
-
g.items,
|
|
77
|
-
g.searchable,
|
|
78
|
-
g.filterMode,
|
|
79
|
-
w,
|
|
80
|
-
x,
|
|
81
|
-
g.matchItem
|
|
82
|
-
]), K = i(() => d({
|
|
83
|
-
items: G,
|
|
84
|
-
itemToString: (e) => e.label,
|
|
85
|
-
itemToValue: (e) => e.value,
|
|
86
|
-
isItemDisabled: (e) => !!e.disabled
|
|
87
|
-
}), [G]), q = !!g.virtualization, J = g.virtualization ? g.virtualization.itemHeight : void 0, Y = Number.isFinite(J) ? Math.max(40, J) : 40, X = G.findIndex((e) => e.value === O), Z = m({
|
|
88
|
-
count: G.length,
|
|
89
|
-
getScrollElement: () => M.current,
|
|
90
|
-
estimateSize: () => Y,
|
|
91
|
-
overscan: g.virtualization ? g.virtualization.overscan ?? 5 : 5,
|
|
92
|
-
enabled: q && E,
|
|
93
|
-
initialRect: {
|
|
94
|
-
width: 0,
|
|
95
|
-
height: 320
|
|
96
|
-
},
|
|
97
|
-
rangeExtractor: (e) => {
|
|
98
|
-
let t = p(e);
|
|
99
|
-
return X >= 0 && !t.includes(X) && t.push(X), t.sort((e, t) => e - t);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
r(() => {
|
|
103
|
-
k(null), q && E && Z.scrollToIndex(Math.max(0, G.findIndex((e) => e.value === y)), { align: g.centerSelected ? "center" : "auto" });
|
|
104
|
-
}, [G, E]), r(() => {
|
|
105
|
-
let e = M.current;
|
|
106
|
-
if (!g.centerSelected || !E || q || !e) return;
|
|
107
|
-
let t = requestAnimationFrame(() => {
|
|
108
|
-
let t = e.querySelector("[data-part=\"item\"][data-state=\"checked\"]");
|
|
109
|
-
if (!t) return;
|
|
110
|
-
let n = e.getBoundingClientRect(), r = t.getBoundingClientRect();
|
|
111
|
-
e.scrollTop += r.top - n.top - (e.clientHeight - r.height) / 2;
|
|
112
|
-
});
|
|
113
|
-
return () => cancelAnimationFrame(t);
|
|
114
|
-
}, [
|
|
115
|
-
E,
|
|
116
|
-
g.centerSelected,
|
|
117
|
-
q
|
|
118
|
-
]);
|
|
119
|
-
let Q = g.searchable ? u : f, $ = q ? Z.getVirtualItems().map((e) => ({
|
|
120
|
-
index: e.index,
|
|
121
|
-
start: e.start
|
|
122
|
-
})) : G.map((e, t) => ({
|
|
123
|
-
index: t,
|
|
124
|
-
start: 0
|
|
125
|
-
}));
|
|
126
|
-
q && X >= 0 && !$.some((e) => e.index === X) && $.push({
|
|
127
|
-
index: X,
|
|
128
|
-
start: X * Y
|
|
129
|
-
});
|
|
130
|
-
let ee = g.loading ? B.loading : g.error ? typeof g.error == "string" ? g.error : B.error : G.length === 0 ? B.empty : "", te = {
|
|
131
|
-
collection: K,
|
|
132
|
-
value: y ? [y] : [],
|
|
133
|
-
open: E && !V,
|
|
134
|
-
disabled: g.disabled,
|
|
135
|
-
readOnly: g.readOnly,
|
|
136
|
-
invalid: g.invalid,
|
|
137
|
-
onOpenChange: (e) => {
|
|
138
|
-
V || D(e.open);
|
|
139
|
-
},
|
|
140
|
-
onValueChange: (e) => {
|
|
141
|
-
if (V || I.current) return;
|
|
142
|
-
let t = e.value[0] ?? "";
|
|
143
|
-
t !== y && W(t);
|
|
144
|
-
},
|
|
145
|
-
onHighlightChange: (e) => k(e.highlightedValue),
|
|
146
|
-
scrollToIndexFn: q ? ({ index: e }) => Z.scrollToIndex(e, { align: "auto" }) : void 0,
|
|
147
|
-
positioning: {
|
|
148
|
-
placement: "bottom-start",
|
|
149
|
-
sameWidth: !0,
|
|
150
|
-
gutter: 4,
|
|
151
|
-
strategy: N?.matches("[role=\"dialog\"], [role=\"alertdialog\"]") ? "fixed" : "absolute",
|
|
152
|
-
hideWhenDetached: !!N?.matches("[role=\"dialog\"], [role=\"alertdialog\"]")
|
|
153
|
-
}
|
|
154
|
-
}, ne = g.searchable ? {
|
|
155
|
-
inputValue: w,
|
|
156
|
-
onInputValueChange: (e) => {
|
|
157
|
-
let t = F.current === e.inputValue && e.reason === "input-change" && A.current?.ownerDocument.activeElement !== A.current;
|
|
158
|
-
F.current = null, !t && !V && e.inputValue !== w && H(e.inputValue);
|
|
159
|
-
},
|
|
160
|
-
selectionBehavior: "preserve",
|
|
161
|
-
...g.autoHighlight ? { inputBehavior: "autohighlight" } : {}
|
|
162
|
-
} : {};
|
|
163
|
-
return /* @__PURE__ */ c(Q.Root, {
|
|
164
|
-
...te,
|
|
165
|
-
...ne,
|
|
166
|
-
id: g.id,
|
|
167
|
-
className: g.rootClass ? `dds-choice ${g.rootClass}` : "dds-choice",
|
|
168
|
-
"data-label-placement": g.labelPlacement ?? "outside",
|
|
169
|
-
"data-has-value": y || w ? "" : void 0,
|
|
170
|
-
children: [
|
|
171
|
-
g.label && /* @__PURE__ */ s(Q.Label, {
|
|
172
|
-
className: "dds-choice-label",
|
|
173
|
-
onClick: () => A.current?.focus(),
|
|
174
|
-
children: g.label
|
|
175
|
-
}),
|
|
176
|
-
/* @__PURE__ */ c(Q.Control, {
|
|
177
|
-
className: "dds-choice-control",
|
|
178
|
-
children: [
|
|
179
|
-
g.searchable ? /* @__PURE__ */ s(u.Input, {
|
|
180
|
-
ref: (e) => {
|
|
181
|
-
A.current = e;
|
|
182
|
-
},
|
|
183
|
-
className: "dds-choice-input",
|
|
184
|
-
"aria-label": g["aria-label"],
|
|
185
|
-
"aria-labelledby": g["aria-labelledby"],
|
|
186
|
-
"aria-describedby": g["aria-describedby"],
|
|
187
|
-
"aria-required": g.required,
|
|
188
|
-
placeholder: g.placeholder,
|
|
189
|
-
inputMode: g.inputMode,
|
|
190
|
-
onCompositionStart: () => {
|
|
191
|
-
I.current = !0;
|
|
192
|
-
},
|
|
193
|
-
onCompositionEnd: () => {
|
|
194
|
-
I.current = !1;
|
|
195
|
-
},
|
|
196
|
-
onKeyDown: (e) => {
|
|
197
|
-
I.current && e.key === "Enter" && (e.preventDefault(), e.stopPropagation());
|
|
198
|
-
},
|
|
199
|
-
onBlur: (e) => {
|
|
200
|
-
if (g.commitDraft) {
|
|
201
|
-
F.current = e.currentTarget.value;
|
|
202
|
-
let t = V ? null : g.commitDraft(e.currentTarget.value);
|
|
203
|
-
t !== null && t !== y ? (W(t), U(z(t))) : U(x);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
y && U(x);
|
|
207
|
-
}
|
|
208
|
-
}) : null,
|
|
209
|
-
/* @__PURE__ */ s(Q.Trigger, {
|
|
210
|
-
ref: (e) => {
|
|
211
|
-
g.searchable || (A.current = e);
|
|
212
|
-
},
|
|
213
|
-
className: "dds-choice-trigger",
|
|
214
|
-
"aria-label": g.searchable ? B.open : g["aria-label"],
|
|
215
|
-
"aria-labelledby": g["aria-labelledby"],
|
|
216
|
-
"aria-describedby": g["aria-describedby"],
|
|
217
|
-
"aria-required": g.required,
|
|
218
|
-
children: g.searchable ? g.triggerContent ?? "⌄" : /* @__PURE__ */ s("span", {
|
|
219
|
-
className: "dds-choice-value",
|
|
220
|
-
children: x || g.placeholder || B.open
|
|
221
|
-
})
|
|
222
|
-
}),
|
|
223
|
-
g.clearable && !V && (y || w) ? /* @__PURE__ */ s("button", {
|
|
224
|
-
className: "dds-choice-clear",
|
|
225
|
-
type: "button",
|
|
226
|
-
"aria-label": B.clear,
|
|
227
|
-
onPointerDown: (e) => e.preventDefault(),
|
|
228
|
-
onClick: () => {
|
|
229
|
-
W(""), H(""), D(!1), A.current?.focus();
|
|
230
|
-
},
|
|
231
|
-
children: "×"
|
|
232
|
-
}) : null
|
|
233
|
-
]
|
|
234
|
-
}),
|
|
235
|
-
/* @__PURE__ */ s("input", {
|
|
236
|
-
ref: j,
|
|
237
|
-
className: "dds-choice-validation",
|
|
238
|
-
style: h,
|
|
239
|
-
tabIndex: -1,
|
|
240
|
-
"aria-hidden": "true",
|
|
241
|
-
name: g.name,
|
|
242
|
-
form: g.form,
|
|
243
|
-
value: y,
|
|
244
|
-
required: g.required,
|
|
245
|
-
disabled: g.disabled,
|
|
246
|
-
onChange: () => {},
|
|
247
|
-
onInvalid: (e) => {
|
|
248
|
-
e.preventDefault(), A.current?.focus();
|
|
249
|
-
}
|
|
250
|
-
}),
|
|
251
|
-
/* @__PURE__ */ c("div", {
|
|
252
|
-
className: "dds-choice-status",
|
|
253
|
-
role: "status",
|
|
254
|
-
"aria-live": "polite",
|
|
255
|
-
children: [ee, g.error && g.onRetry ? /* @__PURE__ */ s("button", {
|
|
256
|
-
className: "dds-choice-retry",
|
|
257
|
-
type: "button",
|
|
258
|
-
onClick: g.onRetry,
|
|
259
|
-
children: B.retry
|
|
260
|
-
}) : null]
|
|
261
|
-
}),
|
|
262
|
-
N && /* @__PURE__ */ s(l, {
|
|
263
|
-
container: { current: N },
|
|
264
|
-
children: /* @__PURE__ */ s(Q.Positioner, {
|
|
265
|
-
className: "dds-choice-positioner",
|
|
266
|
-
children: /* @__PURE__ */ s(Q.Content, {
|
|
267
|
-
ref: M,
|
|
268
|
-
className: "dds-choice-content",
|
|
269
|
-
style: {
|
|
270
|
-
maxHeight: "min(320px, var(--available-height, 320px))",
|
|
271
|
-
overflow: "auto"
|
|
272
|
-
},
|
|
273
|
-
children: /* @__PURE__ */ s("div", {
|
|
274
|
-
style: q ? {
|
|
275
|
-
height: Z.getTotalSize(),
|
|
276
|
-
position: "relative"
|
|
277
|
-
} : void 0,
|
|
278
|
-
children: $.map((e) => {
|
|
279
|
-
let t = G[e.index];
|
|
280
|
-
return /* @__PURE__ */ c(Q.Item, {
|
|
281
|
-
item: t,
|
|
282
|
-
className: "dds-choice-item",
|
|
283
|
-
"aria-posinset": e.index + 1,
|
|
284
|
-
"aria-setsize": G.length,
|
|
285
|
-
style: q ? {
|
|
286
|
-
position: "absolute",
|
|
287
|
-
top: 0,
|
|
288
|
-
left: 0,
|
|
289
|
-
width: "100%",
|
|
290
|
-
height: Y,
|
|
291
|
-
transform: `translateY(${e.start}px)`
|
|
292
|
-
} : void 0,
|
|
293
|
-
children: [/* @__PURE__ */ s(Q.ItemText, { children: t.label }), t.description ? /* @__PURE__ */ s("span", {
|
|
294
|
-
className: "dds-choice-description",
|
|
295
|
-
children: t.description
|
|
296
|
-
}) : null]
|
|
297
|
-
}, t.value);
|
|
298
|
-
})
|
|
299
|
-
})
|
|
300
|
-
})
|
|
301
|
-
})
|
|
302
|
-
})
|
|
303
|
-
]
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
//#endregion
|
|
307
|
-
export { g as t };
|
|
308
|
-
|
|
309
|
-
//# sourceMappingURL=choice-N-5K_ggs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choice-N-5K_ggs.js","names":[],"sources":["../src/internal/choice.tsx"],"sourcesContent":["import { Combobox as C, createListCollection } from \"@ark-ui/react/combobox\";\nimport { Select as S } from \"@ark-ui/react/select\";\nimport { Portal } from \"@ark-ui/react/portal\";\nimport { defaultRangeExtractor, useVirtualizer } from \"@tanstack/react-virtual\";\nimport { useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport {\n choiceMessages,\n choiceWarningsEnabled,\n validateOptions,\n type ChoiceOption,\n type ComboboxProps,\n} from \"../choice-types\";\n\n/**\n * Options for DDS components built on Choice (TimePicker). They are not part\n * of the public Combobox/SelectPicker props; every default keeps the existing\n * Combobox and SelectPicker behavior. Mirrors the Solid Choice internals.\n */\nexport interface ChoiceInternals {\n searchable: boolean;\n /** Replaces the default case-insensitive label substring filter. */\n matchItem?: (item: ChoiceOption, query: string) => boolean;\n /** On blur, the value the typed text stands for, \"\" to clear, or null to restore the label. */\n commitDraft?: (text: string) => string | null;\n /** Content of the searchable trigger button (default \"⌄\"). */\n triggerContent?: ReactNode;\n rootClass?: string;\n invalid?: boolean;\n /** Highlight the first match while typing so Enter picks it. */\n autoHighlight?: boolean;\n /** Scroll the selected option to the middle of the list when it opens. */\n centerSelected?: boolean;\n inputMode?: HTMLAttributes<HTMLInputElement>[\"inputMode\"];\n /** Called before a native form reset restores the value. */\n onFormReset?: () => void;\n /** Observes every change of the uncontrolled input text, including restores. */\n onDraftChange?: (text: string) => void;\n}\n\n/** The native validation input stores one ID, never a second option collection. */\nconst validationStyle = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n border: 0,\n clipPath: \"inset(50%)\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n} as const;\nexport function Choice(props: ComboboxProps & ChoiceInternals) {\n validateOptions(props.items);\n const [internal, setInternal] = useState(props.defaultValue ?? \"\");\n const value = props.value ?? internal;\n const selected =\n props.items.find((item) => item.value === value) ??\n (props.selectedOption?.value === value ? props.selectedOption : undefined);\n const label = selected?.label ?? value;\n const [draft, setDraft] = useState(props.defaultInputValue ?? label);\n const inputValue = props.inputValue ?? draft;\n const changeDraft = (next: string) => {\n setDraft(next);\n props.onDraftChange?.(next);\n };\n const [open, setOpen] = useState(false),\n [highlight, setHighlight] = useState<string | null>(null);\n const visibleRef = useRef<HTMLInputElement | HTMLButtonElement>(null),\n validationRef = useRef<HTMLInputElement>(null),\n scrollRef = useRef<HTMLDivElement>(null);\n const [portalMount, setPortalMount] = useState<HTMLElement | null>(null);\n useEffect(() => {\n const control = visibleRef.current;\n if (control) {\n // Modal isolation hides body siblings. Keep nested choices in the modal's\n // DOM subtree so their options remain available to assistive technology.\n setPortalMount(\n control.closest<HTMLElement>('[role=\"dialog\"], [role=\"alertdialog\"]') ??\n control.ownerDocument.body,\n );\n }\n }, []);\n // Text the blur already committed; Ark may still report that keystroke afterwards.\n const consumedOnBlur = useRef<string | null>(null);\n const composing = useRef(false),\n previousSelection = useRef({ value, label });\n const pendingRestore = useRef<{ from: string; to: string } | null>(null);\n const resolveLabel = (id: string) =>\n props.items.find((item) => item.value === id)?.label ??\n (props.selectedOption?.value === id ? props.selectedOption.label : id);\n const messages = { ...choiceMessages, ...props.messages };\n const blocked = props.disabled || props.readOnly;\n const setInput = (next: string) => {\n if (\n pendingRestore.current?.from === inputValue &&\n pendingRestore.current.to === next\n )\n return;\n pendingRestore.current = null;\n if (props.inputValue === undefined) changeDraft(next);\n props.onInputValueChange?.(next);\n };\n const restoreInput = (next: string) => {\n if (next === inputValue) return;\n if (\n pendingRestore.current?.from === inputValue &&\n pendingRestore.current.to === next\n )\n return;\n pendingRestore.current = { from: inputValue, to: next };\n if (props.inputValue === undefined) changeDraft(next);\n else props.onInputValueChange?.(next);\n };\n const setValue = (next: string) => {\n if (props.value === undefined) setInternal(next);\n props.onValueChange?.(next);\n };\n useEffect(() => {\n if (\n previousSelection.current.value !== value ||\n previousSelection.current.label !== label\n ) {\n previousSelection.current = { value, label };\n restoreInput(label);\n }\n }, [value, label]);\n useEffect(() => {\n if (choiceWarningsEnabled() && value && !selected)\n console.warn(\n `DDS choice: no label supplied for selected ID ${JSON.stringify(value)}; pass selectedOption when the selection is outside items.`,\n );\n }, [value, selected]);\n useEffect(() => {\n const form = validationRef.current?.form;\n if (!form) return;\n // A task, not a microtask: after a reset-button click, microtasks run\n // before the browser resets the controls and would be overwritten.\n const reset = (event: Event) =>\n setTimeout(() => {\n if (event.defaultPrevented) return;\n props.onFormReset?.();\n const resetValue = props.value ?? props.defaultValue ?? \"\";\n const resetLabel = resolveLabel(resetValue);\n previousSelection.current = { value: resetValue, label: resetLabel };\n if (props.value === undefined) setInternal(resetValue);\n const resetQuery = props.defaultInputValue ?? resetLabel;\n pendingRestore.current = null;\n if (props.inputValue === undefined) changeDraft(resetQuery);\n else restoreInput(resetQuery);\n setOpen(false);\n if (visibleRef.current instanceof HTMLInputElement)\n visibleRef.current.value = props.inputValue ?? resetQuery;\n if (validationRef.current) validationRef.current.value = resetValue;\n });\n form.addEventListener(\"reset\", reset);\n return () => form.removeEventListener(\"reset\", reset);\n }, [\n props.defaultValue,\n props.defaultInputValue,\n props.value,\n props.inputValue,\n props.items,\n props.selectedOption,\n props.form,\n ]);\n const items = useMemo(\n () =>\n props.searchable &&\n props.filterMode !== \"external\" &&\n inputValue !== label\n ? props.items.filter((item) =>\n props.matchItem\n ? props.matchItem(item, inputValue)\n : item.label\n .toLocaleLowerCase()\n .includes(inputValue.toLocaleLowerCase()),\n )\n : props.items,\n [props.items, props.searchable, props.filterMode, inputValue, label, props.matchItem],\n );\n const collection = useMemo(\n () =>\n createListCollection({\n items,\n itemToString: (item) => item.label,\n itemToValue: (item) => item.value,\n isItemDisabled: (item) => !!item.disabled,\n }),\n [items],\n );\n const virtual = !!props.virtualization;\n const configuredHeight = props.virtualization\n ? props.virtualization.itemHeight\n : undefined;\n const height = Number.isFinite(configuredHeight)\n ? Math.max(40, configuredHeight!)\n : 40;\n const activeIndex = items.findIndex((item) => item.value === highlight);\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => height,\n overscan: props.virtualization ? (props.virtualization.overscan ?? 5) : 5,\n enabled: virtual && open,\n initialRect: { width: 0, height: 320 },\n rangeExtractor: (range) => {\n const indexes = defaultRangeExtractor(range);\n if (activeIndex >= 0 && !indexes.includes(activeIndex))\n indexes.push(activeIndex);\n return indexes.sort((a, b) => a - b);\n },\n });\n useEffect(() => {\n setHighlight(null);\n if (virtual && open)\n virtualizer.scrollToIndex(\n Math.max(\n 0,\n items.findIndex((item) => item.value === value),\n ),\n { align: props.centerSelected ? \"center\" : \"auto\" },\n );\n }, [items, open]);\n useEffect(() => {\n const content = scrollRef.current;\n if (!props.centerSelected || !open || virtual || !content) return;\n // Ark only scrolls the highlighted option to the nearest edge.\n const frame = requestAnimationFrame(() => {\n const chosen = content.querySelector<HTMLElement>(\n '[data-part=\"item\"][data-state=\"checked\"]',\n );\n if (!chosen) return;\n const list = content.getBoundingClientRect(),\n row = chosen.getBoundingClientRect();\n content.scrollTop +=\n row.top - list.top - (content.clientHeight - row.height) / 2;\n });\n return () => cancelAnimationFrame(frame);\n }, [open, props.centerSelected, virtual]);\n const Parts = props.searchable ? C : S;\n const rows = virtual\n ? virtualizer\n .getVirtualItems()\n .map((row) => ({ index: row.index, start: row.start }))\n : items.map((_, index) => ({ index, start: 0 }));\n // Keep the active row mounted even before the scroll element has a measured range.\n if (\n virtual &&\n activeIndex >= 0 &&\n !rows.some((row) => row.index === activeIndex)\n )\n rows.push({ index: activeIndex, start: activeIndex * height });\n const status = props.loading\n ? messages.loading\n : props.error\n ? typeof props.error === \"string\"\n ? props.error\n : messages.error\n : items.length === 0\n ? messages.empty\n : \"\";\n const rootProps = {\n collection,\n value: value ? [value] : [],\n open: open && !blocked,\n disabled: props.disabled,\n readOnly: props.readOnly,\n invalid: props.invalid,\n onOpenChange: (details: { open: boolean }) => {\n if (!blocked) setOpen(details.open);\n },\n onValueChange: (details: { value: string[] }) => {\n if (blocked || composing.current) return;\n const next = details.value[0] ?? \"\";\n if (next !== value) setValue(next);\n },\n onHighlightChange: (details: { highlightedValue: string | null }) =>\n setHighlight(details.highlightedValue),\n scrollToIndexFn: virtual\n ? ({ index }: { index: number }) =>\n virtualizer.scrollToIndex(index, { align: \"auto\" })\n : undefined,\n positioning: {\n placement: \"bottom-start\" as const,\n sameWidth: true,\n gutter: 4,\n strategy: portalMount?.matches('[role=\"dialog\"], [role=\"alertdialog\"]')\n ? (\"fixed\" as const)\n : (\"absolute\" as const),\n hideWhenDetached: !!portalMount?.matches(\n '[role=\"dialog\"], [role=\"alertdialog\"]',\n ),\n },\n };\n const inputProps = props.searchable\n ? {\n inputValue,\n onInputValueChange: (details: {\n inputValue: string;\n reason?: string;\n }) => {\n const stale =\n consumedOnBlur.current === details.inputValue &&\n details.reason === \"input-change\" &&\n visibleRef.current?.ownerDocument.activeElement !== visibleRef.current;\n consumedOnBlur.current = null;\n if (stale) return;\n if (!blocked && details.inputValue !== inputValue)\n setInput(details.inputValue);\n },\n selectionBehavior: \"preserve\" as const,\n ...(props.autoHighlight\n ? { inputBehavior: \"autohighlight\" as const }\n : {}),\n }\n : {};\n return (\n <Parts.Root\n {...rootProps}\n {...inputProps}\n id={props.id}\n className={props.rootClass ? `dds-choice ${props.rootClass}` : \"dds-choice\"}\n data-label-placement={props.labelPlacement ?? \"outside\"}\n data-has-value={value || inputValue ? \"\" : undefined}\n >\n {props.label && (\n <Parts.Label\n className=\"dds-choice-label\"\n onClick={() => visibleRef.current?.focus()}\n >\n {props.label}\n </Parts.Label>\n )}\n <Parts.Control className=\"dds-choice-control\">\n {props.searchable ? (\n <C.Input\n ref={(node) => {\n visibleRef.current = node;\n }}\n className=\"dds-choice-input\"\n aria-label={props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={props.required}\n placeholder={props.placeholder}\n inputMode={props.inputMode}\n onCompositionStart={() => {\n composing.current = true;\n }}\n onCompositionEnd={() => {\n composing.current = false;\n }}\n onKeyDown={(event) => {\n if (composing.current && event.key === \"Enter\") {\n event.preventDefault();\n event.stopPropagation();\n }\n }}\n onBlur={(event) => {\n if (props.commitDraft) {\n // The DOM holds the latest keystroke; Ark's input state may still be queued.\n consumedOnBlur.current = event.currentTarget.value;\n const next = blocked\n ? null\n : props.commitDraft(event.currentTarget.value);\n if (next !== null && next !== value) {\n setValue(next);\n restoreInput(resolveLabel(next));\n } else restoreInput(label);\n return;\n }\n if (value) restoreInput(label);\n }}\n />\n ) : null}\n <Parts.Trigger\n ref={(node) => {\n if (!props.searchable) visibleRef.current = node;\n }}\n className=\"dds-choice-trigger\"\n aria-label={props.searchable ? messages.open : props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={props.required}\n >\n {props.searchable ? (\n (props.triggerContent ?? \"⌄\")\n ) : (\n <span className=\"dds-choice-value\">\n {label || props.placeholder || messages.open}\n </span>\n )}\n </Parts.Trigger>\n {props.clearable && !blocked && (value || inputValue) ? (\n <button\n className=\"dds-choice-clear\"\n type=\"button\"\n aria-label={messages.clear}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n setValue(\"\");\n setInput(\"\");\n setOpen(false);\n visibleRef.current?.focus();\n }}\n >\n ×\n </button>\n ) : null}\n </Parts.Control>\n <input\n ref={validationRef}\n className=\"dds-choice-validation\"\n style={validationStyle}\n tabIndex={-1}\n aria-hidden=\"true\"\n name={props.name}\n form={props.form}\n value={value}\n required={props.required}\n disabled={props.disabled}\n onChange={() => {}}\n onInvalid={(event) => {\n event.preventDefault();\n visibleRef.current?.focus();\n }}\n />\n <div className=\"dds-choice-status\" role=\"status\" aria-live=\"polite\">\n {status}\n {props.error && props.onRetry ? (\n <button\n className=\"dds-choice-retry\"\n type=\"button\"\n onClick={props.onRetry}\n >\n {messages.retry}\n </button>\n ) : null}\n </div>\n {portalMount && (\n <Portal container={{ current: portalMount }}>\n <Parts.Positioner className=\"dds-choice-positioner\">\n <Parts.Content\n ref={scrollRef}\n className=\"dds-choice-content\"\n style={{\n maxHeight: \"min(320px, var(--available-height, 320px))\",\n overflow: \"auto\",\n }}\n >\n <div\n style={\n virtual\n ? {\n height: virtualizer.getTotalSize(),\n position: \"relative\",\n }\n : undefined\n }\n >\n {rows.map((row) => {\n const item = items[row.index]!;\n return (\n <Parts.Item\n key={item.value}\n item={item}\n className=\"dds-choice-item\"\n aria-posinset={row.index + 1}\n aria-setsize={items.length}\n style={\n virtual\n ? {\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height,\n transform: `translateY(${row.start}px)`,\n }\n : undefined\n }\n >\n <Parts.ItemText>{item.label}</Parts.ItemText>\n {item.description ? (\n <span className=\"dds-choice-description\">\n {item.description}\n </span>\n ) : null}\n </Parts.Item>\n );\n })}\n </div>\n </Parts.Content>\n </Parts.Positioner>\n </Portal>\n )}\n </Parts.Root>\n );\n}\n"],"mappings":"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"}
|