@homebound/beam 3.0.6 → 3.1.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.d.cts CHANGED
@@ -6900,14 +6900,16 @@ type TreeSelectFieldProps<O, V extends Value> = {
6900
6900
  * @default root */
6901
6901
  chipDisplay?: "all" | "leaf" | "root";
6902
6902
  disabledOptions?: V[];
6903
+ groupOptions?: V[];
6903
6904
  } & BeamFocusableProps & PresentationFieldProps;
6904
6905
  declare function TreeSelectField<O, V extends Value>(props: TreeSelectFieldProps<O, V>): JSX.Element;
6905
6906
  declare function TreeSelectField<O extends HasIdAndName<V>, V extends Value>(props: Optional<TreeSelectFieldProps<O, V>, "getOptionValue" | "getOptionLabel">): JSX.Element;
6906
- declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<any, any>;
6907
+ declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<O, V>;
6907
6908
  type CollapsedChildrenState<O, V extends Value> = {
6908
6909
  collapsedKeys: Key$1[];
6909
6910
  setCollapsedKeys: Dispatch<SetStateAction<Key$1[]>>;
6910
6911
  getOptionValue: (opt: O) => V;
6912
+ groupKeys: Key$1[];
6911
6913
  };
6912
6914
  declare const CollapsedContext: React__default.Context<CollapsedChildrenState<any, any>>;
6913
6915
 
package/dist/index.d.ts CHANGED
@@ -6900,14 +6900,16 @@ type TreeSelectFieldProps<O, V extends Value> = {
6900
6900
  * @default root */
6901
6901
  chipDisplay?: "all" | "leaf" | "root";
6902
6902
  disabledOptions?: V[];
6903
+ groupOptions?: V[];
6903
6904
  } & BeamFocusableProps & PresentationFieldProps;
6904
6905
  declare function TreeSelectField<O, V extends Value>(props: TreeSelectFieldProps<O, V>): JSX.Element;
6905
6906
  declare function TreeSelectField<O extends HasIdAndName<V>, V extends Value>(props: Optional<TreeSelectFieldProps<O, V>, "getOptionValue" | "getOptionLabel">): JSX.Element;
6906
- declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<any, any>;
6907
+ declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<O, V>;
6907
6908
  type CollapsedChildrenState<O, V extends Value> = {
6908
6909
  collapsedKeys: Key$1[];
6909
6910
  setCollapsedKeys: Dispatch<SetStateAction<Key$1[]>>;
6910
6911
  getOptionValue: (opt: O) => V;
6912
+ groupKeys: Key$1[];
6911
6913
  };
6912
6914
  declare const CollapsedContext: React__default.Context<CollapsedChildrenState<any, any>>;
6913
6915
 
package/dist/index.js CHANGED
@@ -10547,7 +10547,8 @@ function TreeOption(props) {
10547
10547
  const {
10548
10548
  collapsedKeys,
10549
10549
  setCollapsedKeys,
10550
- getOptionValue
10550
+ getOptionValue,
10551
+ groupKeys
10551
10552
  } = useTreeSelectFieldProvider();
10552
10553
  const {
10553
10554
  optionProps,
@@ -10559,6 +10560,12 @@ function TreeOption(props) {
10559
10560
  shouldSelectOnPressUp: true,
10560
10561
  shouldFocusOnHover: false
10561
10562
  }, state, ref);
10563
+ const isGroup = groupKeys.includes(item.key);
10564
+ const canCollapse = allowCollapsing && !!option.children?.length;
10565
+ function toggleCollapsed() {
10566
+ if (!canCollapse) return;
10567
+ setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
10568
+ }
10562
10569
  const isIndeterminate = !isSelected && option.children?.some((o) => hasSelectedChildren(o, state, getOptionValue));
10563
10570
  const listItemStyles = {
10564
10571
  item: {
@@ -10586,7 +10593,12 @@ function TreeOption(props) {
10586
10593
  }]
10587
10594
  }
10588
10595
  };
10589
- return /* @__PURE__ */ jsxs33("li", { ...hoverProps, ...trussProps34({
10596
+ return /* @__PURE__ */ jsxs33("li", { ...hoverProps, onClick: (e) => {
10597
+ if (!isGroup) return;
10598
+ e.preventDefault();
10599
+ e.stopPropagation();
10600
+ toggleCollapsed();
10601
+ }, ...trussProps34({
10590
10602
  ...{
10591
10603
  display: "df",
10592
10604
  alignItems: "aic",
@@ -10603,18 +10615,18 @@ function TreeOption(props) {
10603
10615
  lineHeight: "lh_20px"
10604
10616
  },
10605
10617
  ...listItemStyles.item,
10606
- ...isHovered && !isDisabled ? listItemStyles.hover : {},
10607
- ...isFocused ? listItemStyles.focus : {},
10608
- ...isDisabled ? listItemStyles.disabled : {}
10618
+ ...isHovered && (!isDisabled || isGroup) ? listItemStyles.hover : {},
10619
+ ...isFocused && !isGroup ? listItemStyles.focus : {},
10620
+ ...isDisabled && !isGroup ? listItemStyles.disabled : {}
10609
10621
  }), children: [
10610
- allowCollapsing && /* @__PURE__ */ jsx49("span", { className: "w_18px fs0 df aic", children: option.children && option.children?.length > 0 && /* @__PURE__ */ jsx49("button", { onClick: (e) => {
10622
+ allowCollapsing && /* @__PURE__ */ jsx49("span", { className: "w_18px fs0 df aic", children: canCollapse && /* @__PURE__ */ jsx49("button", { onClick: (e) => {
10611
10623
  e.preventDefault();
10612
10624
  e.stopPropagation();
10613
- setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
10625
+ toggleCollapsed();
10614
10626
  return false;
10615
10627
  }, className: "br4 h_16px w_16px bgTransparent h_bgGray300", ...tid[`collapseToggle_${item.key}`], children: /* @__PURE__ */ jsx49(Icon, { icon: collapsedKeys.includes(item.key) ? "triangleRight" : "triangleDown", inc: 2 }) }) }),
10616
10628
  /* @__PURE__ */ jsxs33("span", { className: "df aic gap1 h100 fg1 pt1 pb1 pr2", ref, ...optionProps, "data-label": item.textValue, children: [
10617
- /* @__PURE__ */ jsx49(StyledCheckbox, { isDisabled, isSelected, isIndeterminate, ...tid[item.key.toString()] }),
10629
+ !isGroup && /* @__PURE__ */ jsx49(StyledCheckbox, { isDisabled, isSelected, isIndeterminate, ...tid[item.key.toString()] }),
10618
10630
  /* @__PURE__ */ jsx49("div", { className: "pl1", children: item.rendered })
10619
10631
  ] })
10620
10632
  ] });
@@ -10697,9 +10709,14 @@ function VirtualizedOptions(props) {
10697
10709
  totalListHeightChanged: onListHeightChange,
10698
10710
  totalCount: items.length,
10699
10711
  ...process.env.NODE_ENV === "test" ? {
10700
- // We don't really need to set this, but it's handy for tests, which would
10701
- // otherwise render just 1 row. A better way to do this would be to jest.mock
10702
- // out Virtuoso with an impl that just rendered everything, but doing this for now.
10712
+ // In tests, we render all rows so assertions can see expands/async-loaded items. However,
10713
+ // the `initialItemCount` (next prop) is only applied on amount, so we set `key={items.length}`
10714
+ // to force a remount when our list changes -- and we only want/need this in tests, b/c otherwise
10715
+ // in production a Virtuoso remount causes visible flashing.
10716
+ key: items.length,
10717
+ // We don't really need to set this, but it's handy for tests, which would otherwise render
10718
+ // just 1 row. A better way to do this would be to jest.mock out Virtuoso with an impl that
10719
+ // just rendered everything, but doing this for now.
10703
10720
  initialItemCount: items.length
10704
10721
  } : {
10705
10722
  // Ensure the selected item is visible when the list renders
@@ -10739,8 +10756,7 @@ function VirtualizedOptions(props) {
10739
10756
  components: !loading ? {} : {
10740
10757
  Footer: typeof loading === "function" ? loading : () => /* @__PURE__ */ jsx50(LoadingDots, { contrast })
10741
10758
  }
10742
- },
10743
- items.length
10759
+ }
10744
10760
  );
10745
10761
  }
10746
10762
 
@@ -10913,6 +10929,7 @@ function TreeSelectField(props) {
10913
10929
  ...otherProps
10914
10930
  } = props;
10915
10931
  const [collapsedKeys, setCollapsedKeys] = useState17([]);
10932
+ const groupKeys = useMemo15(() => props.groupOptions?.map((option) => valueToKey(option)) ?? [], [props.groupOptions]);
10916
10933
  useEffect13(() => {
10917
10934
  setCollapsedKeys(!Array.isArray(options) ? [] : defaultCollapsed ? options.map((o) => getOptionValue(o)) : options.flatMap(flattenOptions).filter((o) => o.defaultCollapsed).map((o) => getOptionValue(o)));
10918
10935
  }, [options, defaultCollapsed]);
@@ -10920,11 +10937,12 @@ function TreeSelectField(props) {
10920
10937
  () => ({
10921
10938
  collapsedKeys,
10922
10939
  setCollapsedKeys,
10923
- getOptionValue
10940
+ getOptionValue,
10941
+ groupKeys
10924
10942
  }),
10925
10943
  // TODO: validate this eslint-disable. It was automatically ignored as part of https://app.shortcut.com/homebound-team/story/40033/enable-react-hooks-exhaustive-deps-for-react-projects
10926
10944
  // eslint-disable-next-line react-hooks/exhaustive-deps
10927
- [collapsedKeys, setCollapsedKeys]
10945
+ [collapsedKeys, setCollapsedKeys, groupKeys]
10928
10946
  );
10929
10947
  return /* @__PURE__ */ jsx54(CollapsedContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx54(TreeSelectFieldBase, { ...otherProps, options, getOptionLabel, getOptionValue, values, onSelect: ({
10930
10948
  all,
@@ -10945,7 +10963,8 @@ var CollapsedContext = React9.createContext({
10945
10963
  collapsedKeys: [],
10946
10964
  setCollapsedKeys: () => {
10947
10965
  },
10948
- getOptionValue: () => ({})
10966
+ getOptionValue: () => ({}),
10967
+ groupKeys: []
10949
10968
  });
10950
10969
  function TreeSelectFieldBase(props) {
10951
10970
  const {
@@ -10964,13 +10983,15 @@ function TreeSelectFieldBase(props) {
10964
10983
  contrast = false,
10965
10984
  nothingSelectedText = "",
10966
10985
  onSelect,
10967
- defaultCollapsed = false,
10986
+ defaultCollapsed: _defaultCollapsed = false,
10968
10987
  placeholder,
10969
10988
  fullWidth = fieldProps?.fullWidth ?? false,
10970
10989
  chipDisplay = "root",
10971
10990
  disabledOptions,
10991
+ groupOptions: _groupOptions,
10972
10992
  ...otherProps
10973
10993
  } = props;
10994
+ void _defaultCollapsed;
10974
10995
  const isDisabled = !!disabled;
10975
10996
  const isReadOnly = !!readOnly;
10976
10997
  const initialOptions = Array.isArray(options) ? options : options.current;
@@ -10982,7 +11003,10 @@ function TreeSelectFieldBase(props) {
10982
11003
  const {
10983
11004
  collapsedKeys
10984
11005
  } = useTreeSelectFieldProvider();
11006
+ const groupKeys = useMemo15(() => _groupOptions?.map((option) => valueToKey(option)) ?? [], [_groupOptions]);
11007
+ const groupKeySet = useMemo15(() => new Set(groupKeys), [groupKeys]);
10985
11008
  const disabledOptionsWithReasons = Object.fromEntries(disabledOptions?.map(disabledOptionToKeyedTuple) ?? []);
11009
+ const disabledKeys = [.../* @__PURE__ */ new Set([...Object.keys(disabledOptionsWithReasons), ...groupKeys])];
10986
11010
  const initTreeFieldState = useCallback8(() => {
10987
11011
  const selectedKeys = new Set(values?.flatMap((v) => {
10988
11012
  const foundOptions = findOptions(initialOptions, valueToKey(v), getOptionValue);
@@ -10991,14 +11015,16 @@ function TreeSelectFieldBase(props) {
10991
11015
  }) => selectOptionAndAllChildren(option));
10992
11016
  }));
10993
11017
  function selectOptionAndAllChildren(maybeParent) {
10994
- return [valueToKey(getOptionValue(maybeParent)), ...maybeParent.children?.flatMap(selectOptionAndAllChildren) ?? []];
11018
+ const key = valueToKey(getOptionValue(maybeParent));
11019
+ return [...groupKeySet.has(key) ? [] : [key], ...maybeParent.children?.flatMap(selectOptionAndAllChildren) ?? []];
10995
11020
  }
10996
11021
  function areAllChildrenSelected(maybeParent) {
10997
- const isSelected = selectedKeys.has(valueToKey(getOptionValue(maybeParent)));
11022
+ const key = valueToKey(getOptionValue(maybeParent));
11023
+ const isSelected = selectedKeys.has(key);
10998
11024
  if (isSelected || !maybeParent.children || maybeParent.children.length === 0) return isSelected;
10999
11025
  const areAllSelected = maybeParent.children.every(areAllChildrenSelected);
11000
- if (areAllSelected) {
11001
- selectedKeys.add(valueToKey(getOptionValue(maybeParent)));
11026
+ if (areAllSelected && !groupKeySet.has(key)) {
11027
+ selectedKeys.add(key);
11002
11028
  }
11003
11029
  return areAllSelected;
11004
11030
  }
@@ -11009,18 +11035,17 @@ function TreeSelectFieldBase(props) {
11009
11035
  return [maybeOption.option];
11010
11036
  });
11011
11037
  const selectedOptionsLabels = chipDisplay === "root" ? initialOptions.flatMap((o) => getTopLevelSelections(o, selectedKeys, getOptionValue)).map(getOptionLabel) : chipDisplay === "leaf" ? selectedOptions.filter((o) => !o.children || o.children.length === 0).map(getOptionLabel) : selectedOptions.map(getOptionLabel);
11012
- const filteredOptions = initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue));
11013
11038
  return {
11014
11039
  selectedKeys: [...selectedKeys],
11040
+ searchValue: void 0,
11015
11041
  inputValue: selectedOptions.length === 1 ? getOptionLabel([...selectedOptions][0]) : isReadOnly && selectedOptions.length > 0 ? selectedOptionsLabels.join(", ") : selectedOptions.length === 0 ? nothingSelectedText : "",
11016
- filteredOptions,
11017
11042
  selectedOptions,
11018
11043
  allOptions: initialOptions,
11019
11044
  selectedOptionsLabels,
11020
11045
  optionsLoading: false,
11021
11046
  allowCollapsing: true
11022
11047
  };
11023
- }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, collapsedKeys]);
11048
+ }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, groupKeySet]);
11024
11049
  const [fieldState, setFieldState] = useState17(() => initTreeFieldState());
11025
11050
  useEffect13(() => {
11026
11051
  if (Array.isArray(options)) {
@@ -11040,75 +11065,54 @@ function TreeSelectFieldBase(props) {
11040
11065
  setFieldState(initTreeFieldState());
11041
11066
  }
11042
11067
  }, [getOptionValue, initTreeFieldState, values]);
11043
- const reactToCollapse = useRef21(false);
11044
- useEffect13(
11045
- () => {
11046
- if (reactToCollapse.current) {
11047
- setFieldState(({
11048
- allOptions,
11049
- inputValue,
11050
- ...others
11051
- }) => ({
11052
- allOptions,
11053
- inputValue,
11054
- ...others,
11055
- filteredOptions: allOptions.flatMap((o) => levelOptions(o, 0, inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), inputValue)))
11056
- }));
11057
- }
11058
- reactToCollapse.current = true;
11059
- },
11060
- // Only react to collapseKey changes. Other deps should be stable (`contains`, `getOptionLabel`, `getOptionValue`).
11061
- // eslint-disable-next-line react-hooks/exhaustive-deps
11062
- [collapsedKeys]
11063
- );
11068
+ const filteredOptions = useMemo15(() => getFilteredOptions(fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue), [fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue]);
11064
11069
  const onInputChange = useCallback8((inputValue) => {
11065
11070
  setFieldState((prevState) => {
11066
11071
  return {
11067
11072
  ...prevState,
11068
11073
  inputValue,
11069
- allowCollapsing: inputValue.length === 0,
11070
- filteredOptions: prevState.allOptions.flatMap((o) => levelOptions(o, 0, inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), inputValue)))
11074
+ searchValue: inputValue.length === 0 ? void 0 : inputValue,
11075
+ allowCollapsing: inputValue.length === 0
11071
11076
  };
11072
11077
  });
11073
- }, [collapsedKeys, contains, getOptionLabel, getOptionValue]);
11074
- const maybeInitLoad = useCallback8(async (options2, fieldState2, setFieldState2) => {
11078
+ }, []);
11079
+ const maybeInitLoad = useCallback8(async (options2, setFieldState2) => {
11075
11080
  if (!Array.isArray(options2)) {
11076
11081
  setFieldState2((prevState) => ({
11077
11082
  ...prevState,
11078
11083
  optionsLoading: true
11079
11084
  }));
11080
11085
  const loadedOptions = (await options2.load()).options;
11081
- const filteredOptions = loadedOptions.flatMap((o) => levelOptions(o, 0, fieldState2.inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), fieldState2.inputValue)));
11082
11086
  setFieldState2((prevState) => ({
11083
11087
  ...prevState,
11084
- filteredOptions,
11085
11088
  allOptions: loadedOptions,
11086
11089
  optionsLoading: false
11087
11090
  }));
11088
11091
  }
11089
- }, [collapsedKeys, contains, getOptionLabel, getOptionValue]);
11092
+ }, []);
11090
11093
  const firstOpen = useRef21(true);
11091
11094
  function onOpenChange(isOpen) {
11092
11095
  if (firstOpen.current && isOpen) {
11093
- maybeInitLoad(options, fieldState, setFieldState);
11096
+ maybeInitLoad(options, setFieldState);
11094
11097
  firstOpen.current = false;
11095
11098
  }
11096
11099
  if (isOpen) {
11097
11100
  setFieldState((prevState) => ({
11098
11101
  ...prevState,
11099
11102
  inputValue: "",
11100
- filteredOptions: prevState.allOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue))
11103
+ searchValue: void 0,
11104
+ allowCollapsing: true
11101
11105
  }));
11102
11106
  }
11103
11107
  }
11104
11108
  const comboBoxChildren = useCallback8(([item]) => /* @__PURE__ */ jsx54(Item3, { textValue: getOptionLabel(item), children: getOptionMenuLabel(item) }, valueToKey(getOptionValue(item))), [getOptionValue, getOptionLabel, getOptionMenuLabel]);
11105
11109
  const comboBoxProps = {
11106
11110
  ...otherProps,
11107
- disabledKeys: Object.keys(disabledOptionsWithReasons),
11111
+ disabledKeys,
11108
11112
  placeholder: !values || values.length === 0 ? placeholder : "",
11109
11113
  label: props.label,
11110
11114
  inputValue: fieldState.inputValue,
11111
- items: fieldState.filteredOptions,
11115
+ items: filteredOptions,
11112
11116
  isDisabled,
11113
11117
  isReadOnly,
11114
11118
  onInputChange,
@@ -11133,6 +11137,8 @@ function TreeSelectFieldBase(props) {
11133
11137
  setFieldState((prevState) => ({
11134
11138
  ...prevState,
11135
11139
  inputValue: nothingSelectedText,
11140
+ searchValue: void 0,
11141
+ allowCollapsing: true,
11136
11142
  selectedKeys: [],
11137
11143
  selectedOptions: []
11138
11144
  }));
@@ -11163,15 +11169,16 @@ function TreeSelectFieldBase(props) {
11163
11169
  const childrenKeys = option.children.flatMap(flattenOptions).map((o) => valueToKey(getOptionValue(o))).filter((childKey) => {
11164
11170
  return !state.disabledKeys.has(childKey);
11165
11171
  });
11166
- [key, ...childrenKeys].forEach(addedKeys.add, addedKeys);
11172
+ [...groupKeySet.has(key) ? [] : [key], ...childrenKeys].forEach(addedKeys.add, addedKeys);
11167
11173
  }
11168
- for (const parent of parents.reverse()) {
11169
- const allChecked = parent.children?.every((child) => {
11170
- const childKey = valueToKey(getOptionValue(child));
11171
- return addedKeys.has(childKey) || existingKeys.has(childKey) || state.disabledKeys.has(childKey);
11172
- });
11173
- if (allChecked) {
11174
- addedKeys.add(valueToKey(getOptionValue(parent)));
11174
+ const selectionKeys = /* @__PURE__ */ new Set([...existingKeys, ...addedKeys]);
11175
+ for (const parent of [...parents].reverse()) {
11176
+ const parentKey = valueToKey(getOptionValue(parent));
11177
+ if (isOptionFullySelected(parent, selectionKeys, state.disabledKeys, groupKeySet, getOptionValue)) {
11178
+ if (!groupKeySet.has(parentKey)) {
11179
+ addedKeys.add(parentKey);
11180
+ selectionKeys.add(parentKey);
11181
+ }
11175
11182
  }
11176
11183
  }
11177
11184
  }
@@ -11204,7 +11211,7 @@ function TreeSelectFieldBase(props) {
11204
11211
  ...prevState,
11205
11212
  // Since we reset the list of options upon selection changes, then set the `inputValue` to empty string to reflect that.
11206
11213
  inputValue: "",
11207
- filteredOptions: initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)),
11214
+ searchValue: void 0,
11208
11215
  selectedKeys: [...selectedKeys],
11209
11216
  selectedOptions,
11210
11217
  selectedOptionsLabels: chipDisplay === "root" ? rootOptions.map(getOptionLabel) : chipDisplay === "leaf" ? leafOptions.map(getOptionLabel) : selectedOptions.map(getOptionLabel)
@@ -11235,7 +11242,7 @@ function TreeSelectFieldBase(props) {
11235
11242
  setFieldState((prevState) => ({
11236
11243
  ...prevState,
11237
11244
  inputValue: selectedOptions.length === 1 ? getOptionLabel(selectedOptions[0]) : selectedOptions.length === 0 ? nothingSelectedText : "",
11238
- filteredOptions: initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)),
11245
+ searchValue: void 0,
11239
11246
  allowCollapsing: true
11240
11247
  }));
11241
11248
  }
@@ -11324,6 +11331,18 @@ function getTopLevelSelections(o, selectedKeys, getOptionValue) {
11324
11331
  if (o.children) return [...o.children.flatMap((c) => getTopLevelSelections(c, selectedKeys, getOptionValue))];
11325
11332
  return [];
11326
11333
  }
11334
+ function getFilteredOptions(allOptions, searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue) {
11335
+ return allOptions.flatMap((option) => levelOptions(option, 0, !!searchValue, collapsedKeys, getOptionValue).filter(([nestedOption]) => searchValue ? contains(getOptionLabel(nestedOption), searchValue) : true));
11336
+ }
11337
+ function isOptionFullySelected(option, selectedKeys, disabledKeys, groupKeys, getOptionValue) {
11338
+ const key = valueToKey(getOptionValue(option));
11339
+ if (groupKeys.has(key)) {
11340
+ return option.children?.length ? option.children.every((child) => isOptionFullySelected(child, selectedKeys, disabledKeys, groupKeys, getOptionValue)) : false;
11341
+ }
11342
+ if (selectedKeys.has(key) || disabledKeys.has(key)) return true;
11343
+ if (!option.children || option.children.length === 0) return false;
11344
+ return option.children.every((child) => isOptionFullySelected(child, selectedKeys, disabledKeys, groupKeys, getOptionValue));
11345
+ }
11327
11346
 
11328
11347
  // src/inputs/internal/ComboBoxInput.tsx
11329
11348
  import { jsx as jsx55 } from "react/jsx-runtime";