@godxjp/ui 21.0.0 → 23.0.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 +4 -4
- package/dist/app/app-provider.js +2 -1
- package/dist/components/data-display/badge.d.ts +28 -1
- package/dist/components/data-display/badge.js +2 -0
- package/dist/components/data-display/data-table.d.ts +18 -2
- package/dist/components/data-display/data-table.js +4 -0
- package/dist/components/data-display/index.d.ts +1 -1
- package/dist/components/data-display/popover.d.ts +19 -1
- package/dist/components/data-display/popover.js +9 -1
- package/dist/components/data-display/progress.d.ts +37 -0
- package/dist/components/data-display/progress.js +57 -5
- package/dist/components/data-display/scroll-area.d.ts +24 -4
- package/dist/components/data-display/scroll-area.js +34 -72
- package/dist/components/data-entry/cascader.js +8 -6
- package/dist/components/data-entry/checkbox.js +2 -0
- package/dist/components/data-entry/choice-hit-target.d.ts +24 -0
- package/dist/components/data-entry/choice-hit-target.js +12 -0
- package/dist/components/data-entry/control-surface.d.ts +8 -0
- package/dist/components/data-entry/control-surface.js +10 -1
- package/dist/components/data-entry/date-picker.d.ts +10 -3
- package/dist/components/data-entry/date-picker.js +503 -238
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +7 -3
- package/dist/components/data-entry/form.js +10 -1
- package/dist/components/data-entry/index.d.ts +0 -6
- package/dist/components/data-entry/index.js +0 -6
- package/dist/components/data-entry/label.d.ts +14 -1
- package/dist/components/data-entry/label.js +6 -1
- package/dist/components/data-entry/radio.d.ts +27 -6
- package/dist/components/data-entry/radio.js +89 -43
- package/dist/components/data-entry/search-select.js +226 -89
- package/dist/components/data-entry/select.d.ts +76 -14
- package/dist/components/data-entry/select.js +497 -163
- package/dist/components/data-entry/slider.d.ts +3 -11
- package/dist/components/data-entry/slider.js +582 -93
- package/dist/components/data-entry/switch.d.ts +6 -3
- package/dist/components/data-entry/switch.js +36 -11
- package/dist/components/layout/mobile-shell.d.ts +1 -1
- package/dist/components/layout/mobile-shell.js +2 -0
- package/dist/components/navigation/dropdown-menu.d.ts +11 -3
- package/dist/components/navigation/dropdown-menu.js +190 -15
- package/dist/components/navigation/index.d.ts +0 -3
- package/dist/components/navigation/index.js +0 -78
- package/dist/components/navigation/steps.d.ts +1 -1
- package/dist/components/navigation/steps.js +3 -1
- package/dist/components/navigation/tabs-scroll.d.ts +27 -0
- package/dist/components/navigation/tabs-scroll.js +52 -1
- package/dist/components/navigation/tabs.d.ts +2 -2
- package/dist/components/navigation/tabs.js +88 -23
- package/dist/components/ui/index.d.ts +0 -4
- package/dist/components/ui/index.js +0 -4
- package/dist/components/ui/input-otp.d.ts +1 -1
- package/dist/components/ui/segmented.d.ts +15 -1
- package/dist/components/ui/segmented.js +15 -6
- package/dist/components/ui/tag-input.js +3 -5
- package/dist/i18n/messages/en.json +3 -2
- package/dist/i18n/messages/ja.json +3 -2
- package/dist/i18n/messages/vi.json +3 -2
- package/dist/lib/datetime/picker-format.d.ts +18 -0
- package/dist/lib/datetime/picker-format.js +35 -1
- package/dist/lib/field-a11y.d.ts +12 -0
- package/dist/lib/field-a11y.js +14 -1
- package/dist/lib/select-options.d.ts +21 -0
- package/dist/lib/select-options.js +46 -0
- package/dist/props/components/data-display.prop.d.ts +16 -6
- package/dist/props/components/data-entry.prop.d.ts +503 -129
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +12 -1
- package/dist/props/components/navigation.prop.d.ts +93 -1
- package/dist/props/registry.d.ts +79 -16
- package/dist/props/registry.js +85 -15
- package/dist/props/vocabulary/data.prop.d.ts +12 -0
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/layout.prop.d.ts +11 -0
- package/dist/styles/badge-layout.css +4 -0
- package/dist/styles/card-layout.css +6 -6
- package/dist/styles/control.css +220 -29
- package/dist/styles/data-display-layout.css +94 -23
- package/dist/styles/focus-ring.css +6 -4
- package/dist/styles/fonts.css +88 -4
- package/dist/styles/navigation-layout.css +36 -236
- package/dist/styles/shell-layout.css +149 -139
- package/dist/styles/table-layout.css +41 -3
- package/dist/tokens/components/control.css +4 -0
- package/dist/tokens/components/data-display.css +9 -5
- package/dist/tokens/components/navigation.css +9 -5
- package/dist/tokens/components/scroll-area.css +7 -0
- package/dist/tokens/components/segmented.css +0 -2
- package/dist/tokens/components/shell.css +2 -0
- package/dist/tokens/components/table.css +3 -0
- package/dist/tokens/foundation.css +7 -0
- package/docs/COMPONENTS.md +14 -14
- package/docs/CONSUMER-RULES.md +24 -1
- package/docs/CUSTOMER-THEMING.md +7 -1
- package/docs/FRAME-COVERAGE-REPORT.md +5 -11
- package/docs/TOKENS.md +65 -0
- package/docs/data-display/badge.tsx +37 -0
- package/docs/data-display/data-table/index.tsx +45 -1
- package/docs/data-display/popover.tsx +43 -5
- package/docs/data-display/progress.tsx +28 -0
- package/docs/data-display/scroll-area.tsx +51 -45
- package/docs/data-entry/calendar.tsx +2 -2
- package/docs/data-entry/date-picker.tsx +144 -5
- package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
- package/docs/data-entry/form.tsx +4 -4
- package/docs/data-entry/input-otp.tsx +5 -2
- package/docs/data-entry/number-input.tsx +31 -0
- package/docs/data-entry/segmented.tsx +143 -2
- package/docs/data-entry/select-matrix.tsx +1 -2
- package/docs/data-entry/select.tsx +108 -3
- package/docs/data-entry/slider.tsx +125 -47
- package/docs/feedback/dialog.tsx +1 -2
- package/docs/feedback/sheet.tsx +1 -2
- package/docs/layout/app-shell-states.tsx +143 -0
- package/docs/layout/mobile-shell.tsx +5 -0
- package/docs/navigation/dropdown-menu.tsx +75 -4
- package/docs/navigation/tabs.tsx +149 -0
- package/docs/roadmap/antd-parity.md +35 -34
- package/docs/roadmap/parity-audit-data-entry.md +196 -172
- package/docs/roadmap/parity-audit-layout-navigation-general.md +304 -310
- package/docs/roadmap/parity-backlog.md +8 -10
- package/docs/showcase/acme-portal.tsx +7 -0
- package/package.json +28 -64
- package/scripts/ui-audit.mjs +18 -5
- package/scripts/visual-audit-rules.mjs +0 -7
- package/scripts/visual-audit.mjs +6 -27
- package/dist/components/data-entry/date-range-picker.d.ts +0 -11
- package/dist/components/data-entry/date-range-picker.js +0 -349
- package/dist/components/data-entry/month-picker.d.ts +0 -10
- package/dist/components/data-entry/month-picker.js +0 -241
- package/dist/components/data-entry/month-range-picker.d.ts +0 -10
- package/dist/components/data-entry/month-range-picker.js +0 -301
- package/dist/components/navigation/context-menu.d.ts +0 -21
- package/dist/components/navigation/context-menu.js +0 -149
- package/dist/components/navigation/menubar.d.ts +0 -21
- package/dist/components/navigation/menubar.js +0 -136
- package/dist/components/navigation/navigation-menu.d.ts +0 -10
- package/dist/components/navigation/navigation-menu.js +0 -91
- package/dist/components/ui/context-menu.d.ts +0 -1
- package/dist/components/ui/context-menu.js +0 -2
- package/dist/components/ui/date-range-picker.d.ts +0 -1
- package/dist/components/ui/date-range-picker.js +0 -2
- package/dist/components/ui/menubar.d.ts +0 -1
- package/dist/components/ui/menubar.js +0 -2
- package/dist/components/ui/navigation-menu.d.ts +0 -1
- package/dist/components/ui/navigation-menu.js +0 -2
- package/docs/FRAME-A11Y-CI.md +0 -349
- package/docs/data-entry/date-range-picker.tsx +0 -175
- package/docs/data-entry/month-picker.tsx +0 -101
- package/docs/data-entry/month-range-picker.tsx +0 -115
- package/docs/navigation/context-menu.tsx +0 -128
- package/docs/navigation/menubar.tsx +0 -141
- package/docs/navigation/navigation-menu.tsx +0 -158
|
@@ -1,71 +1,230 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
Button as AriaButton,
|
|
6
|
+
ButtonContext,
|
|
7
|
+
Header as AriaHeader,
|
|
8
|
+
ListBox,
|
|
9
|
+
ListBoxItem,
|
|
10
|
+
ListBoxSection,
|
|
11
|
+
Popover as AriaPopover,
|
|
12
|
+
Select as AriaSelect,
|
|
13
|
+
SelectStateContext,
|
|
14
|
+
SelectValue as AriaSelectValue,
|
|
15
|
+
Separator as AriaSeparator
|
|
16
|
+
} from "react-aria-components";
|
|
17
|
+
import { ChevronDown, Loader2, X } from "lucide-react";
|
|
6
18
|
import { cn } from "../../lib/utils.js";
|
|
7
19
|
import { controlSurfaceTriggerClass } from "../../lib/control-styles.js";
|
|
8
20
|
import { controlSurfaceAttrs, resolveAllowClear, resolveAriaInvalid } from "./control-surface.js";
|
|
9
|
-
import { useInertHiddenBackground } from "../general/inert-background.js";
|
|
10
21
|
import {
|
|
11
22
|
mergeAriaIds,
|
|
12
23
|
useFieldIdentity,
|
|
13
|
-
omitFieldA11y,
|
|
14
24
|
pickFieldA11y,
|
|
15
25
|
useFieldNameFallback
|
|
16
26
|
} from "../../lib/field-a11y.js";
|
|
27
|
+
import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
|
|
28
|
+
import { radixSurfaceState, toPlacement } from "../navigation/dropdown-menu.js";
|
|
17
29
|
import { SearchSelect } from "./search-select.js";
|
|
18
30
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
31
|
+
import { normalizeSelectOptions } from "../../lib/select-options.js";
|
|
19
32
|
function isDataSelect(props) {
|
|
20
33
|
return "options" in props || "loadOptions" in props;
|
|
21
34
|
}
|
|
22
35
|
const SelectFieldA11yContext = React.createContext(null);
|
|
36
|
+
function toKey(value) {
|
|
37
|
+
if (value === void 0) return void 0;
|
|
38
|
+
return value === "" ? null : value;
|
|
39
|
+
}
|
|
40
|
+
function splitDomProps(props) {
|
|
41
|
+
const events = {};
|
|
42
|
+
const attributes = {};
|
|
43
|
+
for (const [key, value] of Object.entries(props)) {
|
|
44
|
+
if (/^on[A-Z]/.test(key)) events[key] = value;
|
|
45
|
+
else attributes[key] = value;
|
|
46
|
+
}
|
|
47
|
+
return { events, attributes };
|
|
48
|
+
}
|
|
49
|
+
function itemTextValue(node) {
|
|
50
|
+
if (node == null || typeof node === "boolean") return "";
|
|
51
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
52
|
+
if (Array.isArray(node)) return node.map(itemTextValue).join("");
|
|
53
|
+
if (React.isValidElement(node)) {
|
|
54
|
+
return itemTextValue(node.props.children);
|
|
55
|
+
}
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
function SelectRoot({
|
|
59
|
+
id,
|
|
60
|
+
value,
|
|
61
|
+
defaultValue,
|
|
62
|
+
onValueChange,
|
|
63
|
+
open,
|
|
64
|
+
defaultOpen,
|
|
65
|
+
onOpenChange,
|
|
66
|
+
dir,
|
|
67
|
+
name,
|
|
68
|
+
autoComplete,
|
|
69
|
+
disabled,
|
|
70
|
+
isDisabled,
|
|
71
|
+
required,
|
|
72
|
+
form,
|
|
73
|
+
allowsEmptyCollection,
|
|
74
|
+
"aria-label": ariaLabel,
|
|
75
|
+
"aria-labelledby": ariaLabelledby,
|
|
76
|
+
children
|
|
77
|
+
}) {
|
|
78
|
+
void dir;
|
|
79
|
+
return /* @__PURE__ */ jsx(
|
|
80
|
+
AriaSelect,
|
|
81
|
+
{
|
|
82
|
+
"data-slot": "select",
|
|
83
|
+
className: "ui-select-root",
|
|
84
|
+
id,
|
|
85
|
+
value: toKey(value),
|
|
86
|
+
defaultValue: toKey(defaultValue) ?? void 0,
|
|
87
|
+
onChange: (key) => {
|
|
88
|
+
if (key != null) onValueChange?.(String(key));
|
|
89
|
+
},
|
|
90
|
+
isOpen: open,
|
|
91
|
+
defaultOpen,
|
|
92
|
+
onOpenChange,
|
|
93
|
+
isDisabled: disabled || isDisabled,
|
|
94
|
+
isRequired: required,
|
|
95
|
+
name,
|
|
96
|
+
form,
|
|
97
|
+
autoComplete,
|
|
98
|
+
allowsEmptyCollection,
|
|
99
|
+
"aria-label": ariaLabel,
|
|
100
|
+
"aria-labelledby": ariaLabelledby,
|
|
101
|
+
children
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
23
105
|
function Select(props) {
|
|
24
106
|
if (isDataSelect(props)) {
|
|
107
|
+
if (props.labelInValue) return /* @__PURE__ */ jsx(LabelInValueSelect, { ...props });
|
|
25
108
|
return /* @__PURE__ */ jsx(DataSelect, { ...props });
|
|
26
109
|
}
|
|
27
110
|
return /* @__PURE__ */ jsx(CompoundSelect, { ...props });
|
|
28
111
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
112
|
+
function LabelInValueSelect({
|
|
113
|
+
labelInValue,
|
|
114
|
+
value,
|
|
115
|
+
defaultValue,
|
|
116
|
+
onValueChange,
|
|
117
|
+
onSelect,
|
|
118
|
+
...rest
|
|
119
|
+
}) {
|
|
120
|
+
void labelInValue;
|
|
121
|
+
const multiple = rest.mode === "multiple" || rest.mode === "tags";
|
|
122
|
+
const onDeselect = rest.onDeselect;
|
|
123
|
+
const entries = React.useMemo(() => {
|
|
124
|
+
const current = value ?? defaultValue;
|
|
125
|
+
if (current == null) return [];
|
|
126
|
+
return Array.isArray(current) ? current : [current];
|
|
127
|
+
}, [value, defaultValue]);
|
|
128
|
+
const options = React.useMemo(() => {
|
|
129
|
+
const base = normalizeSelectOptions(rest.options, rest.fieldNames);
|
|
130
|
+
const known = new Set(base.map((option) => option.value));
|
|
131
|
+
const carried = entries.filter((entry) => entry && !known.has(entry.value)).map((entry) => ({ value: entry.value, label: itemTextValue(entry.label) || entry.value }));
|
|
132
|
+
return carried.length ? [...base, ...carried] : base;
|
|
133
|
+
}, [rest.options, rest.fieldNames, entries]);
|
|
134
|
+
const toLabeled = (picked, option) => ({
|
|
135
|
+
value: picked,
|
|
136
|
+
// The OPTION's label wins when the row is known; the label that rode in on the value is the
|
|
137
|
+
// fallback for the row that has not loaded.
|
|
138
|
+
label: option?.label ?? entries.find((entry) => entry.value === picked)?.label ?? picked
|
|
38
139
|
});
|
|
140
|
+
const shared = {
|
|
141
|
+
...rest,
|
|
142
|
+
options,
|
|
143
|
+
fieldNames: void 0,
|
|
144
|
+
onSelect: onSelect ? (picked, option) => onSelect(
|
|
145
|
+
toLabeled(picked, option),
|
|
146
|
+
option
|
|
147
|
+
) : void 0
|
|
148
|
+
};
|
|
149
|
+
if (multiple) {
|
|
150
|
+
const labeledValues = value;
|
|
151
|
+
const labeledDefaults = defaultValue;
|
|
152
|
+
const adapted2 = {
|
|
153
|
+
...shared,
|
|
154
|
+
value: labeledValues?.map((entry) => entry.value),
|
|
155
|
+
defaultValue: labeledDefaults?.map((entry) => entry.value),
|
|
156
|
+
onValueChange: (picked, pickedOptions) => onValueChange?.(
|
|
157
|
+
picked.map(
|
|
158
|
+
(entry) => toLabeled(
|
|
159
|
+
entry,
|
|
160
|
+
pickedOptions?.find((option) => option.value === entry)
|
|
161
|
+
)
|
|
162
|
+
),
|
|
163
|
+
pickedOptions
|
|
164
|
+
),
|
|
165
|
+
onDeselect: onDeselect ? (picked, option) => onDeselect(toLabeled(picked, option), option) : void 0
|
|
166
|
+
};
|
|
167
|
+
return /* @__PURE__ */ jsx(DataSelect, { ...adapted2 });
|
|
168
|
+
}
|
|
169
|
+
const labeledValue = value;
|
|
170
|
+
const labeledDefault = defaultValue;
|
|
171
|
+
const adapted = {
|
|
172
|
+
...shared,
|
|
173
|
+
value: value === void 0 ? void 0 : labeledValue?.value ?? "",
|
|
174
|
+
defaultValue: labeledDefault?.value,
|
|
175
|
+
onValueChange: (picked, option) => onValueChange?.(picked ? toLabeled(picked, option) : void 0, option)
|
|
176
|
+
};
|
|
177
|
+
return /* @__PURE__ */ jsx(DataSelect, { ...adapted });
|
|
178
|
+
}
|
|
179
|
+
function CompoundSelect({ id, name, ...props }) {
|
|
180
|
+
const fieldA11y = pickFieldA11y(props);
|
|
181
|
+
const identity = useFieldIdentity({ id, name, "data-field": fieldA11y["data-field"] });
|
|
39
182
|
return /* @__PURE__ */ jsx(
|
|
40
183
|
SelectFieldA11yContext.Provider,
|
|
41
184
|
{
|
|
42
185
|
value: {
|
|
43
186
|
...fieldA11y,
|
|
44
187
|
"data-field": identity["data-field"] ?? fieldA11y["data-field"],
|
|
45
|
-
id
|
|
46
|
-
value
|
|
188
|
+
id
|
|
47
189
|
},
|
|
48
190
|
children: /* @__PURE__ */ jsx(
|
|
49
|
-
|
|
191
|
+
SelectRoot,
|
|
50
192
|
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
name:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
props.onValueChange?.(next);
|
|
57
|
-
}
|
|
193
|
+
...props,
|
|
194
|
+
id,
|
|
195
|
+
name: name ?? identity.name,
|
|
196
|
+
"aria-label": fieldA11y["aria-label"],
|
|
197
|
+
"aria-labelledby": fieldA11y["aria-labelledby"]
|
|
58
198
|
}
|
|
59
199
|
)
|
|
60
200
|
}
|
|
61
201
|
);
|
|
62
202
|
}
|
|
63
|
-
function SelectGroup(props) {
|
|
64
|
-
return /* @__PURE__ */ jsx(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
203
|
+
function SelectGroup({ className, children, ...props }) {
|
|
204
|
+
return /* @__PURE__ */ jsx(
|
|
205
|
+
ListBoxSection,
|
|
206
|
+
{
|
|
207
|
+
"data-slot": "select-group",
|
|
208
|
+
className,
|
|
209
|
+
...splitDomProps(props).attributes,
|
|
210
|
+
children
|
|
211
|
+
}
|
|
212
|
+
);
|
|
68
213
|
}
|
|
214
|
+
const SelectValue = React.forwardRef(function SelectValue2({ placeholder, children, asChild, className, style, ...props }, ref) {
|
|
215
|
+
void asChild;
|
|
216
|
+
return /* @__PURE__ */ jsx(
|
|
217
|
+
AriaSelectValue,
|
|
218
|
+
{
|
|
219
|
+
ref,
|
|
220
|
+
"data-slot": "select-value",
|
|
221
|
+
className: className ?? "",
|
|
222
|
+
style,
|
|
223
|
+
...props,
|
|
224
|
+
children: ({ isPlaceholder, defaultChildren }) => isPlaceholder ? placeholder ?? null : children ?? defaultChildren
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
});
|
|
69
228
|
const SelectTrigger = React.forwardRef(
|
|
70
229
|
({
|
|
71
230
|
className,
|
|
@@ -75,25 +234,28 @@ const SelectTrigger = React.forwardRef(
|
|
|
75
234
|
status,
|
|
76
235
|
width = "full",
|
|
77
236
|
showIndicator = true,
|
|
237
|
+
disabled,
|
|
238
|
+
asChild,
|
|
239
|
+
style,
|
|
78
240
|
...props
|
|
79
241
|
}, ref) => {
|
|
242
|
+
void asChild;
|
|
80
243
|
const field = React.useContext(SelectFieldA11yContext);
|
|
244
|
+
const state = React.useContext(SelectStateContext);
|
|
245
|
+
const ariaTrigger = React.useContext(ButtonContext);
|
|
81
246
|
const ownsName = props["aria-label"] !== void 0 || props["aria-labelledby"] !== void 0;
|
|
82
247
|
const fieldOwnsName = field?.["aria-label"] !== void 0 || field?.["aria-labelledby"] !== void 0;
|
|
83
248
|
const nameFallback = useFieldNameFallback({
|
|
84
249
|
"aria-label": ownsName ? props["aria-label"] : field?.["aria-label"],
|
|
85
250
|
"aria-labelledby": ownsName ? props["aria-labelledby"] : field?.["aria-labelledby"]
|
|
86
251
|
});
|
|
87
|
-
const
|
|
88
|
-
|
|
252
|
+
const hasField = Boolean(field) || nameFallback["aria-labelledby"] !== void 0;
|
|
253
|
+
const fieldA11y = hasField ? {
|
|
89
254
|
...ownsName ? {} : fieldOwnsName ? {
|
|
90
255
|
"aria-label": field?.["aria-label"],
|
|
91
256
|
"aria-labelledby": field?.["aria-labelledby"]
|
|
92
257
|
} : nameFallback,
|
|
93
|
-
"aria-describedby": mergeAriaIds(
|
|
94
|
-
props["aria-describedby"],
|
|
95
|
-
field?.["aria-describedby"]
|
|
96
|
-
),
|
|
258
|
+
"aria-describedby": mergeAriaIds(props["aria-describedby"], field?.["aria-describedby"]),
|
|
97
259
|
"aria-errormessage": mergeAriaIds(
|
|
98
260
|
props["aria-errormessage"],
|
|
99
261
|
field?.["aria-errormessage"]
|
|
@@ -105,147 +267,277 @@ const SelectTrigger = React.forwardRef(
|
|
|
105
267
|
),
|
|
106
268
|
"data-field": props["data-field"] ?? field?.["data-field"]
|
|
107
269
|
} : { "aria-invalid": resolveAriaInvalid(props["aria-invalid"], status) };
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
270
|
+
const id = props.id ?? (hasField ? field?.id : void 0);
|
|
271
|
+
const isOpen = state?.isOpen ?? false;
|
|
272
|
+
const buttonRef = React.useRef(null);
|
|
273
|
+
const composedRef = React.useCallback(
|
|
274
|
+
(node) => {
|
|
275
|
+
buttonRef.current = node;
|
|
276
|
+
if (typeof ref === "function") ref(node);
|
|
277
|
+
else if (ref) ref.current = node;
|
|
278
|
+
},
|
|
279
|
+
[ref]
|
|
280
|
+
);
|
|
281
|
+
const wasOpen = React.useRef(false);
|
|
282
|
+
React.useEffect(() => {
|
|
283
|
+
if (!wasOpen.current || isOpen) {
|
|
284
|
+
wasOpen.current = isOpen;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
wasOpen.current = isOpen;
|
|
288
|
+
const button = buttonRef.current;
|
|
289
|
+
if (!button) return;
|
|
290
|
+
const restore = button.ownerDocument.defaultView?.setTimeout(() => {
|
|
291
|
+
const owner = button.ownerDocument;
|
|
292
|
+
if (!button.isConnected) return;
|
|
293
|
+
if (owner.activeElement === null || owner.activeElement === owner.body) button.focus();
|
|
294
|
+
}, 0);
|
|
295
|
+
return () => {
|
|
296
|
+
if (restore !== void 0) button.ownerDocument.defaultView?.clearTimeout(restore);
|
|
297
|
+
};
|
|
298
|
+
}, [isOpen]);
|
|
299
|
+
const selected = state ? state.value : null;
|
|
300
|
+
const hasValue = selected != null && selected !== "";
|
|
301
|
+
const dataValue = (props["data-value"] ?? (hasValue ? String(selected) : void 0)) || void 0;
|
|
302
|
+
const { events, attributes } = splitDomProps(props);
|
|
303
|
+
delete attributes.id;
|
|
304
|
+
const triggerContext = React.useMemo(() => {
|
|
305
|
+
if (!ariaTrigger || "slots" in ariaTrigger) return ariaTrigger;
|
|
306
|
+
const next = { ...ariaTrigger };
|
|
307
|
+
delete next["aria-labelledby"];
|
|
308
|
+
return next;
|
|
309
|
+
}, [ariaTrigger]);
|
|
310
|
+
return /* @__PURE__ */ jsx(ButtonContext.Provider, { value: triggerContext, children: /* @__PURE__ */ jsxs(
|
|
311
|
+
AriaButton,
|
|
111
312
|
{
|
|
112
|
-
ref,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
313
|
+
ref: composedRef,
|
|
314
|
+
id,
|
|
315
|
+
onPointerDown: (event) => {
|
|
316
|
+
event.currentTarget.focus();
|
|
317
|
+
},
|
|
318
|
+
...events,
|
|
319
|
+
isDisabled: disabled || void 0,
|
|
320
|
+
style,
|
|
118
321
|
className: cn(
|
|
119
322
|
controlSurfaceTriggerClass,
|
|
120
323
|
// `bounded` deliberately emits NO width utility: its width is owned by the
|
|
121
324
|
// `[data-width="bounded"]` rule in control.css. A utility here would win the layer order
|
|
122
325
|
// and make that rule — and therefore the token — dead, the way `w-full` did to
|
|
123
|
-
// `.ui-app-setting-picker-icon` (gh#366, gh#371).
|
|
326
|
+
// `.ui-app-setting-picker-icon`'s `inline-size` (gh#366, gh#371).
|
|
124
327
|
width === "auto" && "w-auto",
|
|
125
328
|
width === "full" && "w-full",
|
|
126
329
|
"aria-invalid:border-destructive data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground whitespace-nowrap transition-[color,box-shadow] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center",
|
|
127
330
|
className
|
|
128
331
|
),
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
332
|
+
render: (domProps) => /* @__PURE__ */ jsx(
|
|
333
|
+
"button",
|
|
334
|
+
{
|
|
335
|
+
...domProps,
|
|
336
|
+
...attributes,
|
|
337
|
+
...fieldA11y,
|
|
338
|
+
role: "combobox",
|
|
339
|
+
"aria-autocomplete": "none",
|
|
340
|
+
"data-slot": "select-trigger",
|
|
341
|
+
"data-size": size,
|
|
342
|
+
"data-variant": controlSurfaceAttrs({ variant })["data-variant"],
|
|
343
|
+
"data-status": status,
|
|
344
|
+
"data-width": width,
|
|
345
|
+
"data-state": isOpen ? "open" : "closed",
|
|
346
|
+
"data-placeholder": hasValue ? void 0 : "",
|
|
347
|
+
"data-value": dataValue
|
|
348
|
+
}
|
|
349
|
+
),
|
|
132
350
|
children: [
|
|
133
351
|
children,
|
|
134
|
-
showIndicator ? /* @__PURE__ */ jsx(
|
|
352
|
+
showIndicator ? /* @__PURE__ */ jsx(
|
|
135
353
|
ChevronDown,
|
|
136
354
|
{
|
|
137
355
|
"data-slot": "select-chevron",
|
|
138
356
|
className: "ui-select-chevron",
|
|
139
357
|
"aria-hidden": "true"
|
|
140
358
|
}
|
|
141
|
-
)
|
|
359
|
+
) : null
|
|
142
360
|
]
|
|
143
361
|
}
|
|
144
|
-
);
|
|
362
|
+
) });
|
|
145
363
|
}
|
|
146
364
|
);
|
|
147
|
-
SelectTrigger.displayName =
|
|
148
|
-
const SelectScrollUpButton = React.forwardRef(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
ref
|
|
152
|
-
|
|
153
|
-
className: cn("ui-select-scroll-button", className),
|
|
154
|
-
...props,
|
|
155
|
-
children: /* @__PURE__ */ jsx(ChevronUp, { className: "ui-select-scroll-icon", "aria-hidden": "true" })
|
|
365
|
+
SelectTrigger.displayName = "SelectTrigger";
|
|
366
|
+
const SelectScrollUpButton = React.forwardRef(
|
|
367
|
+
function SelectScrollUpButton2(props, ref) {
|
|
368
|
+
void props;
|
|
369
|
+
void ref;
|
|
370
|
+
return null;
|
|
156
371
|
}
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
"data-slot": "select-scroll-down-button",
|
|
164
|
-
className: cn("ui-select-scroll-button", className),
|
|
165
|
-
...props,
|
|
166
|
-
children: /* @__PURE__ */ jsx(ChevronDown, { className: "ui-select-scroll-icon", "aria-hidden": "true" })
|
|
372
|
+
);
|
|
373
|
+
const SelectScrollDownButton = React.forwardRef(
|
|
374
|
+
function SelectScrollDownButton2(props, ref) {
|
|
375
|
+
void props;
|
|
376
|
+
void ref;
|
|
377
|
+
return null;
|
|
167
378
|
}
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
379
|
+
);
|
|
380
|
+
const SELECT_PLACEMENT = {
|
|
381
|
+
bottomStart: { side: "bottom", align: "start" },
|
|
382
|
+
bottomEnd: { side: "bottom", align: "end" },
|
|
383
|
+
topStart: { side: "top", align: "start" },
|
|
384
|
+
topEnd: { side: "top", align: "end" }
|
|
385
|
+
};
|
|
386
|
+
const SelectPopup = React.forwardRef(function SelectPopup2({
|
|
387
|
+
className,
|
|
388
|
+
children,
|
|
389
|
+
style,
|
|
390
|
+
side,
|
|
391
|
+
sideOffset = 4,
|
|
392
|
+
align = "start",
|
|
393
|
+
alignOffset,
|
|
394
|
+
avoidCollisions,
|
|
395
|
+
collisionPadding,
|
|
396
|
+
position,
|
|
397
|
+
sticky,
|
|
398
|
+
hideWhenDetached,
|
|
399
|
+
onCloseAutoFocus,
|
|
400
|
+
onEscapeKeyDown,
|
|
401
|
+
onPointerDownOutside,
|
|
402
|
+
forceMount,
|
|
403
|
+
renderEmpty,
|
|
404
|
+
placement,
|
|
405
|
+
popupRender,
|
|
406
|
+
listHeight,
|
|
407
|
+
onPopupScroll,
|
|
408
|
+
"data-popup-match": popupMatch,
|
|
409
|
+
...props
|
|
410
|
+
}, ref) {
|
|
411
|
+
void position;
|
|
412
|
+
void sticky;
|
|
413
|
+
void hideWhenDetached;
|
|
414
|
+
void onCloseAutoFocus;
|
|
415
|
+
void onEscapeKeyDown;
|
|
416
|
+
void onPointerDownOutside;
|
|
417
|
+
void forceMount;
|
|
418
|
+
const portalContainer = useOverlayPortalContainer();
|
|
419
|
+
const { events, attributes } = splitDomProps(props);
|
|
420
|
+
const anchor = placement ? SELECT_PLACEMENT[placement] : void 0;
|
|
421
|
+
const list = /* @__PURE__ */ jsx(
|
|
422
|
+
ListBox,
|
|
174
423
|
{
|
|
175
|
-
|
|
176
|
-
|
|
424
|
+
"data-slot": "select-viewport",
|
|
425
|
+
className: "ui-select-viewport",
|
|
426
|
+
...events,
|
|
427
|
+
onScroll: onPopupScroll,
|
|
428
|
+
renderEmptyState: renderEmpty === void 0 ? void 0 : () => /* @__PURE__ */ jsx("div", { "data-slot": "select-empty", className: "ui-select-empty", children: renderEmpty }),
|
|
429
|
+
children
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
return /* @__PURE__ */ jsx(
|
|
433
|
+
AriaPopover,
|
|
434
|
+
{
|
|
435
|
+
ref,
|
|
436
|
+
UNSTABLE_portalContainer: portalContainer,
|
|
437
|
+
placement: toPlacement(side ?? anchor?.side, align ?? anchor?.align),
|
|
438
|
+
offset: sideOffset,
|
|
439
|
+
crossOffset: alignOffset,
|
|
440
|
+
shouldFlip: avoidCollisions,
|
|
441
|
+
containerPadding: collisionPadding,
|
|
442
|
+
style: listHeight === void 0 ? style : { ...style, "--select-content-max-height": `${listHeight}px` },
|
|
177
443
|
className: cn(
|
|
178
444
|
"ui-select-content data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
179
|
-
position === "popper" && "translate-y-1",
|
|
180
445
|
className
|
|
181
446
|
),
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
children: [
|
|
185
|
-
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
447
|
+
render: (popoverProps, popoverState) => (
|
|
448
|
+
// `role={undefined}`: a listbox is not a dialog — see the file note (3).
|
|
186
449
|
/* @__PURE__ */ jsx(
|
|
187
|
-
|
|
450
|
+
"div",
|
|
188
451
|
{
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// width of their own — which is exactly what antd's `popupMatchSelectWidth` is for.
|
|
196
|
-
position === "popper" && !props["data-popup-match"] && "min-w-[var(--radix-select-trigger-width)]"
|
|
197
|
-
),
|
|
198
|
-
children
|
|
452
|
+
...popoverProps,
|
|
453
|
+
...attributes,
|
|
454
|
+
role: void 0,
|
|
455
|
+
...radixSurfaceState(popoverState),
|
|
456
|
+
"data-slot": "select-content",
|
|
457
|
+
"data-popup-match": popupMatch
|
|
199
458
|
}
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
|
|
459
|
+
)
|
|
460
|
+
),
|
|
461
|
+
children: popupRender ? popupRender(list) : list
|
|
203
462
|
}
|
|
204
|
-
)
|
|
463
|
+
);
|
|
205
464
|
});
|
|
206
|
-
SelectContent
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
{
|
|
210
|
-
ref,
|
|
211
|
-
"data-slot": "select-label",
|
|
212
|
-
className: cn("ui-select-label", className),
|
|
213
|
-
...props
|
|
465
|
+
const SelectContent = React.forwardRef(
|
|
466
|
+
function SelectContent2(props, ref) {
|
|
467
|
+
return /* @__PURE__ */ jsx(SelectPopup, { ref, ...props });
|
|
214
468
|
}
|
|
215
|
-
)
|
|
216
|
-
SelectLabel
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
"span",
|
|
228
|
-
{
|
|
229
|
-
"data-slot": "select-item-selected-icon",
|
|
230
|
-
className: "ui-search-select-selected-icon",
|
|
231
|
-
"aria-hidden": "true",
|
|
232
|
-
children: selectedIcon
|
|
233
|
-
}
|
|
234
|
-
) }) : null
|
|
235
|
-
]
|
|
469
|
+
);
|
|
470
|
+
const SelectLabel = React.forwardRef(
|
|
471
|
+
function SelectLabel2({ className, ...props }, ref) {
|
|
472
|
+
return /* @__PURE__ */ jsx(
|
|
473
|
+
AriaHeader,
|
|
474
|
+
{
|
|
475
|
+
ref,
|
|
476
|
+
"data-slot": "select-label",
|
|
477
|
+
className: cn("ui-select-label", className),
|
|
478
|
+
...props
|
|
479
|
+
}
|
|
480
|
+
);
|
|
236
481
|
}
|
|
237
|
-
)
|
|
238
|
-
SelectItem
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
482
|
+
);
|
|
483
|
+
const SelectItem = React.forwardRef(function SelectItem2({ className, children, selectedIcon, value, disabled, textValue, asChild, ...props }, ref) {
|
|
484
|
+
void asChild;
|
|
485
|
+
const { events, attributes } = splitDomProps(props);
|
|
486
|
+
return /* @__PURE__ */ jsx(
|
|
487
|
+
ListBoxItem,
|
|
488
|
+
{
|
|
489
|
+
ref,
|
|
490
|
+
id: value,
|
|
491
|
+
textValue: textValue ?? (itemTextValue(children) || value),
|
|
492
|
+
isDisabled: disabled,
|
|
493
|
+
...events,
|
|
494
|
+
className: cn(
|
|
495
|
+
"ui-select-item [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
496
|
+
className
|
|
497
|
+
),
|
|
498
|
+
render: (itemProps, itemState) => (
|
|
499
|
+
// The Radix `data-*` vocabulary control.css reads (`[data-state="checked"]`,
|
|
500
|
+
// `[data-highlighted]`), translated from react-aria's state.
|
|
501
|
+
/* @__PURE__ */ jsx(
|
|
502
|
+
"div",
|
|
503
|
+
{
|
|
504
|
+
...itemProps,
|
|
505
|
+
...attributes,
|
|
506
|
+
"data-slot": "select-item",
|
|
507
|
+
"data-state": itemState.isSelected ? "checked" : "unchecked",
|
|
508
|
+
"data-highlighted": itemState.isFocused ? "" : void 0,
|
|
509
|
+
"data-disabled": itemState.isDisabled ? "" : void 0
|
|
510
|
+
}
|
|
511
|
+
)
|
|
512
|
+
),
|
|
513
|
+
children: ({ isSelected }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
514
|
+
children,
|
|
515
|
+
selectedIcon && isSelected ? /* @__PURE__ */ jsx(
|
|
516
|
+
"span",
|
|
517
|
+
{
|
|
518
|
+
"data-slot": "select-item-selected-icon",
|
|
519
|
+
className: "ui-search-select-selected-icon",
|
|
520
|
+
"aria-hidden": "true",
|
|
521
|
+
children: selectedIcon
|
|
522
|
+
}
|
|
523
|
+
) : null
|
|
524
|
+
] })
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
});
|
|
528
|
+
const SelectSeparator = React.forwardRef(
|
|
529
|
+
function SelectSeparator2({ className, ...props }, ref) {
|
|
530
|
+
return /* @__PURE__ */ jsx(
|
|
531
|
+
AriaSeparator,
|
|
532
|
+
{
|
|
533
|
+
ref,
|
|
534
|
+
"data-slot": "select-separator",
|
|
535
|
+
className: cn("ui-select-separator", className),
|
|
536
|
+
...splitDomProps(props).attributes
|
|
537
|
+
}
|
|
538
|
+
);
|
|
246
539
|
}
|
|
247
|
-
)
|
|
248
|
-
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
540
|
+
);
|
|
249
541
|
function groupDataOptions(options) {
|
|
250
542
|
const order = [];
|
|
251
543
|
const buckets = /* @__PURE__ */ new Map();
|
|
@@ -259,11 +551,19 @@ function groupDataOptions(options) {
|
|
|
259
551
|
}
|
|
260
552
|
return order.map((key) => ({ heading: key || void 0, items: buckets.get(key) ?? [] }));
|
|
261
553
|
}
|
|
554
|
+
function DataSelectLabel({
|
|
555
|
+
labelRender,
|
|
556
|
+
options
|
|
557
|
+
}) {
|
|
558
|
+
const state = React.useContext(SelectStateContext);
|
|
559
|
+
const selected = state ? state.value : null;
|
|
560
|
+
if (selected == null || selected === "") return null;
|
|
561
|
+
const value = String(selected);
|
|
562
|
+
const option = options.find((entry) => entry.value === value);
|
|
563
|
+
return /* @__PURE__ */ jsx(Fragment, { children: labelRender({ value, label: option?.label ?? value, option }) });
|
|
564
|
+
}
|
|
262
565
|
function DataSelect(props) {
|
|
263
566
|
const { t } = useTranslation();
|
|
264
|
-
const [uncontrolledValue, setUncontrolledValue] = React.useState(
|
|
265
|
-
typeof props.defaultValue === "string" ? props.defaultValue : void 0
|
|
266
|
-
);
|
|
267
567
|
const identity = useFieldIdentity({
|
|
268
568
|
id: props.id,
|
|
269
569
|
name: props.name,
|
|
@@ -271,15 +571,33 @@ function DataSelect(props) {
|
|
|
271
571
|
});
|
|
272
572
|
const resolvedName = props.name ?? identity.name;
|
|
273
573
|
const resolvedField = props["data-field"] ?? identity["data-field"];
|
|
274
|
-
const options =
|
|
574
|
+
const options = React.useMemo(
|
|
575
|
+
() => normalizeSelectOptions(props.options, props.fieldNames),
|
|
576
|
+
[props.options, props.fieldNames]
|
|
577
|
+
);
|
|
275
578
|
const hasOptions = options.length > 0;
|
|
276
|
-
const
|
|
277
|
-
|
|
579
|
+
const showSearchConfig = typeof props.showSearch === "object" && props.showSearch !== null ? props.showSearch : void 0;
|
|
580
|
+
const showSearch = showSearchConfig ? true : props.showSearch;
|
|
581
|
+
const searchable = showSearch ?? (Boolean(props.loadOptions) || props.mode !== void 0);
|
|
582
|
+
if (props.mode !== void 0 || searchable) {
|
|
583
|
+
const antdFilter = showSearchConfig?.filterOption;
|
|
584
|
+
const filterOption = antdFilter === void 0 ? props.filterOption : antdFilter === false ? () => true : antdFilter === true ? void 0 : (option, query) => antdFilter(query, option);
|
|
585
|
+
const onSearch = showSearchConfig?.onSearch;
|
|
278
586
|
return /* @__PURE__ */ jsx(
|
|
279
587
|
SearchSelect,
|
|
280
588
|
{
|
|
281
589
|
...props,
|
|
282
590
|
options,
|
|
591
|
+
fieldNames: void 0,
|
|
592
|
+
filterOption,
|
|
593
|
+
filterSort: showSearchConfig?.filterSort ?? props.filterSort,
|
|
594
|
+
optionFilterProp: showSearchConfig?.optionFilterProp ?? props.optionFilterProp,
|
|
595
|
+
search: showSearchConfig?.searchValue ?? props.search,
|
|
596
|
+
onSearchChange: onSearch || props.onSearchChange ? (query) => {
|
|
597
|
+
onSearch?.(query);
|
|
598
|
+
props.onSearchChange?.(query);
|
|
599
|
+
} : void 0,
|
|
600
|
+
autoClearSearchValue: showSearchConfig?.autoClearSearchValue ?? props.autoClearSearchValue,
|
|
283
601
|
disabled: props.disabled || !props.loadOptions && !hasOptions,
|
|
284
602
|
name: resolvedName,
|
|
285
603
|
"data-field": resolvedField
|
|
@@ -298,6 +616,7 @@ function DataSelect(props) {
|
|
|
298
616
|
size,
|
|
299
617
|
status,
|
|
300
618
|
variant,
|
|
619
|
+
width,
|
|
301
620
|
loading,
|
|
302
621
|
open,
|
|
303
622
|
defaultOpen,
|
|
@@ -309,12 +628,18 @@ function DataSelect(props) {
|
|
|
309
628
|
value,
|
|
310
629
|
defaultValue,
|
|
311
630
|
onValueChange,
|
|
631
|
+
labelRender,
|
|
632
|
+
prefix,
|
|
633
|
+
suffixIcon,
|
|
634
|
+
placement,
|
|
635
|
+
popupRender,
|
|
636
|
+
listHeight,
|
|
637
|
+
onPopupScroll,
|
|
312
638
|
id,
|
|
313
639
|
className,
|
|
314
640
|
"data-testid": dataTestId,
|
|
315
641
|
...rest
|
|
316
642
|
} = props;
|
|
317
|
-
const currentValue = value ?? uncontrolledValue;
|
|
318
643
|
const ariaProps = Object.fromEntries(
|
|
319
644
|
Object.entries(rest).filter(([key]) => key.startsWith("aria-"))
|
|
320
645
|
);
|
|
@@ -326,6 +651,7 @@ function DataSelect(props) {
|
|
|
326
651
|
SelectItem,
|
|
327
652
|
{
|
|
328
653
|
value: option.value,
|
|
654
|
+
textValue: option.label,
|
|
329
655
|
disabled: option.disabled,
|
|
330
656
|
"data-testid": optionTestId(option.value),
|
|
331
657
|
selectedIcon: menuItemSelectedIcon,
|
|
@@ -344,60 +670,68 @@ function DataSelect(props) {
|
|
|
344
670
|
const showClear = canClear && Boolean(value);
|
|
345
671
|
const showEmptyPopup = !hasOptions && notFoundContent !== void 0;
|
|
346
672
|
const select = /* @__PURE__ */ jsxs(
|
|
347
|
-
|
|
673
|
+
SelectRoot,
|
|
348
674
|
{
|
|
349
|
-
"data-slot": "select",
|
|
350
675
|
value: isControlled ? value : void 0,
|
|
351
676
|
defaultValue: isControlled ? void 0 : defaultValue || void 0,
|
|
352
677
|
onValueChange: (next) => {
|
|
353
|
-
setUncontrolledValue(next);
|
|
354
678
|
onValueChange?.(
|
|
355
679
|
next,
|
|
356
680
|
options.find((option) => option.value === next)
|
|
357
681
|
);
|
|
358
682
|
},
|
|
359
683
|
disabled: disabled || !hasOptions && !showEmptyPopup,
|
|
684
|
+
allowsEmptyCollection: showEmptyPopup,
|
|
685
|
+
"aria-label": ariaProps["aria-label"],
|
|
686
|
+
"aria-labelledby": ariaProps["aria-labelledby"],
|
|
360
687
|
name: resolvedName,
|
|
361
688
|
open,
|
|
362
689
|
defaultOpen,
|
|
363
690
|
onOpenChange,
|
|
364
691
|
children: [
|
|
365
|
-
/* @__PURE__ */
|
|
692
|
+
/* @__PURE__ */ jsxs(
|
|
366
693
|
SelectTrigger,
|
|
367
694
|
{
|
|
368
695
|
id,
|
|
369
696
|
"data-testid": dataTestId,
|
|
370
697
|
"data-field": resolvedField,
|
|
371
|
-
"data-value": currentValue || void 0,
|
|
372
698
|
size,
|
|
373
699
|
variant,
|
|
374
700
|
status,
|
|
701
|
+
width,
|
|
375
702
|
"aria-busy": loading || void 0,
|
|
376
703
|
className: cn(
|
|
704
|
+
prefix === void 0 || prefix === null ? void 0 : "ui-select-trigger-prefixed",
|
|
377
705
|
(showClear || loading) && "ui-control-trigger-affixed",
|
|
378
706
|
canClear || loading ? void 0 : className
|
|
379
707
|
),
|
|
380
|
-
showIndicator: !showClear && !loading,
|
|
708
|
+
showIndicator: suffixIcon === void 0 && !showClear && !loading,
|
|
381
709
|
...ariaProps,
|
|
382
|
-
children:
|
|
710
|
+
children: [
|
|
711
|
+
prefix === void 0 || prefix === null ? null : /* @__PURE__ */ jsx("span", { "data-slot": "select-prefix", className: "ui-select-prefix", children: prefix }),
|
|
712
|
+
/* @__PURE__ */ jsx(SelectValue, { placeholder, children: labelRender ? /* @__PURE__ */ jsx(DataSelectLabel, { labelRender, options }) : void 0 }),
|
|
713
|
+
suffixIcon === void 0 || suffixIcon === null || showClear || loading ? null : /* @__PURE__ */ jsx("span", { "data-slot": "select-suffix", className: "ui-select-suffix", "aria-hidden": "true", children: suffixIcon })
|
|
714
|
+
]
|
|
383
715
|
}
|
|
384
716
|
),
|
|
385
|
-
/* @__PURE__ */
|
|
386
|
-
|
|
717
|
+
/* @__PURE__ */ jsx(
|
|
718
|
+
SelectPopup,
|
|
387
719
|
{
|
|
720
|
+
renderEmpty: showEmptyPopup ? notFoundContent : void 0,
|
|
721
|
+
placement,
|
|
722
|
+
popupRender,
|
|
723
|
+
listHeight,
|
|
724
|
+
onPopupScroll,
|
|
388
725
|
"data-popup-match": popupMatchSelectWidth === void 0 || popupMatchSelectWidth === true ? void 0 : popupMatchSelectWidth === false ? "content" : "fixed",
|
|
389
726
|
style: typeof popupMatchSelectWidth === "number" ? {
|
|
390
727
|
"--select-content-inline-size": `${popupMatchSelectWidth}px`
|
|
391
728
|
} : void 0,
|
|
392
|
-
children:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
] }, group.heading) : /* @__PURE__ */ jsx(React.Fragment, { children: group.items.map(renderItem) }, "__ungrouped")
|
|
399
|
-
)
|
|
400
|
-
]
|
|
729
|
+
children: groupDataOptions(options).map(
|
|
730
|
+
(group) => group.heading ? /* @__PURE__ */ jsxs(SelectGroup, { children: [
|
|
731
|
+
/* @__PURE__ */ jsx(SelectLabel, { children: group.heading }),
|
|
732
|
+
group.items.map(renderItem)
|
|
733
|
+
] }, group.heading) : /* @__PURE__ */ jsx(React.Fragment, { children: group.items.map(renderItem) }, "__ungrouped")
|
|
734
|
+
)
|
|
401
735
|
}
|
|
402
736
|
)
|
|
403
737
|
]
|