@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.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React$1 from "react";
|
|
2
|
-
import React, { Suspense
|
|
3
|
-
import { AnglesLeft, AnglesRight, ArrowUpRightFromSquare, AttentionOutlined, AttentionSolid, CalendarNextOutlined, CalendarOutlined, CalendarPrevOutlined, CaretRight, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, CircleXmark, CloseOutlined, DragGrip, Exclamation, EyeInvisibleOutlined, EyeOutlined, InfoOutlined, InfoSolid, Loading, SuccessOutlined, SuccessSolid, SwapRightOutlined, WarningOutlined, WarningSolid } from "@capra/icons";
|
|
4
|
-
import { Breadcrumb as Breadcrumb$1, Breadcrumbs as Breadcrumbs$1, Button as Button$1, ButtonContext, Calendar, CalendarCell, CalendarGrid, CalendarGridBody, CalendarGridHeader, CalendarHeaderCell, Collection, ComboBox, DateInput, DatePicker, DatePickerStateContext, DateRangePicker, DateRangePickerStateContext, DateSegment, Dialog, DialogTrigger, Disclosure, DisclosurePanel, Focusable, Group, Header, Heading, HeadingContext, Input, InputContext, LabelContext, Link as Link$1, ListBox, ListBoxItem, Menu as Menu$1, MenuItem, MenuSection, MenuTrigger, Modal as Modal$1, ModalOverlay, NumberField as NumberField$1, OverlayArrow, OverlayTriggerStateContext, Popover as Popover$1, Pressable, RangeCalendar, RangeCalendarStateContext, RouterProvider, Separator, SubmenuTrigger, Text as Text$1, TextArea as TextArea$1, TextContext, TextField as TextField$1, Tooltip as Tooltip$1, TooltipTrigger, Tree as Tree$1, TreeItem, TreeItemContent, composeRenderProps, useContextProps, useSlottedContext } from "react-aria-components";
|
|
5
|
-
import { FocusScope, UNSAFE_PortalProvider, useDateFormatter, useFocusWithin, usePreventScroll } from "react-aria";
|
|
2
|
+
import React, { Suspense } from "react";
|
|
3
|
+
import { AnglesLeft, AnglesRight, ArrowUpRightFromSquare, AttentionOutlined, AttentionSolid, CalendarNextOutlined, CalendarOutlined, CalendarPrevOutlined, CaretRight, CheckOutlined, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, CircleXmark, CloseOutlined, DragGrip, Exclamation, EyeInvisibleOutlined, EyeOutlined, InfoOutlined, InfoSolid, Loading, SuccessOutlined, SuccessSolid, SwapRightOutlined, WarningOutlined, WarningSolid } from "@capra/icons";
|
|
4
|
+
import { Autocomplete, Breadcrumb as Breadcrumb$1, Breadcrumbs as Breadcrumbs$1, Button as Button$1, ButtonContext, Calendar, CalendarCell, CalendarGrid, CalendarGridBody, CalendarGridHeader, CalendarHeaderCell, Collection, ComboBox, DateInput, DatePicker, DatePickerStateContext, DateRangePicker, DateRangePickerStateContext, DateSegment, Dialog, DialogTrigger, Disclosure, DisclosurePanel, FieldInputContext, Focusable, Group, Header, Heading, HeadingContext, Input, InputContext, LabelContext, Link as Link$1, ListBox, ListBoxItem, ListBoxSection, Menu as Menu$1, MenuItem, MenuSection, MenuTrigger, Modal as Modal$1, ModalOverlay, NumberField as NumberField$1, OverlayArrow, OverlayTriggerStateContext, Popover as Popover$1, Pressable, RangeCalendar, RangeCalendarStateContext, RouterProvider, Select, SelectStateContext, SelectValue, Separator, SubmenuTrigger, Tag as Tag$1, TagGroup, TagList, Text as Text$1, TextArea as TextArea$1, TextContext, TextField as TextField$1, Tooltip as Tooltip$1, TooltipTrigger, Tree as Tree$1, TreeItem, TreeItemContent, composeRenderProps, useContextProps, useFilter, useSlottedContext } from "react-aria-components";
|
|
5
|
+
import { FocusScope, UNSAFE_PortalProvider, mergeProps, useButton, useDateFormatter, useFocusRing, useFocusWithin, usePreventScroll } from "react-aria";
|
|
6
6
|
import { createRoot } from "react-dom/client";
|
|
7
7
|
import { createPortal } from "react-dom";
|
|
8
8
|
//#region ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/lite.mjs
|
|
@@ -323,11 +323,50 @@ HelperText.displayName = "HelperText";
|
|
|
323
323
|
//#endregion
|
|
324
324
|
//#region src/components/input-helpers/fieldLayout.module.css
|
|
325
325
|
var fieldLayout_module_default = {
|
|
326
|
-
"field": "capra-fieldLayout-module-
|
|
327
|
-
"fieldContent": "capra-fieldLayout-module-
|
|
328
|
-
"labelRow": "capra-fieldLayout-module-
|
|
326
|
+
"field": "capra-fieldLayout-module-0mM4jW-field",
|
|
327
|
+
"fieldContent": "capra-fieldLayout-module-0mM4jW-fieldContent",
|
|
328
|
+
"labelRow": "capra-fieldLayout-module-0mM4jW-labelRow"
|
|
329
329
|
};
|
|
330
330
|
//#endregion
|
|
331
|
+
//#region src/components/input-helpers/useAnchorWidth.ts
|
|
332
|
+
/**
|
|
333
|
+
* Element that visually bounds the field (select trigger or text input shell). The popover matches
|
|
334
|
+
* its width and left edge, which differs from the field root in horizontal layouts where the label
|
|
335
|
+
* sits beside the control.
|
|
336
|
+
*/
|
|
337
|
+
function getShellElement(anchor) {
|
|
338
|
+
return anchor.querySelector("[data-capra-anchor-width-target]") ?? anchor.querySelector("[data-capra-text-input]") ?? anchor;
|
|
339
|
+
}
|
|
340
|
+
/** Element React Aria anchors the popover to: the select trigger or the combobox input. */
|
|
341
|
+
function getTriggerElement(anchor) {
|
|
342
|
+
return anchor.querySelector("[data-capra-anchor-width-target]") ?? anchor.querySelector("input") ?? anchor;
|
|
343
|
+
}
|
|
344
|
+
function useAnchorWidth(additionalDependencies = []) {
|
|
345
|
+
const anchorRef = React$1.useRef(null);
|
|
346
|
+
const [width, setWidth] = React$1.useState(null);
|
|
347
|
+
const [offset, setOffset] = React$1.useState(0);
|
|
348
|
+
React$1.useEffect(() => {
|
|
349
|
+
const anchor = anchorRef.current;
|
|
350
|
+
if (!anchor) return;
|
|
351
|
+
const measure = () => {
|
|
352
|
+
const shell = getShellElement(anchor);
|
|
353
|
+
const trigger = getTriggerElement(anchor);
|
|
354
|
+
setWidth(shell.offsetWidth + "px");
|
|
355
|
+
setOffset(shell.getBoundingClientRect().left - trigger.getBoundingClientRect().left);
|
|
356
|
+
};
|
|
357
|
+
const observer = new ResizeObserver(measure);
|
|
358
|
+
observer.observe(anchor);
|
|
359
|
+
const shell = getShellElement(anchor);
|
|
360
|
+
if (shell !== anchor) observer.observe(shell);
|
|
361
|
+
return () => observer.disconnect();
|
|
362
|
+
}, additionalDependencies);
|
|
363
|
+
return [
|
|
364
|
+
anchorRef,
|
|
365
|
+
width,
|
|
366
|
+
offset
|
|
367
|
+
];
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
331
370
|
//#region src/components/Autocomplete/AutocompleteField.module.css
|
|
332
371
|
var AutocompleteField_module_default = {
|
|
333
372
|
"item": "capra-AutocompleteField-module-MVvKYa-item",
|
|
@@ -386,41 +425,6 @@ function AutocompleteFieldWithoutRef(props, ref) {
|
|
|
386
425
|
style: { width: shouldAutoSizeDropdown ? width : void 0 }
|
|
387
426
|
}, /* @__PURE__ */ React.createElement(ListBox, { className: AutocompleteField_module_default.listbox }, children)));
|
|
388
427
|
}
|
|
389
|
-
function useResizeObserver({ ref, onResize, additionalDependencies = [] }) {
|
|
390
|
-
React.useEffect(() => {
|
|
391
|
-
if (!ref.current) return;
|
|
392
|
-
const observer = new ResizeObserver((entries) => {
|
|
393
|
-
onResize(entries[0]);
|
|
394
|
-
});
|
|
395
|
-
observer.observe(ref.current);
|
|
396
|
-
return () => observer.disconnect();
|
|
397
|
-
}, [
|
|
398
|
-
ref,
|
|
399
|
-
onResize,
|
|
400
|
-
...additionalDependencies
|
|
401
|
-
]);
|
|
402
|
-
}
|
|
403
|
-
function useAnchorWidth(additionalDependencies = []) {
|
|
404
|
-
const anchorRef = React.useRef(null);
|
|
405
|
-
const [width, setWidth] = useState(null);
|
|
406
|
-
const [offset, setOffset] = useState(0);
|
|
407
|
-
useResizeObserver({
|
|
408
|
-
ref: anchorRef,
|
|
409
|
-
onResize: useCallback(() => {
|
|
410
|
-
if (anchorRef.current) {
|
|
411
|
-
setWidth(anchorRef.current.offsetWidth + "px");
|
|
412
|
-
const input = anchorRef.current.querySelector("input");
|
|
413
|
-
if (input) setOffset(anchorRef.current.offsetLeft - input.offsetLeft);
|
|
414
|
-
}
|
|
415
|
-
}, [anchorRef]),
|
|
416
|
-
additionalDependencies
|
|
417
|
-
});
|
|
418
|
-
return [
|
|
419
|
-
anchorRef,
|
|
420
|
-
width,
|
|
421
|
-
offset
|
|
422
|
-
];
|
|
423
|
-
}
|
|
424
428
|
/**
|
|
425
429
|
* 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.
|
|
426
430
|
*/
|
|
@@ -811,7 +815,7 @@ function RadioTileWithoutRef({ children, checked, disabled, description, icon, F
|
|
|
811
815
|
const RadioTile = fixedForwardRef(RadioTileWithoutRef);
|
|
812
816
|
//#endregion
|
|
813
817
|
//#region src/components/Switch/Switch.module.css
|
|
814
|
-
var Switch_module_default = { "switch": "capra-Switch-module-
|
|
818
|
+
var Switch_module_default = { "switch": "capra-Switch-module-j8Yc-q-switch" };
|
|
815
819
|
//#endregion
|
|
816
820
|
//#region src/components/Switch/Switch.tsx
|
|
817
821
|
const Switch = React$1.forwardRef((props, ref) => {
|
|
@@ -2290,6 +2294,430 @@ const DatePickerFieldWithRef = React$1.forwardRef(DatePickerFieldInner);
|
|
|
2290
2294
|
DatePickerFieldWithRef.displayName = "DatePickerField";
|
|
2291
2295
|
const DatePickerField = DatePickerFieldWithRef;
|
|
2292
2296
|
//#endregion
|
|
2297
|
+
//#region src/components/SelectField/SelectField.module.css
|
|
2298
|
+
var SelectField_module_default = {
|
|
2299
|
+
"chevron": "capra-SelectField-module-1X4diq-chevron",
|
|
2300
|
+
"dropdownPanel": "capra-SelectField-module-1X4diq-dropdownPanel",
|
|
2301
|
+
"emptyState": "capra-SelectField-module-1X4diq-emptyState",
|
|
2302
|
+
"errorIndicator": "capra-SelectField-module-1X4diq-errorIndicator",
|
|
2303
|
+
"header": "capra-SelectField-module-1X4diq-header",
|
|
2304
|
+
"item": "capra-SelectField-module-1X4diq-item",
|
|
2305
|
+
"itemCheck": "capra-SelectField-module-1X4diq-itemCheck",
|
|
2306
|
+
"itemContent": "capra-SelectField-module-1X4diq-itemContent",
|
|
2307
|
+
"leadingSlot": "capra-SelectField-module-1X4diq-leadingSlot",
|
|
2308
|
+
"listbox": "capra-SelectField-module-1X4diq-listbox",
|
|
2309
|
+
"multipleOpenButton": "capra-SelectField-module-1X4diq-multipleOpenButton",
|
|
2310
|
+
"multipleTrigger": "capra-SelectField-module-1X4diq-multipleTrigger",
|
|
2311
|
+
"search": "capra-SelectField-module-1X4diq-search",
|
|
2312
|
+
"section": "capra-SelectField-module-1X4diq-section",
|
|
2313
|
+
"singleTrigger": "capra-SelectField-module-1X4diq-singleTrigger",
|
|
2314
|
+
"tag": "capra-SelectField-module-1X4diq-tag",
|
|
2315
|
+
"tagGroup": "capra-SelectField-module-1X4diq-tagGroup",
|
|
2316
|
+
"tagIcon": "capra-SelectField-module-1X4diq-tagIcon",
|
|
2317
|
+
"tagLabel": "capra-SelectField-module-1X4diq-tagLabel",
|
|
2318
|
+
"tagList": "capra-SelectField-module-1X4diq-tagList",
|
|
2319
|
+
"tagRemove": "capra-SelectField-module-1X4diq-tagRemove",
|
|
2320
|
+
"trailingSlot": "capra-SelectField-module-1X4diq-trailingSlot",
|
|
2321
|
+
"triggerShell": "capra-SelectField-module-1X4diq-triggerShell",
|
|
2322
|
+
"value": "capra-SelectField-module-1X4diq-value",
|
|
2323
|
+
"valueIcon": "capra-SelectField-module-1X4diq-valueIcon",
|
|
2324
|
+
"valueText": "capra-SelectField-module-1X4diq-valueText",
|
|
2325
|
+
"warningIndicator": "capra-SelectField-module-1X4diq-warningIndicator"
|
|
2326
|
+
};
|
|
2327
|
+
//#endregion
|
|
2328
|
+
//#region src/components/SelectField/SelectField.tsx
|
|
2329
|
+
/** When true, SelectField.Item indents by default (inside SelectField.Section that contains SelectField.Header). */
|
|
2330
|
+
const SelectFieldSectionIndentContext = React$1.createContext(false);
|
|
2331
|
+
function normalizeIterable(value) {
|
|
2332
|
+
return value === void 0 ? void 0 : Array.from(value);
|
|
2333
|
+
}
|
|
2334
|
+
function getItemLabelFromNode(node) {
|
|
2335
|
+
if (typeof node === "string") return node;
|
|
2336
|
+
if (typeof node === "number") return String(node);
|
|
2337
|
+
if (React$1.isValidElement(node)) {
|
|
2338
|
+
if (typeof node.props.textValue === "string") return node.props.textValue;
|
|
2339
|
+
return getItemLabelFromNode(node.props.children);
|
|
2340
|
+
}
|
|
2341
|
+
return "";
|
|
2342
|
+
}
|
|
2343
|
+
function removeKeysFromSelection(selection, keys) {
|
|
2344
|
+
return (selection ?? []).filter((selectedKey) => !keys.has(selectedKey));
|
|
2345
|
+
}
|
|
2346
|
+
function getItemIcon(item) {
|
|
2347
|
+
if (item && typeof item === "object" && "icon" in item) {
|
|
2348
|
+
const icon = item.icon;
|
|
2349
|
+
return icon && typeof icon === "object" && "__brand" in icon ? icon : void 0;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
function isDefaultSection(item) {
|
|
2353
|
+
const children = item.children;
|
|
2354
|
+
return children != null && typeof children !== "string" && typeof children[Symbol.iterator] === "function";
|
|
2355
|
+
}
|
|
2356
|
+
function SelectFieldIndicators(props) {
|
|
2357
|
+
const { appearance } = props;
|
|
2358
|
+
return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, appearance === "warning" ? /* @__PURE__ */ React$1.createElement("span", {
|
|
2359
|
+
className: SelectField_module_default.warningIndicator,
|
|
2360
|
+
"aria-hidden": true
|
|
2361
|
+
}, /* @__PURE__ */ React$1.createElement(WarningOutlined, { size: "sm" })) : null, appearance === "danger" ? /* @__PURE__ */ React$1.createElement("span", {
|
|
2362
|
+
className: SelectField_module_default.errorIndicator,
|
|
2363
|
+
"aria-hidden": true
|
|
2364
|
+
}, /* @__PURE__ */ React$1.createElement(Exclamation, { size: "sm" })) : null, /* @__PURE__ */ React$1.createElement("span", {
|
|
2365
|
+
className: SelectField_module_default.chevron,
|
|
2366
|
+
"aria-hidden": true
|
|
2367
|
+
}, /* @__PURE__ */ React$1.createElement(ChevronDown, { size: "sm" })));
|
|
2368
|
+
}
|
|
2369
|
+
function SelectFieldTriggerButton(props) {
|
|
2370
|
+
const { appearance, buttonRef, children, className, ...rest } = props;
|
|
2371
|
+
const localRef = React$1.useRef(null);
|
|
2372
|
+
const ref = buttonRef ?? localRef;
|
|
2373
|
+
const [mergedProps, mergedRef] = useContextProps({
|
|
2374
|
+
...rest,
|
|
2375
|
+
className
|
|
2376
|
+
}, ref, ButtonContext);
|
|
2377
|
+
const { buttonProps, isPressed } = useButton(mergedProps, mergedRef);
|
|
2378
|
+
const { focusProps, isFocused, isFocusVisible } = useFocusRing(mergedProps);
|
|
2379
|
+
return /* @__PURE__ */ React$1.createElement("button", {
|
|
2380
|
+
...mergeProps(buttonProps, focusProps),
|
|
2381
|
+
ref: mergedRef,
|
|
2382
|
+
className,
|
|
2383
|
+
"aria-invalid": appearance === "danger" ? true : void 0,
|
|
2384
|
+
"data-pressed": isPressed || void 0,
|
|
2385
|
+
"data-focused": isFocused || void 0,
|
|
2386
|
+
"data-focus-visible": isFocusVisible || void 0,
|
|
2387
|
+
"data-disabled": mergedProps.isDisabled || void 0
|
|
2388
|
+
}, children);
|
|
2389
|
+
}
|
|
2390
|
+
function SelectFieldTrigger(props) {
|
|
2391
|
+
const { appearance, disabled, leadingSlot, placeholder, required, selectedItemsLabel, size, triggerRef } = props;
|
|
2392
|
+
const state = React$1.useContext(SelectStateContext);
|
|
2393
|
+
const openButtonRef = React$1.useRef(null);
|
|
2394
|
+
if (!state) return null;
|
|
2395
|
+
if (!(state.selectionManager.selectionMode === "multiple")) return /* @__PURE__ */ React$1.createElement(SelectFieldTriggerButton, {
|
|
2396
|
+
appearance,
|
|
2397
|
+
className: clsx(SelectField_module_default.triggerShell, SelectField_module_default.singleTrigger),
|
|
2398
|
+
"data-capra-anchor-width-target": "",
|
|
2399
|
+
"data-size": size,
|
|
2400
|
+
"data-disabled": disabled || void 0,
|
|
2401
|
+
"aria-required": required || void 0,
|
|
2402
|
+
isDisabled: disabled
|
|
2403
|
+
}, leadingSlot ? /* @__PURE__ */ React$1.createElement("span", { className: SelectField_module_default.leadingSlot }, leadingSlot) : null, /* @__PURE__ */ React$1.createElement(SelectValue, { className: SelectField_module_default.value }, ({ isPlaceholder, selectedText, selectedItems }) => {
|
|
2404
|
+
const ValueIcon = getItemIcon(selectedItems[0]);
|
|
2405
|
+
return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, ValueIcon ? /* @__PURE__ */ React$1.createElement("span", {
|
|
2406
|
+
className: SelectField_module_default.valueIcon,
|
|
2407
|
+
"aria-hidden": true
|
|
2408
|
+
}, /* @__PURE__ */ React$1.createElement(ValueIcon, { size: "sm" })) : null, /* @__PURE__ */ React$1.createElement("span", {
|
|
2409
|
+
className: SelectField_module_default.valueText,
|
|
2410
|
+
"data-placeholder": isPlaceholder || !selectedText || void 0
|
|
2411
|
+
}, selectedText || placeholder));
|
|
2412
|
+
}), /* @__PURE__ */ React$1.createElement("span", { className: SelectField_module_default.trailingSlot }, /* @__PURE__ */ React$1.createElement(SelectFieldIndicators, { appearance })));
|
|
2413
|
+
const hasSelection = !state.selectionManager.isEmpty;
|
|
2414
|
+
const handleEmptyTriggerPress = (event) => {
|
|
2415
|
+
if (disabled || hasSelection || state.isOpen) return;
|
|
2416
|
+
if (event.target.closest("button")) return;
|
|
2417
|
+
openButtonRef.current?.focus();
|
|
2418
|
+
state.open();
|
|
2419
|
+
};
|
|
2420
|
+
return /* @__PURE__ */ React$1.createElement(Group, {
|
|
2421
|
+
ref: triggerRef,
|
|
2422
|
+
className: clsx(SelectField_module_default.triggerShell, SelectField_module_default.multipleTrigger),
|
|
2423
|
+
"data-capra-anchor-width-target": "",
|
|
2424
|
+
"data-size": size,
|
|
2425
|
+
"data-disabled": disabled || void 0,
|
|
2426
|
+
"data-empty": hasSelection ? void 0 : "",
|
|
2427
|
+
onClick: handleEmptyTriggerPress
|
|
2428
|
+
}, leadingSlot ? /* @__PURE__ */ React$1.createElement("span", { className: SelectField_module_default.leadingSlot }, leadingSlot) : null, /* @__PURE__ */ React$1.createElement(ButtonContext.Provider, { value: null }, /* @__PURE__ */ React$1.createElement(SelectValue, { className: SelectField_module_default.value }, ({ state: selectState }) => {
|
|
2429
|
+
const tagItems = selectState.selectedItems.filter((item) => item != null).map((item) => ({
|
|
2430
|
+
id: item.key,
|
|
2431
|
+
label: item.textValue || getItemLabelFromNode(item.rendered) || String(item.key),
|
|
2432
|
+
icon: getItemIcon(item.value)
|
|
2433
|
+
}));
|
|
2434
|
+
return /* @__PURE__ */ React$1.createElement(TagGroup, {
|
|
2435
|
+
"aria-label": selectedItemsLabel,
|
|
2436
|
+
className: SelectField_module_default.tagGroup,
|
|
2437
|
+
onRemove: disabled ? void 0 : (keys) => {
|
|
2438
|
+
const value = selectState.value;
|
|
2439
|
+
if (Array.isArray(value)) selectState.setValue(removeKeysFromSelection(value, keys));
|
|
2440
|
+
}
|
|
2441
|
+
}, /* @__PURE__ */ React$1.createElement(TagList, {
|
|
2442
|
+
className: SelectField_module_default.tagList,
|
|
2443
|
+
items: tagItems,
|
|
2444
|
+
renderEmptyState: () => /* @__PURE__ */ React$1.createElement("span", {
|
|
2445
|
+
className: SelectField_module_default.valueText,
|
|
2446
|
+
"data-placeholder": placeholder ? true : void 0
|
|
2447
|
+
}, placeholder)
|
|
2448
|
+
}, (item) => /* @__PURE__ */ React$1.createElement(Tag$1, {
|
|
2449
|
+
id: item.id,
|
|
2450
|
+
textValue: item.label,
|
|
2451
|
+
className: SelectField_module_default.tag,
|
|
2452
|
+
"data-size": size === "sm" ? "sm" : "md"
|
|
2453
|
+
}, ({ allowsRemoving }) => /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, item.icon ? /* @__PURE__ */ React$1.createElement("span", {
|
|
2454
|
+
className: SelectField_module_default.tagIcon,
|
|
2455
|
+
"aria-hidden": true
|
|
2456
|
+
}, /* @__PURE__ */ React$1.createElement(item.icon, { size: "xs" })) : null, /* @__PURE__ */ React$1.createElement("span", { className: SelectField_module_default.tagLabel }, item.label), allowsRemoving ? /* @__PURE__ */ React$1.createElement(Button$1, {
|
|
2457
|
+
slot: "remove",
|
|
2458
|
+
className: SelectField_module_default.tagRemove,
|
|
2459
|
+
"aria-label": "Delete",
|
|
2460
|
+
excludeFromTabOrder: true
|
|
2461
|
+
}, /* @__PURE__ */ React$1.createElement(CloseOutlined, { size: "xs" })) : null))));
|
|
2462
|
+
})), /* @__PURE__ */ React$1.createElement(SelectFieldTriggerButton, {
|
|
2463
|
+
appearance,
|
|
2464
|
+
buttonRef: openButtonRef,
|
|
2465
|
+
className: SelectField_module_default.multipleOpenButton,
|
|
2466
|
+
isDisabled: disabled,
|
|
2467
|
+
"aria-required": required || void 0
|
|
2468
|
+
}, /* @__PURE__ */ React$1.createElement("span", { className: SelectField_module_default.trailingSlot }, /* @__PURE__ */ React$1.createElement(SelectFieldIndicators, { appearance }))));
|
|
2469
|
+
}
|
|
2470
|
+
function SelectFieldItem(props) {
|
|
2471
|
+
const { id, textValue, isDisabled, indent: indentProp, value, children } = props;
|
|
2472
|
+
const indentFromSectionHeader = React$1.useContext(SelectFieldSectionIndentContext);
|
|
2473
|
+
const indent = indentProp !== void 0 ? indentProp : indentFromSectionHeader;
|
|
2474
|
+
return /* @__PURE__ */ React$1.createElement(ListBoxItem, {
|
|
2475
|
+
id,
|
|
2476
|
+
value,
|
|
2477
|
+
textValue: textValue || getItemLabelFromNode(children),
|
|
2478
|
+
isDisabled,
|
|
2479
|
+
className: SelectField_module_default.item,
|
|
2480
|
+
"data-indent": indent || void 0
|
|
2481
|
+
}, ({ isSelected, selectionMode }) => /* @__PURE__ */ React$1.createElement("div", { className: SelectField_module_default.itemContent }, selectionMode === "multiple" ? /* @__PURE__ */ React$1.createElement("span", {
|
|
2482
|
+
className: SelectField_module_default.itemCheck,
|
|
2483
|
+
"data-selected": isSelected || void 0,
|
|
2484
|
+
"aria-hidden": true
|
|
2485
|
+
}, isSelected ? /* @__PURE__ */ React$1.createElement(CheckOutlined, { size: "sm" }) : null) : null, typeof children === "string" ? /* @__PURE__ */ React$1.createElement(Text, { slot: "label" }, children) : children));
|
|
2486
|
+
}
|
|
2487
|
+
function SelectFieldHeader(props) {
|
|
2488
|
+
const { id, label = "Header", FORCE__className: classNameOverride, children } = props;
|
|
2489
|
+
return /* @__PURE__ */ React$1.createElement(Header, {
|
|
2490
|
+
id,
|
|
2491
|
+
className: clsx(SelectField_module_default.header, classNameOverride)
|
|
2492
|
+
}, children ?? label);
|
|
2493
|
+
}
|
|
2494
|
+
SelectFieldHeader.displayName = "SelectField.Header";
|
|
2495
|
+
function isSelectFieldHeaderElement(child) {
|
|
2496
|
+
return React$1.isValidElement(child) && child.type === SelectFieldHeader;
|
|
2497
|
+
}
|
|
2498
|
+
function SelectFieldSection(props) {
|
|
2499
|
+
const { children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, FORCE__className: classNameOverride, className, ...rest } = props;
|
|
2500
|
+
const autoHeaderId = React$1.useId();
|
|
2501
|
+
const childArray = React$1.Children.toArray(children);
|
|
2502
|
+
let headerIndex = -1;
|
|
2503
|
+
for (let i = 0; i < childArray.length; i++) if (isSelectFieldHeaderElement(childArray[i])) {
|
|
2504
|
+
headerIndex = i;
|
|
2505
|
+
break;
|
|
2506
|
+
}
|
|
2507
|
+
const hasHeader = headerIndex >= 0;
|
|
2508
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2509
|
+
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.");
|
|
2510
|
+
}
|
|
2511
|
+
const labelledBy = hasHeader ? ariaLabelledBy ?? autoHeaderId : ariaLabelledBy;
|
|
2512
|
+
const effectiveAriaLabel = hasHeader ? void 0 : ariaLabel;
|
|
2513
|
+
const resolvedChildren = hasHeader && headerIndex >= 0 ? childArray.map((child, i) => {
|
|
2514
|
+
if (i === headerIndex && isSelectFieldHeaderElement(child)) return React$1.cloneElement(child, { id: child.props.id ?? autoHeaderId });
|
|
2515
|
+
return child;
|
|
2516
|
+
}) : children;
|
|
2517
|
+
return /* @__PURE__ */ React$1.createElement(SelectFieldSectionIndentContext.Provider, { value: hasHeader }, /* @__PURE__ */ React$1.createElement(ListBoxSection, {
|
|
2518
|
+
"aria-label": effectiveAriaLabel,
|
|
2519
|
+
"aria-labelledby": labelledBy,
|
|
2520
|
+
className: clsx(SelectField_module_default.section, className, classNameOverride),
|
|
2521
|
+
...rest
|
|
2522
|
+
}, resolvedChildren));
|
|
2523
|
+
}
|
|
2524
|
+
SelectFieldSection.displayName = "SelectField.Section";
|
|
2525
|
+
function defaultSelectFieldItemRenderer(item) {
|
|
2526
|
+
if (isDefaultSection(item)) {
|
|
2527
|
+
const { id, label, "aria-label": ariaLabel, children } = item;
|
|
2528
|
+
return /* @__PURE__ */ React$1.createElement(SelectFieldSection, {
|
|
2529
|
+
key: String(id),
|
|
2530
|
+
"aria-label": label ? void 0 : ariaLabel
|
|
2531
|
+
}, label ? /* @__PURE__ */ React$1.createElement(SelectFieldHeader, { label }) : null, /* @__PURE__ */ React$1.createElement(Collection, { items: children }, (child) => defaultSelectFieldItemRenderer(child)));
|
|
2532
|
+
}
|
|
2533
|
+
const Icon = item.icon;
|
|
2534
|
+
return /* @__PURE__ */ React$1.createElement(SelectFieldItem, {
|
|
2535
|
+
id: item.id,
|
|
2536
|
+
textValue: item.label
|
|
2537
|
+
}, Icon ? /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement(Icon, { size: "sm" }), /* @__PURE__ */ React$1.createElement(Text, { slot: "label" }, item.label)) : item.label);
|
|
2538
|
+
}
|
|
2539
|
+
function SelectFieldLabel(props) {
|
|
2540
|
+
const { children, required } = props;
|
|
2541
|
+
const { elementType: _elementType, ...labelContextWithoutElementType } = useSlottedContext(LabelContext) ?? {};
|
|
2542
|
+
return /* @__PURE__ */ React$1.createElement(LabelContext.Provider, { value: labelContextWithoutElementType }, /* @__PURE__ */ React$1.createElement(Label, { required }, children));
|
|
2543
|
+
}
|
|
2544
|
+
function AutocompleteTextInput(props) {
|
|
2545
|
+
const { placeholder, shouldFocus, size } = props;
|
|
2546
|
+
const ref = React$1.useRef(null);
|
|
2547
|
+
const [mergedProps, mergedRef] = useContextProps({
|
|
2548
|
+
"aria-label": props["aria-label"],
|
|
2549
|
+
placeholder,
|
|
2550
|
+
type: "search"
|
|
2551
|
+
}, ref, FieldInputContext);
|
|
2552
|
+
const { onChange, value, ...inputProps } = mergedProps;
|
|
2553
|
+
const inputRef = mergedRef;
|
|
2554
|
+
React$1.useLayoutEffect(() => {
|
|
2555
|
+
if (!shouldFocus) return;
|
|
2556
|
+
const input = inputRef.current;
|
|
2557
|
+
if (!input) return;
|
|
2558
|
+
requestAnimationFrame(() => {
|
|
2559
|
+
try {
|
|
2560
|
+
input.focus({ preventScroll: true });
|
|
2561
|
+
} catch {}
|
|
2562
|
+
});
|
|
2563
|
+
}, [inputRef, shouldFocus]);
|
|
2564
|
+
return /* @__PURE__ */ React$1.createElement(TextInput, {
|
|
2565
|
+
...inputProps,
|
|
2566
|
+
ref: inputRef,
|
|
2567
|
+
size,
|
|
2568
|
+
value: typeof value === "string" ? value : "",
|
|
2569
|
+
onChange: (event) => {
|
|
2570
|
+
onChange?.(event.target.value);
|
|
2571
|
+
}
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2574
|
+
function SelectFieldInner(props, ref) {
|
|
2575
|
+
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;
|
|
2576
|
+
const [searchValue, setSearchValue] = React$1.useState("");
|
|
2577
|
+
const [popoverWidth, setPopoverWidth] = React$1.useState();
|
|
2578
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React$1.useState(Boolean(defaultOpen));
|
|
2579
|
+
const isPopoverOpen = isOpen ?? uncontrolledOpen;
|
|
2580
|
+
const { contains } = useFilter({ sensitivity: "base" });
|
|
2581
|
+
const [anchorRef, width, offset] = useAnchorWidth([
|
|
2582
|
+
canSearch,
|
|
2583
|
+
selectionMode,
|
|
2584
|
+
size
|
|
2585
|
+
]);
|
|
2586
|
+
const multipleTriggerRef = React$1.useRef(null);
|
|
2587
|
+
const selectedItemsLabel = label ? `Selected ${label}` : ariaLabel ?? "Selected items";
|
|
2588
|
+
React$1.useImperativeHandle(ref, () => anchorRef.current, [anchorRef]);
|
|
2589
|
+
React$1.useLayoutEffect(() => {
|
|
2590
|
+
const trigger = multipleTriggerRef.current ?? anchorRef.current;
|
|
2591
|
+
if (selectionMode !== "multiple" || !isPopoverOpen || popoverWidth || !trigger) return;
|
|
2592
|
+
setPopoverWidth(`${trigger.offsetWidth}px`);
|
|
2593
|
+
}, [
|
|
2594
|
+
isPopoverOpen,
|
|
2595
|
+
popoverWidth,
|
|
2596
|
+
selectionMode,
|
|
2597
|
+
width,
|
|
2598
|
+
anchorRef
|
|
2599
|
+
]);
|
|
2600
|
+
const itemList = React$1.useMemo(() => items ? Array.from(items) : void 0, [items]);
|
|
2601
|
+
const resolvedChildren = children ?? (itemList ? defaultSelectFieldItemRenderer : void 0);
|
|
2602
|
+
const handleOpenChange = React$1.useCallback((nextOpen) => {
|
|
2603
|
+
if (isOpen === void 0) setUncontrolledOpen(nextOpen);
|
|
2604
|
+
if (selectionMode === "multiple" && !nextOpen) setPopoverWidth(void 0);
|
|
2605
|
+
if (!nextOpen) setSearchValue("");
|
|
2606
|
+
onOpenChange?.(nextOpen);
|
|
2607
|
+
}, [
|
|
2608
|
+
isOpen,
|
|
2609
|
+
onOpenChange,
|
|
2610
|
+
selectionMode
|
|
2611
|
+
]);
|
|
2612
|
+
const dropdownWidth = selectionMode === "multiple" ? popoverWidth ?? width ?? void 0 : width ?? void 0;
|
|
2613
|
+
const listBoxSearchProps = canSearch ? {
|
|
2614
|
+
autoFocus: false,
|
|
2615
|
+
renderEmptyState: () => /* @__PURE__ */ React$1.createElement("span", { className: SelectField_module_default.emptyState }, "No results")
|
|
2616
|
+
} : {};
|
|
2617
|
+
const listBox = /* @__PURE__ */ React$1.createElement(ListBox, {
|
|
2618
|
+
...listBoxSearchProps,
|
|
2619
|
+
className: SelectField_module_default.listbox,
|
|
2620
|
+
"data-selection-mode": selectionMode,
|
|
2621
|
+
items: itemList
|
|
2622
|
+
}, resolvedChildren);
|
|
2623
|
+
const popoverContent = canSearch ? /* @__PURE__ */ React$1.createElement(Autocomplete, {
|
|
2624
|
+
filter: contains,
|
|
2625
|
+
inputValue: searchValue,
|
|
2626
|
+
onInputChange: setSearchValue
|
|
2627
|
+
}, /* @__PURE__ */ React$1.createElement("div", { className: SelectField_module_default.search }, /* @__PURE__ */ React$1.createElement(AutocompleteTextInput, {
|
|
2628
|
+
"aria-label": searchPlaceholder || "Search",
|
|
2629
|
+
placeholder: searchPlaceholder || "Search",
|
|
2630
|
+
shouldFocus: isPopoverOpen,
|
|
2631
|
+
size
|
|
2632
|
+
})), listBox) : listBox;
|
|
2633
|
+
const selectContent = /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement("div", { className: fieldLayout_module_default.labelRow }, /* @__PURE__ */ React$1.createElement(SelectFieldLabel, { required }, label)), /* @__PURE__ */ React$1.createElement("div", { className: fieldLayout_module_default.fieldContent }, /* @__PURE__ */ React$1.createElement(SelectFieldTrigger, {
|
|
2634
|
+
appearance,
|
|
2635
|
+
disabled,
|
|
2636
|
+
leadingSlot,
|
|
2637
|
+
placeholder,
|
|
2638
|
+
required,
|
|
2639
|
+
selectedItemsLabel,
|
|
2640
|
+
size,
|
|
2641
|
+
triggerRef: selectionMode === "multiple" ? multipleTriggerRef : void 0
|
|
2642
|
+
}), /* @__PURE__ */ React$1.createElement(HelperText, {
|
|
2643
|
+
appearance,
|
|
2644
|
+
disabled
|
|
2645
|
+
}, helperText)), /* @__PURE__ */ React$1.createElement(Popover$1, {
|
|
2646
|
+
className: SelectField_module_default.dropdownPanel,
|
|
2647
|
+
offset: 2,
|
|
2648
|
+
crossOffset: offset,
|
|
2649
|
+
triggerRef: selectionMode === "multiple" ? multipleTriggerRef : void 0,
|
|
2650
|
+
style: { width: shouldAutoSizeDropdown ? dropdownWidth : void 0 }
|
|
2651
|
+
}, popoverContent));
|
|
2652
|
+
if (props.selectionMode === "multiple") {
|
|
2653
|
+
const handleChange = (nextValue) => {
|
|
2654
|
+
props.onChange?.(new Set(nextValue));
|
|
2655
|
+
};
|
|
2656
|
+
return /* @__PURE__ */ React$1.createElement(Select, {
|
|
2657
|
+
id,
|
|
2658
|
+
ref: anchorRef,
|
|
2659
|
+
name,
|
|
2660
|
+
className: clsx(fieldLayout_module_default.field, classNameOverride),
|
|
2661
|
+
"data-capra-field-root": "",
|
|
2662
|
+
"data-layout": layout,
|
|
2663
|
+
isDisabled: disabled,
|
|
2664
|
+
isRequired: required,
|
|
2665
|
+
isInvalid: appearance === "danger",
|
|
2666
|
+
validationBehavior: "aria",
|
|
2667
|
+
placeholder,
|
|
2668
|
+
selectionMode: "multiple",
|
|
2669
|
+
disabledKeys,
|
|
2670
|
+
value: normalizeIterable(props.value),
|
|
2671
|
+
defaultValue: normalizeIterable(props.defaultValue),
|
|
2672
|
+
onChange: handleChange,
|
|
2673
|
+
isOpen,
|
|
2674
|
+
defaultOpen,
|
|
2675
|
+
onOpenChange: handleOpenChange,
|
|
2676
|
+
autoFocus,
|
|
2677
|
+
"aria-label": ariaLabel,
|
|
2678
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2679
|
+
"aria-describedby": ariaDescribedBy
|
|
2680
|
+
}, selectContent);
|
|
2681
|
+
}
|
|
2682
|
+
const handleChange = (nextValue) => {
|
|
2683
|
+
props.onChange?.(nextValue ?? null);
|
|
2684
|
+
};
|
|
2685
|
+
return /* @__PURE__ */ React$1.createElement(Select, {
|
|
2686
|
+
id,
|
|
2687
|
+
ref: anchorRef,
|
|
2688
|
+
name,
|
|
2689
|
+
className: clsx(fieldLayout_module_default.field, classNameOverride),
|
|
2690
|
+
"data-capra-field-root": "",
|
|
2691
|
+
"data-layout": layout,
|
|
2692
|
+
isDisabled: disabled,
|
|
2693
|
+
isRequired: required,
|
|
2694
|
+
isInvalid: appearance === "danger",
|
|
2695
|
+
validationBehavior: "aria",
|
|
2696
|
+
placeholder,
|
|
2697
|
+
selectionMode: "single",
|
|
2698
|
+
disabledKeys,
|
|
2699
|
+
value: props.value,
|
|
2700
|
+
defaultValue: props.defaultValue,
|
|
2701
|
+
onChange: handleChange,
|
|
2702
|
+
isOpen,
|
|
2703
|
+
defaultOpen,
|
|
2704
|
+
onOpenChange: handleOpenChange,
|
|
2705
|
+
autoFocus,
|
|
2706
|
+
"aria-label": ariaLabel,
|
|
2707
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2708
|
+
"aria-describedby": ariaDescribedBy
|
|
2709
|
+
}, selectContent);
|
|
2710
|
+
}
|
|
2711
|
+
const SelectFieldRoot = React$1.forwardRef(SelectFieldInner);
|
|
2712
|
+
/**
|
|
2713
|
+
* Composed select field with Capra label/helper text layout, single and multiple selection, and an optional popover search input.
|
|
2714
|
+
*/
|
|
2715
|
+
const SelectField = Object.assign(SelectFieldRoot, {
|
|
2716
|
+
Item: SelectFieldItem,
|
|
2717
|
+
Header: SelectFieldHeader,
|
|
2718
|
+
Section: SelectFieldSection
|
|
2719
|
+
});
|
|
2720
|
+
//#endregion
|
|
2293
2721
|
//#region src/components/DateRangePickerField/DateRangePickerField.module.css
|
|
2294
2722
|
var DateRangePickerField_module_default = {
|
|
2295
2723
|
"cell": "capra-DateRangePickerField-module-QpPhpG-cell",
|
|
@@ -5169,4 +5597,4 @@ function Tree({ FORCE__className: classNameOverride, items, selectionMode = "mul
|
|
|
5169
5597
|
}, /* @__PURE__ */ React$1.createElement(Collection, { items }, renderTreeItem)));
|
|
5170
5598
|
}
|
|
5171
5599
|
//#endregion
|
|
5172
|
-
export { Alert, Anchor, AutocompleteField, Badge, BadgeLayout, Breadcrumb, Breadcrumbs, Button, ButtonLink, Card, Checkbox, Collapse, CustomTooltipTrigger, DatePickerField, DateRangePickerField, Divider, Drawer, EmptyState, IconButton, InputRow, Label, Link, ListItem, Menu, Modal, NumberField, Pagination, PasswordField, Pill, Popover, Radio, RadioGroup, RadioTile, Ribbon, RouterProvider, SKELETON_SIZE, SKELETON_SIZE_TOKENS, Skeleton, SkeletonGroup, Spinner, Switch, TabNav, Tag, Text, TextArea, TextField, Toast, Tooltip, TopNav, Tree, VerticalNavigation, VisuallyHidden, submenuPanelClassName, tagColors };
|
|
5600
|
+
export { Alert, Anchor, AutocompleteField, Badge, BadgeLayout, Breadcrumb, Breadcrumbs, Button, ButtonLink, Card, Checkbox, Collapse, CustomTooltipTrigger, DatePickerField, DateRangePickerField, Divider, Drawer, EmptyState, IconButton, InputRow, Label, Link, ListItem, Menu, Modal, NumberField, Pagination, PasswordField, Pill, Popover, Radio, RadioGroup, RadioTile, Ribbon, RouterProvider, SKELETON_SIZE, SKELETON_SIZE_TOKENS, SelectField, Skeleton, SkeletonGroup, Spinner, Switch, TabNav, Tag, Text, TextArea, TextField, Toast, Tooltip, TopNav, Tree, VerticalNavigation, VisuallyHidden, submenuPanelClassName, tagColors };
|