@capra/core 1.12.0 → 1.13.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/dist/index.cjs +468 -39
- package/dist/index.d.cts +127 -5
- package/dist/index.d.mts +127 -5
- package/dist/index.mjs +472 -44
- package/dist/style.css +354 -18
- package/docs/core-autocompletefield--usage.md +1 -1
- package/docs/core-selectfield--design.md +66 -0
- package/docs/core-selectfield--usage.md +145 -0
- package/docs/history-changelogs-capra-core--docs.md +10 -0
- package/docs/index.md +2 -0
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -346,11 +346,50 @@ HelperText.displayName = "HelperText";
|
|
|
346
346
|
//#endregion
|
|
347
347
|
//#region src/components/input-helpers/fieldLayout.module.css
|
|
348
348
|
var fieldLayout_module_default = {
|
|
349
|
-
"field": "capra-fieldLayout-module-
|
|
350
|
-
"fieldContent": "capra-fieldLayout-module-
|
|
351
|
-
"labelRow": "capra-fieldLayout-module-
|
|
349
|
+
"field": "capra-fieldLayout-module-0mM4jW-field",
|
|
350
|
+
"fieldContent": "capra-fieldLayout-module-0mM4jW-fieldContent",
|
|
351
|
+
"labelRow": "capra-fieldLayout-module-0mM4jW-labelRow"
|
|
352
352
|
};
|
|
353
353
|
//#endregion
|
|
354
|
+
//#region src/components/input-helpers/useAnchorWidth.ts
|
|
355
|
+
/**
|
|
356
|
+
* Element that visually bounds the field (select trigger or text input shell). The popover matches
|
|
357
|
+
* its width and left edge, which differs from the field root in horizontal layouts where the label
|
|
358
|
+
* sits beside the control.
|
|
359
|
+
*/
|
|
360
|
+
function getShellElement(anchor) {
|
|
361
|
+
return anchor.querySelector("[data-capra-anchor-width-target]") ?? anchor.querySelector("[data-capra-text-input]") ?? anchor;
|
|
362
|
+
}
|
|
363
|
+
/** Element React Aria anchors the popover to: the select trigger or the combobox input. */
|
|
364
|
+
function getTriggerElement(anchor) {
|
|
365
|
+
return anchor.querySelector("[data-capra-anchor-width-target]") ?? anchor.querySelector("input") ?? anchor;
|
|
366
|
+
}
|
|
367
|
+
function useAnchorWidth(additionalDependencies = []) {
|
|
368
|
+
const anchorRef = react.useRef(null);
|
|
369
|
+
const [width, setWidth] = react.useState(null);
|
|
370
|
+
const [offset, setOffset] = react.useState(0);
|
|
371
|
+
react.useEffect(() => {
|
|
372
|
+
const anchor = anchorRef.current;
|
|
373
|
+
if (!anchor) return;
|
|
374
|
+
const measure = () => {
|
|
375
|
+
const shell = getShellElement(anchor);
|
|
376
|
+
const trigger = getTriggerElement(anchor);
|
|
377
|
+
setWidth(shell.offsetWidth + "px");
|
|
378
|
+
setOffset(shell.getBoundingClientRect().left - trigger.getBoundingClientRect().left);
|
|
379
|
+
};
|
|
380
|
+
const observer = new ResizeObserver(measure);
|
|
381
|
+
observer.observe(anchor);
|
|
382
|
+
const shell = getShellElement(anchor);
|
|
383
|
+
if (shell !== anchor) observer.observe(shell);
|
|
384
|
+
return () => observer.disconnect();
|
|
385
|
+
}, additionalDependencies);
|
|
386
|
+
return [
|
|
387
|
+
anchorRef,
|
|
388
|
+
width,
|
|
389
|
+
offset
|
|
390
|
+
];
|
|
391
|
+
}
|
|
392
|
+
//#endregion
|
|
354
393
|
//#region src/components/Autocomplete/AutocompleteField.module.css
|
|
355
394
|
var AutocompleteField_module_default = {
|
|
356
395
|
"item": "capra-AutocompleteField-module-MVvKYa-item",
|
|
@@ -409,41 +448,6 @@ function AutocompleteFieldWithoutRef(props, ref) {
|
|
|
409
448
|
style: { width: shouldAutoSizeDropdown ? width : void 0 }
|
|
410
449
|
}, /* @__PURE__ */ react.default.createElement(react_aria_components.ListBox, { className: AutocompleteField_module_default.listbox }, children)));
|
|
411
450
|
}
|
|
412
|
-
function useResizeObserver({ ref, onResize, additionalDependencies = [] }) {
|
|
413
|
-
react.default.useEffect(() => {
|
|
414
|
-
if (!ref.current) return;
|
|
415
|
-
const observer = new ResizeObserver((entries) => {
|
|
416
|
-
onResize(entries[0]);
|
|
417
|
-
});
|
|
418
|
-
observer.observe(ref.current);
|
|
419
|
-
return () => observer.disconnect();
|
|
420
|
-
}, [
|
|
421
|
-
ref,
|
|
422
|
-
onResize,
|
|
423
|
-
...additionalDependencies
|
|
424
|
-
]);
|
|
425
|
-
}
|
|
426
|
-
function useAnchorWidth(additionalDependencies = []) {
|
|
427
|
-
const anchorRef = react.default.useRef(null);
|
|
428
|
-
const [width, setWidth] = (0, react.useState)(null);
|
|
429
|
-
const [offset, setOffset] = (0, react.useState)(0);
|
|
430
|
-
useResizeObserver({
|
|
431
|
-
ref: anchorRef,
|
|
432
|
-
onResize: (0, react.useCallback)(() => {
|
|
433
|
-
if (anchorRef.current) {
|
|
434
|
-
setWidth(anchorRef.current.offsetWidth + "px");
|
|
435
|
-
const input = anchorRef.current.querySelector("input");
|
|
436
|
-
if (input) setOffset(anchorRef.current.offsetLeft - input.offsetLeft);
|
|
437
|
-
}
|
|
438
|
-
}, [anchorRef]),
|
|
439
|
-
additionalDependencies
|
|
440
|
-
});
|
|
441
|
-
return [
|
|
442
|
-
anchorRef,
|
|
443
|
-
width,
|
|
444
|
-
offset
|
|
445
|
-
];
|
|
446
|
-
}
|
|
447
451
|
/**
|
|
448
452
|
* AutocompleteField combines a text field with a suggestions list. Consumers can supply static `AutocompleteField.Item` children or an `items` collection with an optional default item renderer. The field allows custom values that are not in the list.
|
|
449
453
|
*/
|
|
@@ -834,7 +838,7 @@ function RadioTileWithoutRef({ children, checked, disabled, description, icon, F
|
|
|
834
838
|
const RadioTile = fixedForwardRef(RadioTileWithoutRef);
|
|
835
839
|
//#endregion
|
|
836
840
|
//#region src/components/Switch/Switch.module.css
|
|
837
|
-
var Switch_module_default = { "switch": "capra-Switch-module-
|
|
841
|
+
var Switch_module_default = { "switch": "capra-Switch-module-j8Yc-q-switch" };
|
|
838
842
|
//#endregion
|
|
839
843
|
//#region src/components/Switch/Switch.tsx
|
|
840
844
|
const Switch = react.forwardRef((props, ref) => {
|
|
@@ -2313,6 +2317,430 @@ const DatePickerFieldWithRef = react.forwardRef(DatePickerFieldInner);
|
|
|
2313
2317
|
DatePickerFieldWithRef.displayName = "DatePickerField";
|
|
2314
2318
|
const DatePickerField = DatePickerFieldWithRef;
|
|
2315
2319
|
//#endregion
|
|
2320
|
+
//#region src/components/SelectField/SelectField.module.css
|
|
2321
|
+
var SelectField_module_default = {
|
|
2322
|
+
"chevron": "capra-SelectField-module-1X4diq-chevron",
|
|
2323
|
+
"dropdownPanel": "capra-SelectField-module-1X4diq-dropdownPanel",
|
|
2324
|
+
"emptyState": "capra-SelectField-module-1X4diq-emptyState",
|
|
2325
|
+
"errorIndicator": "capra-SelectField-module-1X4diq-errorIndicator",
|
|
2326
|
+
"header": "capra-SelectField-module-1X4diq-header",
|
|
2327
|
+
"item": "capra-SelectField-module-1X4diq-item",
|
|
2328
|
+
"itemCheck": "capra-SelectField-module-1X4diq-itemCheck",
|
|
2329
|
+
"itemContent": "capra-SelectField-module-1X4diq-itemContent",
|
|
2330
|
+
"leadingSlot": "capra-SelectField-module-1X4diq-leadingSlot",
|
|
2331
|
+
"listbox": "capra-SelectField-module-1X4diq-listbox",
|
|
2332
|
+
"multipleOpenButton": "capra-SelectField-module-1X4diq-multipleOpenButton",
|
|
2333
|
+
"multipleTrigger": "capra-SelectField-module-1X4diq-multipleTrigger",
|
|
2334
|
+
"search": "capra-SelectField-module-1X4diq-search",
|
|
2335
|
+
"section": "capra-SelectField-module-1X4diq-section",
|
|
2336
|
+
"singleTrigger": "capra-SelectField-module-1X4diq-singleTrigger",
|
|
2337
|
+
"tag": "capra-SelectField-module-1X4diq-tag",
|
|
2338
|
+
"tagGroup": "capra-SelectField-module-1X4diq-tagGroup",
|
|
2339
|
+
"tagIcon": "capra-SelectField-module-1X4diq-tagIcon",
|
|
2340
|
+
"tagLabel": "capra-SelectField-module-1X4diq-tagLabel",
|
|
2341
|
+
"tagList": "capra-SelectField-module-1X4diq-tagList",
|
|
2342
|
+
"tagRemove": "capra-SelectField-module-1X4diq-tagRemove",
|
|
2343
|
+
"trailingSlot": "capra-SelectField-module-1X4diq-trailingSlot",
|
|
2344
|
+
"triggerShell": "capra-SelectField-module-1X4diq-triggerShell",
|
|
2345
|
+
"value": "capra-SelectField-module-1X4diq-value",
|
|
2346
|
+
"valueIcon": "capra-SelectField-module-1X4diq-valueIcon",
|
|
2347
|
+
"valueText": "capra-SelectField-module-1X4diq-valueText",
|
|
2348
|
+
"warningIndicator": "capra-SelectField-module-1X4diq-warningIndicator"
|
|
2349
|
+
};
|
|
2350
|
+
//#endregion
|
|
2351
|
+
//#region src/components/SelectField/SelectField.tsx
|
|
2352
|
+
/** When true, SelectField.Item indents by default (inside SelectField.Section that contains SelectField.Header). */
|
|
2353
|
+
const SelectFieldSectionIndentContext = react.createContext(false);
|
|
2354
|
+
function normalizeIterable(value) {
|
|
2355
|
+
return value === void 0 ? void 0 : Array.from(value);
|
|
2356
|
+
}
|
|
2357
|
+
function getItemLabelFromNode(node) {
|
|
2358
|
+
if (typeof node === "string") return node;
|
|
2359
|
+
if (typeof node === "number") return String(node);
|
|
2360
|
+
if (react.isValidElement(node)) {
|
|
2361
|
+
if (typeof node.props.textValue === "string") return node.props.textValue;
|
|
2362
|
+
return getItemLabelFromNode(node.props.children);
|
|
2363
|
+
}
|
|
2364
|
+
return "";
|
|
2365
|
+
}
|
|
2366
|
+
function removeKeysFromSelection(selection, keys) {
|
|
2367
|
+
return (selection ?? []).filter((selectedKey) => !keys.has(selectedKey));
|
|
2368
|
+
}
|
|
2369
|
+
function getItemIcon(item) {
|
|
2370
|
+
if (item && typeof item === "object" && "icon" in item) {
|
|
2371
|
+
const icon = item.icon;
|
|
2372
|
+
return icon && typeof icon === "object" && "__brand" in icon ? icon : void 0;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
function isDefaultSection(item) {
|
|
2376
|
+
const children = item.children;
|
|
2377
|
+
return children != null && typeof children !== "string" && typeof children[Symbol.iterator] === "function";
|
|
2378
|
+
}
|
|
2379
|
+
function SelectFieldIndicators(props) {
|
|
2380
|
+
const { appearance } = props;
|
|
2381
|
+
return /* @__PURE__ */ react.createElement(react.Fragment, null, appearance === "warning" ? /* @__PURE__ */ react.createElement("span", {
|
|
2382
|
+
className: SelectField_module_default.warningIndicator,
|
|
2383
|
+
"aria-hidden": true
|
|
2384
|
+
}, /* @__PURE__ */ react.createElement(_capra_icons.WarningOutlined, { size: "sm" })) : null, appearance === "danger" ? /* @__PURE__ */ react.createElement("span", {
|
|
2385
|
+
className: SelectField_module_default.errorIndicator,
|
|
2386
|
+
"aria-hidden": true
|
|
2387
|
+
}, /* @__PURE__ */ react.createElement(_capra_icons.Exclamation, { size: "sm" })) : null, /* @__PURE__ */ react.createElement("span", {
|
|
2388
|
+
className: SelectField_module_default.chevron,
|
|
2389
|
+
"aria-hidden": true
|
|
2390
|
+
}, /* @__PURE__ */ react.createElement(_capra_icons.ChevronDown, { size: "sm" })));
|
|
2391
|
+
}
|
|
2392
|
+
function SelectFieldTriggerButton(props) {
|
|
2393
|
+
const { appearance, buttonRef, children, className, ...rest } = props;
|
|
2394
|
+
const localRef = react.useRef(null);
|
|
2395
|
+
const ref = buttonRef ?? localRef;
|
|
2396
|
+
const [mergedProps, mergedRef] = (0, react_aria_components.useContextProps)({
|
|
2397
|
+
...rest,
|
|
2398
|
+
className
|
|
2399
|
+
}, ref, react_aria_components.ButtonContext);
|
|
2400
|
+
const { buttonProps, isPressed } = (0, react_aria.useButton)(mergedProps, mergedRef);
|
|
2401
|
+
const { focusProps, isFocused, isFocusVisible } = (0, react_aria.useFocusRing)(mergedProps);
|
|
2402
|
+
return /* @__PURE__ */ react.createElement("button", {
|
|
2403
|
+
...(0, react_aria.mergeProps)(buttonProps, focusProps),
|
|
2404
|
+
ref: mergedRef,
|
|
2405
|
+
className,
|
|
2406
|
+
"aria-invalid": appearance === "danger" ? true : void 0,
|
|
2407
|
+
"data-pressed": isPressed || void 0,
|
|
2408
|
+
"data-focused": isFocused || void 0,
|
|
2409
|
+
"data-focus-visible": isFocusVisible || void 0,
|
|
2410
|
+
"data-disabled": mergedProps.isDisabled || void 0
|
|
2411
|
+
}, children);
|
|
2412
|
+
}
|
|
2413
|
+
function SelectFieldTrigger(props) {
|
|
2414
|
+
const { appearance, disabled, leadingSlot, placeholder, required, selectedItemsLabel, size, triggerRef } = props;
|
|
2415
|
+
const state = react.useContext(react_aria_components.SelectStateContext);
|
|
2416
|
+
const openButtonRef = react.useRef(null);
|
|
2417
|
+
if (!state) return null;
|
|
2418
|
+
if (!(state.selectionManager.selectionMode === "multiple")) return /* @__PURE__ */ react.createElement(SelectFieldTriggerButton, {
|
|
2419
|
+
appearance,
|
|
2420
|
+
className: clsx(SelectField_module_default.triggerShell, SelectField_module_default.singleTrigger),
|
|
2421
|
+
"data-capra-anchor-width-target": "",
|
|
2422
|
+
"data-size": size,
|
|
2423
|
+
"data-disabled": disabled || void 0,
|
|
2424
|
+
"aria-required": required || void 0,
|
|
2425
|
+
isDisabled: disabled
|
|
2426
|
+
}, leadingSlot ? /* @__PURE__ */ react.createElement("span", { className: SelectField_module_default.leadingSlot }, leadingSlot) : null, /* @__PURE__ */ react.createElement(react_aria_components.SelectValue, { className: SelectField_module_default.value }, ({ isPlaceholder, selectedText, selectedItems }) => {
|
|
2427
|
+
const ValueIcon = getItemIcon(selectedItems[0]);
|
|
2428
|
+
return /* @__PURE__ */ react.createElement(react.Fragment, null, ValueIcon ? /* @__PURE__ */ react.createElement("span", {
|
|
2429
|
+
className: SelectField_module_default.valueIcon,
|
|
2430
|
+
"aria-hidden": true
|
|
2431
|
+
}, /* @__PURE__ */ react.createElement(ValueIcon, { size: "sm" })) : null, /* @__PURE__ */ react.createElement("span", {
|
|
2432
|
+
className: SelectField_module_default.valueText,
|
|
2433
|
+
"data-placeholder": isPlaceholder || !selectedText || void 0
|
|
2434
|
+
}, selectedText || placeholder));
|
|
2435
|
+
}), /* @__PURE__ */ react.createElement("span", { className: SelectField_module_default.trailingSlot }, /* @__PURE__ */ react.createElement(SelectFieldIndicators, { appearance })));
|
|
2436
|
+
const hasSelection = !state.selectionManager.isEmpty;
|
|
2437
|
+
const handleEmptyTriggerPress = (event) => {
|
|
2438
|
+
if (disabled || hasSelection || state.isOpen) return;
|
|
2439
|
+
if (event.target.closest("button")) return;
|
|
2440
|
+
openButtonRef.current?.focus();
|
|
2441
|
+
state.open();
|
|
2442
|
+
};
|
|
2443
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.Group, {
|
|
2444
|
+
ref: triggerRef,
|
|
2445
|
+
className: clsx(SelectField_module_default.triggerShell, SelectField_module_default.multipleTrigger),
|
|
2446
|
+
"data-capra-anchor-width-target": "",
|
|
2447
|
+
"data-size": size,
|
|
2448
|
+
"data-disabled": disabled || void 0,
|
|
2449
|
+
"data-empty": hasSelection ? void 0 : "",
|
|
2450
|
+
onClick: handleEmptyTriggerPress
|
|
2451
|
+
}, leadingSlot ? /* @__PURE__ */ react.createElement("span", { className: SelectField_module_default.leadingSlot }, leadingSlot) : null, /* @__PURE__ */ react.createElement(react_aria_components.ButtonContext.Provider, { value: null }, /* @__PURE__ */ react.createElement(react_aria_components.SelectValue, { className: SelectField_module_default.value }, ({ state: selectState }) => {
|
|
2452
|
+
const tagItems = selectState.selectedItems.filter((item) => item != null).map((item) => ({
|
|
2453
|
+
id: item.key,
|
|
2454
|
+
label: item.textValue || getItemLabelFromNode(item.rendered) || String(item.key),
|
|
2455
|
+
icon: getItemIcon(item.value)
|
|
2456
|
+
}));
|
|
2457
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.TagGroup, {
|
|
2458
|
+
"aria-label": selectedItemsLabel,
|
|
2459
|
+
className: SelectField_module_default.tagGroup,
|
|
2460
|
+
onRemove: disabled ? void 0 : (keys) => {
|
|
2461
|
+
const value = selectState.value;
|
|
2462
|
+
if (Array.isArray(value)) selectState.setValue(removeKeysFromSelection(value, keys));
|
|
2463
|
+
}
|
|
2464
|
+
}, /* @__PURE__ */ react.createElement(react_aria_components.TagList, {
|
|
2465
|
+
className: SelectField_module_default.tagList,
|
|
2466
|
+
items: tagItems,
|
|
2467
|
+
renderEmptyState: () => /* @__PURE__ */ react.createElement("span", {
|
|
2468
|
+
className: SelectField_module_default.valueText,
|
|
2469
|
+
"data-placeholder": placeholder ? true : void 0
|
|
2470
|
+
}, placeholder)
|
|
2471
|
+
}, (item) => /* @__PURE__ */ react.createElement(react_aria_components.Tag, {
|
|
2472
|
+
id: item.id,
|
|
2473
|
+
textValue: item.label,
|
|
2474
|
+
className: SelectField_module_default.tag,
|
|
2475
|
+
"data-size": size === "sm" ? "sm" : "md"
|
|
2476
|
+
}, ({ allowsRemoving }) => /* @__PURE__ */ react.createElement(react.Fragment, null, item.icon ? /* @__PURE__ */ react.createElement("span", {
|
|
2477
|
+
className: SelectField_module_default.tagIcon,
|
|
2478
|
+
"aria-hidden": true
|
|
2479
|
+
}, /* @__PURE__ */ react.createElement(item.icon, { size: "xs" })) : null, /* @__PURE__ */ react.createElement("span", { className: SelectField_module_default.tagLabel }, item.label), allowsRemoving ? /* @__PURE__ */ react.createElement(react_aria_components.Button, {
|
|
2480
|
+
slot: "remove",
|
|
2481
|
+
className: SelectField_module_default.tagRemove,
|
|
2482
|
+
"aria-label": "Delete",
|
|
2483
|
+
excludeFromTabOrder: true
|
|
2484
|
+
}, /* @__PURE__ */ react.createElement(_capra_icons.CloseOutlined, { size: "xs" })) : null))));
|
|
2485
|
+
})), /* @__PURE__ */ react.createElement(SelectFieldTriggerButton, {
|
|
2486
|
+
appearance,
|
|
2487
|
+
buttonRef: openButtonRef,
|
|
2488
|
+
className: SelectField_module_default.multipleOpenButton,
|
|
2489
|
+
isDisabled: disabled,
|
|
2490
|
+
"aria-required": required || void 0
|
|
2491
|
+
}, /* @__PURE__ */ react.createElement("span", { className: SelectField_module_default.trailingSlot }, /* @__PURE__ */ react.createElement(SelectFieldIndicators, { appearance }))));
|
|
2492
|
+
}
|
|
2493
|
+
function SelectFieldItem(props) {
|
|
2494
|
+
const { id, textValue, isDisabled, indent: indentProp, value, children } = props;
|
|
2495
|
+
const indentFromSectionHeader = react.useContext(SelectFieldSectionIndentContext);
|
|
2496
|
+
const indent = indentProp !== void 0 ? indentProp : indentFromSectionHeader;
|
|
2497
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.ListBoxItem, {
|
|
2498
|
+
id,
|
|
2499
|
+
value,
|
|
2500
|
+
textValue: textValue || getItemLabelFromNode(children),
|
|
2501
|
+
isDisabled,
|
|
2502
|
+
className: SelectField_module_default.item,
|
|
2503
|
+
"data-indent": indent || void 0
|
|
2504
|
+
}, ({ isSelected, selectionMode }) => /* @__PURE__ */ react.createElement("div", { className: SelectField_module_default.itemContent }, selectionMode === "multiple" ? /* @__PURE__ */ react.createElement("span", {
|
|
2505
|
+
className: SelectField_module_default.itemCheck,
|
|
2506
|
+
"data-selected": isSelected || void 0,
|
|
2507
|
+
"aria-hidden": true
|
|
2508
|
+
}, isSelected ? /* @__PURE__ */ react.createElement(_capra_icons.CheckOutlined, { size: "sm" }) : null) : null, typeof children === "string" ? /* @__PURE__ */ react.createElement(Text, { slot: "label" }, children) : children));
|
|
2509
|
+
}
|
|
2510
|
+
function SelectFieldHeader(props) {
|
|
2511
|
+
const { id, label = "Header", FORCE__className: classNameOverride, children } = props;
|
|
2512
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.Header, {
|
|
2513
|
+
id,
|
|
2514
|
+
className: clsx(SelectField_module_default.header, classNameOverride)
|
|
2515
|
+
}, children ?? label);
|
|
2516
|
+
}
|
|
2517
|
+
SelectFieldHeader.displayName = "SelectField.Header";
|
|
2518
|
+
function isSelectFieldHeaderElement(child) {
|
|
2519
|
+
return react.isValidElement(child) && child.type === SelectFieldHeader;
|
|
2520
|
+
}
|
|
2521
|
+
function SelectFieldSection(props) {
|
|
2522
|
+
const { children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, FORCE__className: classNameOverride, className, ...rest } = props;
|
|
2523
|
+
const autoHeaderId = react.useId();
|
|
2524
|
+
const childArray = react.Children.toArray(children);
|
|
2525
|
+
let headerIndex = -1;
|
|
2526
|
+
for (let i = 0; i < childArray.length; i++) if (isSelectFieldHeaderElement(childArray[i])) {
|
|
2527
|
+
headerIndex = i;
|
|
2528
|
+
break;
|
|
2529
|
+
}
|
|
2530
|
+
const hasHeader = headerIndex >= 0;
|
|
2531
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2532
|
+
if (!hasHeader && !ariaLabel?.trim() && !ariaLabelledBy?.trim()) console.error("SelectField.Section: provide aria-label or aria-labelledby when the section has no direct SelectField.Header child.");
|
|
2533
|
+
}
|
|
2534
|
+
const labelledBy = hasHeader ? ariaLabelledBy ?? autoHeaderId : ariaLabelledBy;
|
|
2535
|
+
const effectiveAriaLabel = hasHeader ? void 0 : ariaLabel;
|
|
2536
|
+
const resolvedChildren = hasHeader && headerIndex >= 0 ? childArray.map((child, i) => {
|
|
2537
|
+
if (i === headerIndex && isSelectFieldHeaderElement(child)) return react.cloneElement(child, { id: child.props.id ?? autoHeaderId });
|
|
2538
|
+
return child;
|
|
2539
|
+
}) : children;
|
|
2540
|
+
return /* @__PURE__ */ react.createElement(SelectFieldSectionIndentContext.Provider, { value: hasHeader }, /* @__PURE__ */ react.createElement(react_aria_components.ListBoxSection, {
|
|
2541
|
+
"aria-label": effectiveAriaLabel,
|
|
2542
|
+
"aria-labelledby": labelledBy,
|
|
2543
|
+
className: clsx(SelectField_module_default.section, className, classNameOverride),
|
|
2544
|
+
...rest
|
|
2545
|
+
}, resolvedChildren));
|
|
2546
|
+
}
|
|
2547
|
+
SelectFieldSection.displayName = "SelectField.Section";
|
|
2548
|
+
function defaultSelectFieldItemRenderer(item) {
|
|
2549
|
+
if (isDefaultSection(item)) {
|
|
2550
|
+
const { id, label, "aria-label": ariaLabel, children } = item;
|
|
2551
|
+
return /* @__PURE__ */ react.createElement(SelectFieldSection, {
|
|
2552
|
+
key: String(id),
|
|
2553
|
+
"aria-label": label ? void 0 : ariaLabel
|
|
2554
|
+
}, label ? /* @__PURE__ */ react.createElement(SelectFieldHeader, { label }) : null, /* @__PURE__ */ react.createElement(react_aria_components.Collection, { items: children }, (child) => defaultSelectFieldItemRenderer(child)));
|
|
2555
|
+
}
|
|
2556
|
+
const Icon = item.icon;
|
|
2557
|
+
return /* @__PURE__ */ react.createElement(SelectFieldItem, {
|
|
2558
|
+
id: item.id,
|
|
2559
|
+
textValue: item.label
|
|
2560
|
+
}, Icon ? /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(Icon, { size: "sm" }), /* @__PURE__ */ react.createElement(Text, { slot: "label" }, item.label)) : item.label);
|
|
2561
|
+
}
|
|
2562
|
+
function SelectFieldLabel(props) {
|
|
2563
|
+
const { children, required } = props;
|
|
2564
|
+
const { elementType: _elementType, ...labelContextWithoutElementType } = (0, react_aria_components.useSlottedContext)(react_aria_components.LabelContext) ?? {};
|
|
2565
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.LabelContext.Provider, { value: labelContextWithoutElementType }, /* @__PURE__ */ react.createElement(Label, { required }, children));
|
|
2566
|
+
}
|
|
2567
|
+
function AutocompleteTextInput(props) {
|
|
2568
|
+
const { placeholder, shouldFocus, size } = props;
|
|
2569
|
+
const ref = react.useRef(null);
|
|
2570
|
+
const [mergedProps, mergedRef] = (0, react_aria_components.useContextProps)({
|
|
2571
|
+
"aria-label": props["aria-label"],
|
|
2572
|
+
placeholder,
|
|
2573
|
+
type: "search"
|
|
2574
|
+
}, ref, react_aria_components.FieldInputContext);
|
|
2575
|
+
const { onChange, value, ...inputProps } = mergedProps;
|
|
2576
|
+
const inputRef = mergedRef;
|
|
2577
|
+
react.useLayoutEffect(() => {
|
|
2578
|
+
if (!shouldFocus) return;
|
|
2579
|
+
const input = inputRef.current;
|
|
2580
|
+
if (!input) return;
|
|
2581
|
+
requestAnimationFrame(() => {
|
|
2582
|
+
try {
|
|
2583
|
+
input.focus({ preventScroll: true });
|
|
2584
|
+
} catch {}
|
|
2585
|
+
});
|
|
2586
|
+
}, [inputRef, shouldFocus]);
|
|
2587
|
+
return /* @__PURE__ */ react.createElement(TextInput, {
|
|
2588
|
+
...inputProps,
|
|
2589
|
+
ref: inputRef,
|
|
2590
|
+
size,
|
|
2591
|
+
value: typeof value === "string" ? value : "",
|
|
2592
|
+
onChange: (event) => {
|
|
2593
|
+
onChange?.(event.target.value);
|
|
2594
|
+
}
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
function SelectFieldInner(props, ref) {
|
|
2598
|
+
const { appearance = "default", autoFocus, canSearch, defaultOpen, disabled, disabledKeys, helperText, id, isOpen, items, children, label, layout, leadingSlot, name, onOpenChange, placeholder, required, searchPlaceholder, selectionMode = "single", shouldAutoSizeDropdown = true, size = "md", FORCE__className: classNameOverride, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy } = props;
|
|
2599
|
+
const [searchValue, setSearchValue] = react.useState("");
|
|
2600
|
+
const [popoverWidth, setPopoverWidth] = react.useState();
|
|
2601
|
+
const [uncontrolledOpen, setUncontrolledOpen] = react.useState(Boolean(defaultOpen));
|
|
2602
|
+
const isPopoverOpen = isOpen ?? uncontrolledOpen;
|
|
2603
|
+
const { contains } = (0, react_aria_components.useFilter)({ sensitivity: "base" });
|
|
2604
|
+
const [anchorRef, width, offset] = useAnchorWidth([
|
|
2605
|
+
canSearch,
|
|
2606
|
+
selectionMode,
|
|
2607
|
+
size
|
|
2608
|
+
]);
|
|
2609
|
+
const multipleTriggerRef = react.useRef(null);
|
|
2610
|
+
const selectedItemsLabel = label ? `Selected ${label}` : ariaLabel ?? "Selected items";
|
|
2611
|
+
react.useImperativeHandle(ref, () => anchorRef.current, [anchorRef]);
|
|
2612
|
+
react.useLayoutEffect(() => {
|
|
2613
|
+
const trigger = multipleTriggerRef.current ?? anchorRef.current;
|
|
2614
|
+
if (selectionMode !== "multiple" || !isPopoverOpen || popoverWidth || !trigger) return;
|
|
2615
|
+
setPopoverWidth(`${trigger.offsetWidth}px`);
|
|
2616
|
+
}, [
|
|
2617
|
+
isPopoverOpen,
|
|
2618
|
+
popoverWidth,
|
|
2619
|
+
selectionMode,
|
|
2620
|
+
width,
|
|
2621
|
+
anchorRef
|
|
2622
|
+
]);
|
|
2623
|
+
const itemList = react.useMemo(() => items ? Array.from(items) : void 0, [items]);
|
|
2624
|
+
const resolvedChildren = children ?? (itemList ? defaultSelectFieldItemRenderer : void 0);
|
|
2625
|
+
const handleOpenChange = react.useCallback((nextOpen) => {
|
|
2626
|
+
if (isOpen === void 0) setUncontrolledOpen(nextOpen);
|
|
2627
|
+
if (selectionMode === "multiple" && !nextOpen) setPopoverWidth(void 0);
|
|
2628
|
+
if (!nextOpen) setSearchValue("");
|
|
2629
|
+
onOpenChange?.(nextOpen);
|
|
2630
|
+
}, [
|
|
2631
|
+
isOpen,
|
|
2632
|
+
onOpenChange,
|
|
2633
|
+
selectionMode
|
|
2634
|
+
]);
|
|
2635
|
+
const dropdownWidth = selectionMode === "multiple" ? popoverWidth ?? width ?? void 0 : width ?? void 0;
|
|
2636
|
+
const listBoxSearchProps = canSearch ? {
|
|
2637
|
+
autoFocus: false,
|
|
2638
|
+
renderEmptyState: () => /* @__PURE__ */ react.createElement("span", { className: SelectField_module_default.emptyState }, "No results")
|
|
2639
|
+
} : {};
|
|
2640
|
+
const listBox = /* @__PURE__ */ react.createElement(react_aria_components.ListBox, {
|
|
2641
|
+
...listBoxSearchProps,
|
|
2642
|
+
className: SelectField_module_default.listbox,
|
|
2643
|
+
"data-selection-mode": selectionMode,
|
|
2644
|
+
items: itemList
|
|
2645
|
+
}, resolvedChildren);
|
|
2646
|
+
const popoverContent = canSearch ? /* @__PURE__ */ react.createElement(react_aria_components.Autocomplete, {
|
|
2647
|
+
filter: contains,
|
|
2648
|
+
inputValue: searchValue,
|
|
2649
|
+
onInputChange: setSearchValue
|
|
2650
|
+
}, /* @__PURE__ */ react.createElement("div", { className: SelectField_module_default.search }, /* @__PURE__ */ react.createElement(AutocompleteTextInput, {
|
|
2651
|
+
"aria-label": searchPlaceholder || "Search",
|
|
2652
|
+
placeholder: searchPlaceholder || "Search",
|
|
2653
|
+
shouldFocus: isPopoverOpen,
|
|
2654
|
+
size
|
|
2655
|
+
})), listBox) : listBox;
|
|
2656
|
+
const selectContent = /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement("div", { className: fieldLayout_module_default.labelRow }, /* @__PURE__ */ react.createElement(SelectFieldLabel, { required }, label)), /* @__PURE__ */ react.createElement("div", { className: fieldLayout_module_default.fieldContent }, /* @__PURE__ */ react.createElement(SelectFieldTrigger, {
|
|
2657
|
+
appearance,
|
|
2658
|
+
disabled,
|
|
2659
|
+
leadingSlot,
|
|
2660
|
+
placeholder,
|
|
2661
|
+
required,
|
|
2662
|
+
selectedItemsLabel,
|
|
2663
|
+
size,
|
|
2664
|
+
triggerRef: selectionMode === "multiple" ? multipleTriggerRef : void 0
|
|
2665
|
+
}), /* @__PURE__ */ react.createElement(HelperText, {
|
|
2666
|
+
appearance,
|
|
2667
|
+
disabled
|
|
2668
|
+
}, helperText)), /* @__PURE__ */ react.createElement(react_aria_components.Popover, {
|
|
2669
|
+
className: SelectField_module_default.dropdownPanel,
|
|
2670
|
+
offset: 2,
|
|
2671
|
+
crossOffset: offset,
|
|
2672
|
+
triggerRef: selectionMode === "multiple" ? multipleTriggerRef : void 0,
|
|
2673
|
+
style: { width: shouldAutoSizeDropdown ? dropdownWidth : void 0 }
|
|
2674
|
+
}, popoverContent));
|
|
2675
|
+
if (props.selectionMode === "multiple") {
|
|
2676
|
+
const handleChange = (nextValue) => {
|
|
2677
|
+
props.onChange?.(new Set(nextValue));
|
|
2678
|
+
};
|
|
2679
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.Select, {
|
|
2680
|
+
id,
|
|
2681
|
+
ref: anchorRef,
|
|
2682
|
+
name,
|
|
2683
|
+
className: clsx(fieldLayout_module_default.field, classNameOverride),
|
|
2684
|
+
"data-capra-field-root": "",
|
|
2685
|
+
"data-layout": layout,
|
|
2686
|
+
isDisabled: disabled,
|
|
2687
|
+
isRequired: required,
|
|
2688
|
+
isInvalid: appearance === "danger",
|
|
2689
|
+
validationBehavior: "aria",
|
|
2690
|
+
placeholder,
|
|
2691
|
+
selectionMode: "multiple",
|
|
2692
|
+
disabledKeys,
|
|
2693
|
+
value: normalizeIterable(props.value),
|
|
2694
|
+
defaultValue: normalizeIterable(props.defaultValue),
|
|
2695
|
+
onChange: handleChange,
|
|
2696
|
+
isOpen,
|
|
2697
|
+
defaultOpen,
|
|
2698
|
+
onOpenChange: handleOpenChange,
|
|
2699
|
+
autoFocus,
|
|
2700
|
+
"aria-label": ariaLabel,
|
|
2701
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2702
|
+
"aria-describedby": ariaDescribedBy
|
|
2703
|
+
}, selectContent);
|
|
2704
|
+
}
|
|
2705
|
+
const handleChange = (nextValue) => {
|
|
2706
|
+
props.onChange?.(nextValue ?? null);
|
|
2707
|
+
};
|
|
2708
|
+
return /* @__PURE__ */ react.createElement(react_aria_components.Select, {
|
|
2709
|
+
id,
|
|
2710
|
+
ref: anchorRef,
|
|
2711
|
+
name,
|
|
2712
|
+
className: clsx(fieldLayout_module_default.field, classNameOverride),
|
|
2713
|
+
"data-capra-field-root": "",
|
|
2714
|
+
"data-layout": layout,
|
|
2715
|
+
isDisabled: disabled,
|
|
2716
|
+
isRequired: required,
|
|
2717
|
+
isInvalid: appearance === "danger",
|
|
2718
|
+
validationBehavior: "aria",
|
|
2719
|
+
placeholder,
|
|
2720
|
+
selectionMode: "single",
|
|
2721
|
+
disabledKeys,
|
|
2722
|
+
value: props.value,
|
|
2723
|
+
defaultValue: props.defaultValue,
|
|
2724
|
+
onChange: handleChange,
|
|
2725
|
+
isOpen,
|
|
2726
|
+
defaultOpen,
|
|
2727
|
+
onOpenChange: handleOpenChange,
|
|
2728
|
+
autoFocus,
|
|
2729
|
+
"aria-label": ariaLabel,
|
|
2730
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2731
|
+
"aria-describedby": ariaDescribedBy
|
|
2732
|
+
}, selectContent);
|
|
2733
|
+
}
|
|
2734
|
+
const SelectFieldRoot = react.forwardRef(SelectFieldInner);
|
|
2735
|
+
/**
|
|
2736
|
+
* Composed select field with Capra label/helper text layout, single and multiple selection, and an optional popover search input.
|
|
2737
|
+
*/
|
|
2738
|
+
const SelectField = Object.assign(SelectFieldRoot, {
|
|
2739
|
+
Item: SelectFieldItem,
|
|
2740
|
+
Header: SelectFieldHeader,
|
|
2741
|
+
Section: SelectFieldSection
|
|
2742
|
+
});
|
|
2743
|
+
//#endregion
|
|
2316
2744
|
//#region src/components/DateRangePickerField/DateRangePickerField.module.css
|
|
2317
2745
|
var DateRangePickerField_module_default = {
|
|
2318
2746
|
"cell": "capra-DateRangePickerField-module-QpPhpG-cell",
|
|
@@ -5234,6 +5662,7 @@ Object.defineProperty(exports, "RouterProvider", {
|
|
|
5234
5662
|
});
|
|
5235
5663
|
exports.SKELETON_SIZE = SKELETON_SIZE;
|
|
5236
5664
|
exports.SKELETON_SIZE_TOKENS = SKELETON_SIZE_TOKENS;
|
|
5665
|
+
exports.SelectField = SelectField;
|
|
5237
5666
|
exports.Skeleton = Skeleton;
|
|
5238
5667
|
exports.SkeletonGroup = SkeletonGroup;
|
|
5239
5668
|
exports.Spinner = Spinner;
|