@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.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as React$1 from "react";
2
- import React, { Suspense, useCallback, useState } from "react";
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-GZD11W-field",
327
- "fieldContent": "capra-fieldLayout-module-GZD11W-fieldContent",
328
- "labelRow": "capra-fieldLayout-module-GZD11W-labelRow"
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-16LYpW-switch" };
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 };