@capra/core 1.8.2 → 1.10.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.
Files changed (50) hide show
  1. package/dist/index.cjs +294 -46
  2. package/dist/index.d.cts +132 -20
  3. package/dist/index.d.mts +132 -20
  4. package/dist/index.mjs +295 -49
  5. package/dist/style.css +251 -72
  6. package/docs/core-alert--usage.md +2 -0
  7. package/docs/core-anchor--usage.md +2 -0
  8. package/docs/core-autocompletefield--usage.md +2 -0
  9. package/docs/core-badge--design.md +10 -5
  10. package/docs/core-badge--usage.md +5 -2
  11. package/docs/core-breadcrumbs--usage.md +2 -0
  12. package/docs/core-button--usage.md +2 -0
  13. package/docs/core-buttonlink--usage.md +2 -0
  14. package/docs/core-checkbox--usage.md +2 -0
  15. package/docs/core-collapse--usage.md +2 -0
  16. package/docs/core-datepickerfield--usage.md +2 -0
  17. package/docs/core-daterangepickerfield--usage.md +2 -0
  18. package/docs/core-divider--usage.md +2 -0
  19. package/docs/core-emptystate--usage.md +2 -0
  20. package/docs/core-helpertext--usage.md +2 -0
  21. package/docs/core-iconbutton--usage.md +2 -0
  22. package/docs/core-inputrow--usage.md +2 -0
  23. package/docs/core-label--usage.md +2 -0
  24. package/docs/core-link--usage.md +2 -0
  25. package/docs/core-listitem--usage.md +2 -0
  26. package/docs/core-menu--usage.md +2 -0
  27. package/docs/core-modal--usage.md +2 -0
  28. package/docs/core-pagination--usage.md +2 -0
  29. package/docs/core-pill--usage.md +2 -0
  30. package/docs/core-radio--usage.md +2 -0
  31. package/docs/core-radiogroup--usage.md +2 -0
  32. package/docs/core-radiotile--usage.md +2 -0
  33. package/docs/core-ribbon--usage.md +2 -0
  34. package/docs/core-skeleton--usage.md +1 -2
  35. package/docs/core-skeletongroup--usage.md +0 -1
  36. package/docs/core-spinner--usage.md +2 -0
  37. package/docs/core-switch--usage.md +2 -0
  38. package/docs/core-tabnav--usage.md +2 -0
  39. package/docs/core-tag--usage.md +2 -0
  40. package/docs/core-text--usage.md +2 -0
  41. package/docs/core-textarea--usage.md +2 -0
  42. package/docs/core-textinput--usage.md +2 -0
  43. package/docs/core-tooltip--usage.md +2 -0
  44. package/docs/core-topnav--usage.md +2 -0
  45. package/docs/core-tree--design.md +31 -0
  46. package/docs/core-tree--usage.md +102 -0
  47. package/docs/core-verticalnavigation--usage.md +2 -0
  48. package/docs/history-changelogs-capra-core--docs.md +34 -0
  49. package/docs/index.md +2 -0
  50. package/package.json +7 -7
package/dist/index.cjs CHANGED
@@ -252,7 +252,7 @@ const VisuallyHidden = ({ children, ...props }) => {
252
252
  //#endregion
253
253
  //#region src/components/input-helpers/Label.tsx
254
254
  /** Label text and optional required indicator for form fields, aligned with Capra field layouts. */
255
- const Label$1 = react.forwardRef((props, ref) => {
255
+ const Label = react.forwardRef((props, ref) => {
256
256
  const [mergedProps, mergedRef] = (0, react_aria_components.useContextProps)(props, ref, react_aria_components.LabelContext);
257
257
  const { trailingSlot, children, required, FORCE__className: classNameOverride, style, ...labelProps } = mergedProps;
258
258
  if (!children) return null;
@@ -265,7 +265,7 @@ const Label$1 = react.forwardRef((props, ref) => {
265
265
  "aria-hidden": true
266
266
  }, "*"), /* @__PURE__ */ react.createElement(VisuallyHidden, null, "This field is required"))), trailingSlot && /* @__PURE__ */ react.createElement("span", { className: Label_module_default.trailingSlot }, trailingSlot));
267
267
  });
268
- Label$1.displayName = "Label";
268
+ Label.displayName = "Label";
269
269
  //#endregion
270
270
  //#region src/components/TextInput/TextInput.module.css
271
271
  var TextInput_module_default = {
@@ -395,7 +395,7 @@ function AutocompleteFieldWithoutRef(props, ref) {
395
395
  id,
396
396
  shouldFocusWrap: true,
397
397
  ref: comboboxRef
398
- }, /* @__PURE__ */ react.default.createElement(Label$1, null, label), /* @__PURE__ */ react.default.createElement(TextInput, {
398
+ }, /* @__PURE__ */ react.default.createElement(Label, null, label), /* @__PURE__ */ react.default.createElement(TextInput, {
399
399
  ...inputProps,
400
400
  ref,
401
401
  trailingSlot: trailingContent
@@ -577,15 +577,15 @@ const Card = Object.assign(CardRoot, {
577
577
  //#endregion
578
578
  //#region src/components/Badge/Badge.module.css
579
579
  var Badge_module_default = {
580
- "badge": "capra-Badge-module-yecu4W-badge",
581
- "base": "capra-Badge-module-yecu4W-base"
580
+ "badge": "capra-Badge-module-_3WihW-badge",
581
+ "base": "capra-Badge-module-_3WihW-base"
582
582
  };
583
583
  //#endregion
584
584
  //#region src/components/Badge/Badge.tsx
585
585
  /**
586
586
  * Badges display an indicator/counter on an associated component.
587
587
  */
588
- function Badge({ appearance = "danger", variant, count = 0, showZero = false, overflowCount = 99, FORCE__className, ...props }) {
588
+ function Badge({ appearance = "danger", variant = "counter", size = "md", count = 0, showZero = false, overflowCount = 99, FORCE__className, style, ...props }) {
589
589
  if (variant === "counter" && !showZero && !count) return null;
590
590
  const getBadgeContent = () => {
591
591
  if (variant === "dot") return null;
@@ -593,43 +593,55 @@ function Badge({ appearance = "danger", variant, count = 0, showZero = false, ov
593
593
  return value > overflowCount ? `${overflowCount}+` : value;
594
594
  };
595
595
  return /* @__PURE__ */ react.createElement("span", {
596
- role: "status",
597
596
  className: clsx(Badge_module_default.badge, FORCE__className),
598
597
  "data-appearance": appearance,
598
+ "data-size": size,
599
599
  "data-variant": variant,
600
+ style,
600
601
  ...props
601
602
  }, getBadgeContent());
602
603
  }
603
604
  /**
604
605
  * A convenience component allowing you to easily attach a badge to another component.
605
606
  */
606
- function BadgeLayout({ children }) {
607
- return /* @__PURE__ */ react.createElement("div", { className: Badge_module_default.base }, children);
607
+ function BadgeLayout({ children, offset = [0, 0] }) {
608
+ return /* @__PURE__ */ react.createElement("div", {
609
+ className: Badge_module_default.base,
610
+ style: {
611
+ "--_badge-offset-x": `${offset[0]}px`,
612
+ "--_badge-offset-y": `${offset[1]}px`
613
+ }
614
+ }, children);
608
615
  }
609
616
  //#endregion
610
617
  //#region src/components/ListItem/ListItem.module.css
611
618
  var ListItem_module_default = {
612
- "content": "capra-ListItem-module-VUh15W-content",
613
- "description": "capra-ListItem-module-VUh15W-description",
614
- "label": "capra-ListItem-module-VUh15W-label",
615
- "leading": "capra-ListItem-module-VUh15W-leading",
616
- "listItem": "capra-ListItem-module-VUh15W-listItem",
617
- "slot": "capra-ListItem-module-VUh15W-slot",
618
- "slots": "capra-ListItem-module-VUh15W-slots",
619
- "suffix": "capra-ListItem-module-VUh15W-suffix",
620
- "trailing": "capra-ListItem-module-VUh15W-trailing"
619
+ "__listItem-layout": "capra-ListItem-module-QN6vFW-__listItem-layout",
620
+ "content": "capra-ListItem-module-QN6vFW-content",
621
+ "description": "capra-ListItem-module-QN6vFW-description",
622
+ "label": "capra-ListItem-module-QN6vFW-label",
623
+ "leading": "capra-ListItem-module-QN6vFW-leading",
624
+ "listItem": "capra-ListItem-module-QN6vFW-listItem capra-ListItem-module-QN6vFW-__listItem-layout",
625
+ "slot": "capra-ListItem-module-QN6vFW-slot",
626
+ "slots": "capra-ListItem-module-QN6vFW-slots",
627
+ "suffix": "capra-ListItem-module-QN6vFW-suffix",
628
+ "trailing": "capra-ListItem-module-QN6vFW-trailing"
621
629
  };
622
630
  //#endregion
623
631
  //#region src/components/ListItem/ListItemSlots.tsx
632
+ const CollapsedSlot = "__CollapsedSlot__";
624
633
  const ListItemSlots = ({ children, trailing = false, FORCE__className }) => {
625
634
  if (react.default.Children.count(children) === 0) return null;
626
635
  return /* @__PURE__ */ react.default.createElement("div", {
627
636
  className: clsx(ListItem_module_default.slots, FORCE__className),
628
637
  "data-trailing": trailing || void 0
629
- }, react.default.Children.map(children, (child, index) => /* @__PURE__ */ react.default.createElement("div", {
630
- key: index,
631
- className: ListItem_module_default.slot
632
- }, child)));
638
+ }, react.default.Children.map(children, (child, index) => {
639
+ if (child === "__CollapsedSlot__") return void 0;
640
+ return /* @__PURE__ */ react.default.createElement("div", {
641
+ key: index,
642
+ className: ListItem_module_default.slot
643
+ }, child);
644
+ }));
633
645
  };
634
646
  //#endregion
635
647
  //#region src/components/ListItem/ListItem.tsx
@@ -652,7 +664,7 @@ const Trailing = ({ children, FORCE__className }) => {
652
664
  const Content = ({ children, FORCE__className }) => {
653
665
  return /* @__PURE__ */ react.createElement("div", { className: clsx(ListItem_module_default.content, FORCE__className) }, children);
654
666
  };
655
- const Label = ({ children, id }) => {
667
+ const Label$1 = ({ children, id }) => {
656
668
  return /* @__PURE__ */ react.createElement("div", {
657
669
  id,
658
670
  className: ListItem_module_default.label
@@ -671,7 +683,7 @@ const Spacer = () => {
671
683
  });
672
684
  };
673
685
  ListItem.Content = Content;
674
- ListItem.Label = Label;
686
+ ListItem.Label = Label$1;
675
687
  ListItem.Description = Description;
676
688
  ListItem.Suffix = Suffix;
677
689
  ListItem.Spacer = Spacer;
@@ -1112,7 +1124,7 @@ const TextField = react.forwardRef((props, ref) => {
1112
1124
  className: fieldLayout_module_default.field,
1113
1125
  "data-capra-field-root": "",
1114
1126
  "data-layout": layout
1115
- }, /* @__PURE__ */ react.createElement(Label$1, { required }, label), /* @__PURE__ */ react.createElement(TextInput, {
1127
+ }, /* @__PURE__ */ react.createElement(Label, { required }, label), /* @__PURE__ */ react.createElement(TextInput, {
1116
1128
  ref,
1117
1129
  ...inputRest,
1118
1130
  appearance,
@@ -1216,7 +1228,7 @@ const NumberField = react.forwardRef((props, ref) => {
1216
1228
  className: fieldLayout_module_default.field,
1217
1229
  "data-capra-field-root": "",
1218
1230
  "data-layout": layout
1219
- }, /* @__PURE__ */ react.createElement(Label$1, { required }, label), /* @__PURE__ */ react.createElement(react_aria_components.Group, {
1231
+ }, /* @__PURE__ */ react.createElement(Label, { required }, label), /* @__PURE__ */ react.createElement(react_aria_components.Group, {
1220
1232
  "data-capra-text-input": "",
1221
1233
  "data-size": size,
1222
1234
  className: clsx(TextInput_module_default.wrapper, NumberField_module_default.withStepper, classNameOverride)
@@ -2232,7 +2244,7 @@ function DatePickerFieldInner(props, ref) {
2232
2244
  isInvalid,
2233
2245
  shouldForceLeadingZeros: true,
2234
2246
  validationBehavior: "aria"
2235
- }, /* @__PURE__ */ react.createElement(Label$1, { required }, label), /* @__PURE__ */ react.createElement(DatePickerFieldRow, {
2247
+ }, /* @__PURE__ */ react.createElement(Label, { required }, label), /* @__PURE__ */ react.createElement(DatePickerFieldRow, {
2236
2248
  appearance,
2237
2249
  size,
2238
2250
  leadingSlot,
@@ -2474,7 +2486,7 @@ function DateRangePickerFieldInner(props, ref) {
2474
2486
  isInvalid,
2475
2487
  shouldForceLeadingZeros: true,
2476
2488
  validationBehavior: "aria"
2477
- }, /* @__PURE__ */ react.createElement(Label$1, { required }, label), /* @__PURE__ */ react.createElement(DateRangePickerFieldRow, {
2489
+ }, /* @__PURE__ */ react.createElement(Label, { required }, label), /* @__PURE__ */ react.createElement(DateRangePickerFieldRow, {
2478
2490
  appearance,
2479
2491
  size,
2480
2492
  leadingSlot,
@@ -2703,7 +2715,7 @@ const TextArea = react.forwardRef((props, ref) => {
2703
2715
  ...ariaFieldProps,
2704
2716
  className: fieldLayout_module_default.field,
2705
2717
  "data-layout": layout
2706
- }, /* @__PURE__ */ react.createElement(Label$1, { required }, label), /* @__PURE__ */ react.createElement("div", {
2718
+ }, /* @__PURE__ */ react.createElement(Label, { required }, label), /* @__PURE__ */ react.createElement("div", {
2707
2719
  className: clsx(TextArea_module_default.wrapper, classNameOverride),
2708
2720
  "data-has-indicator": hasIndicator,
2709
2721
  "data-autosize": autoSizeActive,
@@ -4380,23 +4392,23 @@ const submenuPanelClassName = Menu_module_default.menu;
4380
4392
  //#endregion
4381
4393
  //#region src/components/TabNav/TabNav.module.css
4382
4394
  var TabNav_module_default = {
4383
- "dropdownIcon": "capra-TabNav-module-qqfvea-dropdownIcon",
4384
- "extraContent": "capra-TabNav-module-qqfvea-extraContent",
4385
- "indentSpacer": "capra-TabNav-module-qqfvea-indentSpacer",
4386
- "panel": "capra-TabNav-module-qqfvea-panel",
4387
- "root": "capra-TabNav-module-qqfvea-root",
4388
- "subMenu": "capra-TabNav-module-qqfvea-subMenu",
4389
- "subMenuItem": "capra-TabNav-module-qqfvea-subMenuItem",
4390
- "subMenuItemActive": "capra-TabNav-module-qqfvea-subMenuItemActive",
4391
- "subTab": "capra-TabNav-module-qqfvea-subTab",
4392
- "subTabList": "capra-TabNav-module-qqfvea-subTabList",
4393
- "subTabListItem": "capra-TabNav-module-qqfvea-subTabListItem",
4394
- "tab": "capra-TabNav-module-qqfvea-tab",
4395
- "tabBar": "capra-TabNav-module-qqfvea-tabBar",
4396
- "tabGroup": "capra-TabNav-module-qqfvea-tabGroup",
4397
- "tabIcon": "capra-TabNav-module-qqfvea-tabIcon",
4398
- "tabLabel": "capra-TabNav-module-qqfvea-tabLabel",
4399
- "tabList": "capra-TabNav-module-qqfvea-tabList"
4395
+ "dropdownIcon": "capra-TabNav-module-pLDWhG-dropdownIcon",
4396
+ "extraContent": "capra-TabNav-module-pLDWhG-extraContent",
4397
+ "indentSpacer": "capra-TabNav-module-pLDWhG-indentSpacer",
4398
+ "panel": "capra-TabNav-module-pLDWhG-panel",
4399
+ "root": "capra-TabNav-module-pLDWhG-root",
4400
+ "subMenu": "capra-TabNav-module-pLDWhG-subMenu",
4401
+ "subMenuItem": "capra-TabNav-module-pLDWhG-subMenuItem",
4402
+ "subMenuItemActive": "capra-TabNav-module-pLDWhG-subMenuItemActive",
4403
+ "subTab": "capra-TabNav-module-pLDWhG-subTab",
4404
+ "subTabList": "capra-TabNav-module-pLDWhG-subTabList",
4405
+ "subTabListItem": "capra-TabNav-module-pLDWhG-subTabListItem",
4406
+ "tab": "capra-TabNav-module-pLDWhG-tab",
4407
+ "tabBar": "capra-TabNav-module-pLDWhG-tabBar",
4408
+ "tabGroup": "capra-TabNav-module-pLDWhG-tabGroup",
4409
+ "tabIcon": "capra-TabNav-module-pLDWhG-tabIcon",
4410
+ "tabLabel": "capra-TabNav-module-pLDWhG-tabLabel",
4411
+ "tabList": "capra-TabNav-module-pLDWhG-tabList"
4400
4412
  };
4401
4413
  //#endregion
4402
4414
  //#region src/components/TabNav/TabNav.tsx
@@ -4970,6 +4982,240 @@ function ArrowSvg() {
4970
4982
  }));
4971
4983
  }
4972
4984
  //#endregion
4985
+ //#region src/components/Tree/Tree.module.css
4986
+ var Tree_module_default = {
4987
+ "chevronButton": "capra-Tree-module--hXpBa-chevronButton",
4988
+ "chevronIcon": "capra-Tree-module--hXpBa-chevronIcon",
4989
+ "indentSpacer": "capra-Tree-module--hXpBa-indentSpacer",
4990
+ "item": "capra-Tree-module--hXpBa-item capra-ListItem-module-QN6vFW-__listItem-layout",
4991
+ "itemContent": "capra-Tree-module--hXpBa-itemContent capra-ListItem-module-QN6vFW-content",
4992
+ "itemLabel": "capra-Tree-module--hXpBa-itemLabel capra-ListItem-module-QN6vFW-label",
4993
+ "itemSuffix": "capra-Tree-module--hXpBa-itemSuffix capra-ListItem-module-QN6vFW-suffix",
4994
+ "label": "capra-Tree-module--hXpBa-label",
4995
+ "root": "capra-Tree-module--hXpBa-root",
4996
+ "selectionCheckbox": "capra-Tree-module--hXpBa-selectionCheckbox",
4997
+ "suffix": "capra-Tree-module--hXpBa-suffix"
4998
+ };
4999
+ //#endregion
5000
+ //#region src/components/Tree/Tree.tsx
5001
+ const TreeSelectionContext = react.createContext(null);
5002
+ function getTextValue(item) {
5003
+ return typeof item.label === "string" ? item.label : String(item.key);
5004
+ }
5005
+ function buildTreeIndex(items) {
5006
+ const parentByKey = /* @__PURE__ */ new Map();
5007
+ const descendantsByKey = /* @__PURE__ */ new Map();
5008
+ const selectableDescendantsByKey = /* @__PURE__ */ new Map();
5009
+ const disabledKeys = /* @__PURE__ */ new Set();
5010
+ const selectableKeys = /* @__PURE__ */ new Set();
5011
+ const visit = (item, parent) => {
5012
+ parentByKey.set(item.key, parent);
5013
+ if (item.isDisabled) disabledKeys.add(item.key);
5014
+ else selectableKeys.add(item.key);
5015
+ const descendants = [];
5016
+ const selectableDescendants = [];
5017
+ for (const child of item.children ?? []) {
5018
+ visit(child, item.key);
5019
+ descendants.push(child.key, ...descendantsByKey.get(child.key) ?? []);
5020
+ if (!child.isDisabled) selectableDescendants.push(child.key);
5021
+ for (const descendant of selectableDescendantsByKey.get(child.key) ?? []) selectableDescendants.push(descendant);
5022
+ }
5023
+ descendantsByKey.set(item.key, descendants);
5024
+ selectableDescendantsByKey.set(item.key, selectableDescendants);
5025
+ };
5026
+ for (const item of items) visit(item, null);
5027
+ return {
5028
+ parentByKey,
5029
+ descendantsByKey,
5030
+ selectableDescendantsByKey,
5031
+ disabledKeys,
5032
+ selectableKeys
5033
+ };
5034
+ }
5035
+ function sanitizeSelection(selection, index) {
5036
+ const next = /* @__PURE__ */ new Set();
5037
+ for (const key of selection) if (index.parentByKey.has(key) && !index.disabledKeys.has(key)) next.add(key);
5038
+ return next;
5039
+ }
5040
+ function reconcileParentKeys(selection, index) {
5041
+ const next = new Set(selection);
5042
+ for (const [key, selectableDescendants] of index.selectableDescendantsByKey) {
5043
+ if (selectableDescendants.length === 0) continue;
5044
+ if (!selectableDescendants.every((descendantKey) => next.has(descendantKey))) next.delete(key);
5045
+ }
5046
+ return next;
5047
+ }
5048
+ function selectionToSet(selection, index) {
5049
+ if (selection === "all") return new Set(index.selectableKeys);
5050
+ if (selection == null) return /* @__PURE__ */ new Set();
5051
+ return sanitizeSelection(selection, index);
5052
+ }
5053
+ function expandKeysWithAncestors(keys, index) {
5054
+ if (keys == null) return;
5055
+ const expanded = /* @__PURE__ */ new Set();
5056
+ for (const key of keys) {
5057
+ if (!index.parentByKey.has(key)) continue;
5058
+ let current = key;
5059
+ while (current != null) {
5060
+ expanded.add(current);
5061
+ current = index.parentByKey.get(current) ?? null;
5062
+ }
5063
+ }
5064
+ return expanded;
5065
+ }
5066
+ function getCheckboxState(key, selectedKeys, index) {
5067
+ const selectableDescendants = index.selectableDescendantsByKey.get(key) ?? [];
5068
+ if (selectableDescendants.length === 0) return {
5069
+ checked: selectedKeys.has(key),
5070
+ indeterminate: false
5071
+ };
5072
+ const selectedDescendantCount = selectableDescendants.filter((descendantKey) => selectedKeys.has(descendantKey)).length;
5073
+ const allSelectableDescendantsSelected = selectedDescendantCount === selectableDescendants.length;
5074
+ const someSelectableDescendantsSelected = selectedDescendantCount > 0;
5075
+ if (allSelectableDescendantsSelected || selectedKeys.has(key)) return {
5076
+ checked: true,
5077
+ indeterminate: false
5078
+ };
5079
+ return {
5080
+ checked: false,
5081
+ indeterminate: someSelectableDescendantsSelected
5082
+ };
5083
+ }
5084
+ function applySelectionChange(prev, next, index) {
5085
+ const cascadedSelection = sanitizeSelection(next, index);
5086
+ for (const key of next) {
5087
+ if (prev.has(key) || index.disabledKeys.has(key)) continue;
5088
+ if ((index.descendantsByKey.get(key) ?? []).length === 0) continue;
5089
+ cascadedSelection.add(key);
5090
+ for (const descendantKey of index.selectableDescendantsByKey.get(key) ?? []) cascadedSelection.add(descendantKey);
5091
+ }
5092
+ for (const key of prev) {
5093
+ if (next.has(key) || index.disabledKeys.has(key)) continue;
5094
+ if ((index.descendantsByKey.get(key) ?? []).length === 0) continue;
5095
+ cascadedSelection.delete(key);
5096
+ for (const descendantKey of index.descendantsByKey.get(key) ?? []) cascadedSelection.delete(descendantKey);
5097
+ }
5098
+ return reconcileParentKeys(cascadedSelection, index);
5099
+ }
5100
+ function TreeSelectionCheckbox({ item }) {
5101
+ const context = react.useContext(TreeSelectionContext);
5102
+ if (context?.selectionMode !== "multiple") return null;
5103
+ const checkboxState = getCheckboxState(item.key, context.selectedKeys, context.index);
5104
+ return /* @__PURE__ */ react.createElement(Checkbox, {
5105
+ "aria-checked": checkboxState.indeterminate ? "mixed" : checkboxState.checked ? "true" : "false",
5106
+ "aria-label": getTextValue(item),
5107
+ checked: checkboxState.checked,
5108
+ disabled: context.index.disabledKeys.has(item.key),
5109
+ indeterminate: checkboxState.indeterminate,
5110
+ FORCE__className: Tree_module_default.selectionCheckbox,
5111
+ onChange: (event) => {
5112
+ event.stopPropagation();
5113
+ context.toggleSelection(item.key);
5114
+ },
5115
+ onClick: (event) => {
5116
+ event.stopPropagation();
5117
+ },
5118
+ onMouseDown: (event) => {
5119
+ event.stopPropagation();
5120
+ },
5121
+ onKeyDown: (event) => {
5122
+ event.stopPropagation();
5123
+ },
5124
+ onPointerDown: (event) => {
5125
+ event.stopPropagation();
5126
+ }
5127
+ });
5128
+ }
5129
+ function renderTreeItem(item) {
5130
+ return /* @__PURE__ */ react.createElement(react_aria_components.TreeItem, {
5131
+ id: item.key,
5132
+ key: item.key,
5133
+ className: Tree_module_default.item,
5134
+ isDisabled: item.isDisabled,
5135
+ textValue: getTextValue(item)
5136
+ }, /* @__PURE__ */ react.createElement(react_aria_components.TreeItemContent, null, ({ hasChildItems, id, level, selectionMode }) => /* @__PURE__ */ react.createElement(react.Fragment, null, /* @__PURE__ */ react.createElement(ListItem.Leading, null, Array.from({ length: Math.max(level - 1, 0) }).map((_, index) => /* @__PURE__ */ react.createElement("span", {
5137
+ key: `${String(item.key)}-indent-${index}`,
5138
+ "aria-hidden": "true",
5139
+ className: Tree_module_default.indentSpacer
5140
+ })), hasChildItems ? /* @__PURE__ */ react.createElement(react_aria_components.Button, {
5141
+ slot: "chevron",
5142
+ className: Tree_module_default.chevronButton
5143
+ }, /* @__PURE__ */ react.createElement("span", {
5144
+ "aria-hidden": "true",
5145
+ className: Tree_module_default.chevronIcon
5146
+ }, /* @__PURE__ */ react.createElement(_capra_icons.CaretRight, { size: "xs" }))) : /* @__PURE__ */ react.createElement("div", null), selectionMode === "multiple" ? /* @__PURE__ */ react.createElement(TreeSelectionCheckbox, { item }) : CollapsedSlot), /* @__PURE__ */ react.createElement("div", { className: Tree_module_default.itemContent }, /* @__PURE__ */ react.createElement("div", {
5147
+ id: String(id),
5148
+ className: Tree_module_default.itemLabel
5149
+ }, item.label)), /* @__PURE__ */ react.createElement(ListItem.Trailing, null, item.suffix ? /* @__PURE__ */ react.createElement("div", { className: Tree_module_default.itemSuffix }, item.suffix) : CollapsedSlot, item.trailingSlot || "__CollapsedSlot__"))), /* @__PURE__ */ react.createElement(react_aria_components.Collection, { items: item.children }, renderTreeItem));
5150
+ }
5151
+ /**
5152
+ * A hierarchical tree with cascading multi-select and Capra ListItem row layout.
5153
+ */
5154
+ function Tree({ FORCE__className: classNameOverride, items, selectionMode = "multiple", defaultSelectedKeys, selectedKeys, onSelectionChange, expandedKeys, defaultExpandedKeys, ...props }) {
5155
+ const index = react.useMemo(() => buildTreeIndex(items), [items]);
5156
+ const resolvedExpandedKeys = react.useMemo(() => expandKeysWithAncestors(expandedKeys, index), [expandedKeys, index]);
5157
+ const resolvedDefaultExpandedKeys = react.useMemo(() => expandKeysWithAncestors(defaultExpandedKeys, index), [defaultExpandedKeys, index]);
5158
+ const [internalSelectedKeys, setInternalSelectedKeys] = react.useState(() => applySelectionChange(/* @__PURE__ */ new Set(), selectionToSet(selectedKeys ?? defaultSelectedKeys, index), index));
5159
+ react.useEffect(() => {
5160
+ const nextSelectedKeys = selectedKeys != null ? applySelectionChange(/* @__PURE__ */ new Set(), selectionToSet(selectedKeys, index), index) : reconcileParentKeys(sanitizeSelection(internalSelectedKeys, index), index);
5161
+ if (nextSelectedKeys.size !== internalSelectedKeys.size || Array.from(nextSelectedKeys).some((key) => !internalSelectedKeys.has(key))) setInternalSelectedKeys(nextSelectedKeys);
5162
+ }, [
5163
+ index,
5164
+ internalSelectedKeys,
5165
+ selectedKeys
5166
+ ]);
5167
+ const selectedKeysRef = react.useRef(internalSelectedKeys);
5168
+ selectedKeysRef.current = internalSelectedKeys;
5169
+ const commitSelection = react.useCallback((nextSelectedKeys) => {
5170
+ setInternalSelectedKeys(nextSelectedKeys);
5171
+ onSelectionChange?.(new Set(nextSelectedKeys));
5172
+ }, [onSelectionChange]);
5173
+ const toggleSelection = react.useCallback((key) => {
5174
+ if (selectionMode !== "multiple" || index.disabledKeys.has(key)) return;
5175
+ const nextSelectedKeys = new Set(selectedKeysRef.current);
5176
+ if (nextSelectedKeys.has(key)) nextSelectedKeys.delete(key);
5177
+ else nextSelectedKeys.add(key);
5178
+ commitSelection(applySelectionChange(selectedKeysRef.current, nextSelectedKeys, index));
5179
+ }, [
5180
+ commitSelection,
5181
+ index,
5182
+ selectionMode
5183
+ ]);
5184
+ const handleSelectionChange = react.useCallback((nextSelection) => {
5185
+ if (selectionMode !== "multiple") {
5186
+ commitSelection(selectionToSet(nextSelection, index));
5187
+ return;
5188
+ }
5189
+ commitSelection(applySelectionChange(selectedKeysRef.current, selectionToSet(nextSelection, index), index));
5190
+ }, [
5191
+ commitSelection,
5192
+ index,
5193
+ selectionMode
5194
+ ]);
5195
+ const selectionContext = react.useMemo(() => ({
5196
+ index,
5197
+ selectedKeys: internalSelectedKeys,
5198
+ selectionMode,
5199
+ toggleSelection
5200
+ }), [
5201
+ index,
5202
+ internalSelectedKeys,
5203
+ selectionMode,
5204
+ toggleSelection
5205
+ ]);
5206
+ return /* @__PURE__ */ react.createElement(TreeSelectionContext.Provider, { value: selectionContext }, /* @__PURE__ */ react.createElement(react_aria_components.Tree, {
5207
+ ...props,
5208
+ selectionBehavior: "toggle",
5209
+ className: clsx(Tree_module_default.root, classNameOverride),
5210
+ items,
5211
+ selectedKeys: internalSelectedKeys,
5212
+ selectionMode,
5213
+ onSelectionChange: handleSelectionChange,
5214
+ expandedKeys: resolvedExpandedKeys,
5215
+ defaultExpandedKeys: resolvedDefaultExpandedKeys
5216
+ }, /* @__PURE__ */ react.createElement(react_aria_components.Collection, { items }, renderTreeItem)));
5217
+ }
5218
+ //#endregion
4973
5219
  exports.Alert = Alert;
4974
5220
  exports.Anchor = Anchor;
4975
5221
  exports.AutocompleteField = AutocompleteField;
@@ -4990,6 +5236,7 @@ exports.Drawer = Drawer;
4990
5236
  exports.EmptyState = EmptyState;
4991
5237
  exports.IconButton = IconButton;
4992
5238
  exports.InputRow = InputRow;
5239
+ exports.Label = Label;
4993
5240
  exports.Link = Link;
4994
5241
  exports.ListItem = ListItem;
4995
5242
  exports.Menu = Menu;
@@ -5023,6 +5270,7 @@ exports.TextField = TextField;
5023
5270
  exports.Toast = Toast;
5024
5271
  exports.Tooltip = Tooltip;
5025
5272
  exports.TopNav = TopNav;
5273
+ exports.Tree = Tree;
5026
5274
  exports.VerticalNavigation = VerticalNavigation;
5027
5275
  exports.VisuallyHidden = VisuallyHidden;
5028
5276
  exports.submenuPanelClassName = submenuPanelClassName;