@sproutsocial/seeds-react-tree 0.3.1 → 0.4.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.
@@ -1,4 +1,5 @@
1
1
  yarn run v1.22.22
2
+ warning package.json: "dependencies" has dependency "@sproutsocial/seeds-react-popout" with range "^2.5.7" that collides with a dependency in "devDependencies" of the same name with version "^2.5.9"
2
3
  $ tsup --dts
3
4
  CLI Building entry: src/index.ts
4
5
  CLI Using tsconfig: tsconfig.json
@@ -8,14 +9,14 @@ $ tsup --dts
8
9
  CLI Cleaning output folder
9
10
  CJS Build start
10
11
  ESM Build start
11
- CJS dist/index.js 29.75 KB
12
- CJS dist/index.js.map 58.64 KB
13
- CJS ⚡️ Build success in 26ms
14
- ESM dist/esm/index.js 26.95 KB
15
- ESM dist/esm/index.js.map 58.29 KB
16
- ESM ⚡️ Build success in 27ms
12
+ CJS dist/index.js 41.77 KB
13
+ CJS dist/index.js.map 86.20 KB
14
+ CJS ⚡️ Build success in 77ms
15
+ ESM dist/esm/index.js 38.14 KB
16
+ ESM dist/esm/index.js.map 85.67 KB
17
+ ESM ⚡️ Build success in 78ms
17
18
  DTS Build start
18
- DTS ⚡️ Build success in 1655ms
19
- DTS dist/index.d.ts 4.11 KB
20
- DTS dist/index.d.mts 4.11 KB
21
- Done in 2.39s.
19
+ DTS ⚡️ Build success in 2451ms
20
+ DTS dist/index.d.ts 7.37 KB
21
+ DTS dist/index.d.mts 7.37 KB
22
+ Done in 3.32s.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @sproutsocial/seeds-react-tree
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7e1e820: Add `SingleTreeSearchableSelect` and `MultiTreeSearchableSelect` — wrap
8
+ `TreeCombobox` in a popout-style disclosure that matches the existing
9
+ `SingleSearchableSelect` / `MultiSearchableSelect` API (`selectedItemId(s)`,
10
+ `onSelectedItemId(s)Change`, `defaultSelectedItemId(s)`).
11
+
12
+ The trigger renders the placeholder when nothing is selected, a comma-
13
+ separated list of labels for up to 3 selections, and `"N selected"` beyond
14
+ that. Pass `renderTrigger` to fully override the trigger label content. Pass
15
+ `contentWidth` to pin the popout width; by default it tracks the trigger via
16
+ `var(--radix-popover-trigger-width)` with a viewport cap, and expands
17
+ horizontally for very deep trees so labels never get clipped. The popout
18
+ height caps at `min(var(--radix-popper-available-height), 400px)` and the
19
+ tree section scrolls vertically beyond that.
20
+
21
+ `SingleTreeSearchableSelect` closes the popout on selection;
22
+ `MultiTreeSearchableSelect` stays open so users can accumulate picks. Both
23
+ close on Escape (when the search query is empty), outside click, or trigger
24
+ toggle.
25
+
26
+ `TreeCombobox` internals were restructured to a v3-style search header
27
+ (padded, with a border-bottom separator) + scrollable list section so the
28
+ inline appearance lines up with the new popout components.
29
+
30
+ `Tree` rows and `TreeCombobox`'s search input dropped from `typography[300]`
31
+ to `typography[200]` to match the rest of the searchable-select family.
32
+ `TreeItem` per-level indentation reduced from `space[500]` (20px) to
33
+ `space[400]` (16px) so deeply nested trees stay readable inside a narrow
34
+ popout.
35
+
36
+ `@sproutsocial/seeds-react-popout` is promoted from a dev dependency to a
37
+ runtime dependency.
38
+
3
39
  ## 0.3.1
4
40
 
5
41
  ### Patch Changes
package/dist/esm/index.js CHANGED
@@ -105,7 +105,8 @@ var TreeRoot = styled.ul`
105
105
  margin: 0;
106
106
  padding: 0;
107
107
  font-family: ${({ theme }) => theme.fontFamily};
108
- ${({ theme }) => theme.typography[300]}
108
+ font-size: ${({ theme }) => theme.typography[200].fontSize};
109
+ line-height: ${({ theme }) => theme.typography[200].lineHeight};
109
110
  color: ${({ theme }) => theme.colors.text.body};
110
111
  `;
111
112
  var TreeItemRow = styled.div`
@@ -113,7 +114,7 @@ var TreeItemRow = styled.div`
113
114
  align-items: center;
114
115
  gap: ${({ theme }) => theme.space[300]};
115
116
  padding: ${({ theme }) => theme.space[300]};
116
- padding-left: ${({ theme, $level }) => `calc(${theme.space[300]} + ${$level - 1} * ${theme.space[500]})`};
117
+ padding-left: ${({ theme, $level }) => `calc(${theme.space[300]} + ${$level - 1} * ${theme.space[400]})`};
117
118
  border-radius: ${({ theme }) => theme.radii[400]};
118
119
  cursor: pointer;
119
120
  user-select: none;
@@ -683,7 +684,13 @@ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
683
684
  var Root = styled2.div`
684
685
  display: flex;
685
686
  flex-direction: column;
686
- gap: ${({ theme }) => theme.space[300]};
687
+ flex: 1;
688
+ min-height: 0;
689
+ `;
690
+ var SearchSection = styled2.div`
691
+ padding: ${({ theme }) => theme.space[300]};
692
+ border-bottom: 1px solid ${({ theme }) => theme.colors.container.border.base};
693
+ flex-shrink: 0;
687
694
  `;
688
695
  var InputGroup = styled2.div`
689
696
  display: flex;
@@ -691,8 +698,8 @@ var InputGroup = styled2.div`
691
698
  gap: ${({ theme }) => theme.space[200]};
692
699
  padding: ${({ theme }) => theme.space[200]} ${({ theme }) => theme.space[300]};
693
700
  border-radius: ${({ theme }) => theme.radii[500]};
694
- border: 1px solid ${({ theme }) => theme.colors.form.border.base};
695
- background: ${({ theme }) => theme.colors.form.background.base};
701
+ border: 1px solid ${({ theme }) => theme.colors.container.border.base};
702
+ background: ${({ theme }) => theme.colors.container.background.base};
696
703
  color: ${({ theme }) => theme.colors.icon.base};
697
704
 
698
705
  &:focus-within {
@@ -705,18 +712,26 @@ var ComboboxInput = styled2.input`
705
712
  background: transparent;
706
713
  outline: none;
707
714
  font-family: ${({ theme }) => theme.fontFamily};
708
- ${({ theme }) => theme.typography[300]}
715
+ font-size: ${({ theme }) => theme.typography[200].fontSize};
716
+ line-height: ${({ theme }) => theme.typography[200].lineHeight};
709
717
  color: ${({ theme }) => theme.colors.text.body};
710
718
 
711
719
  &::placeholder {
712
720
  color: ${({ theme }) => theme.colors.text.subtext};
713
721
  }
714
722
  `;
723
+ var ListSection = styled2.div`
724
+ padding: ${({ theme }) => theme.space[200]};
725
+ overflow: auto;
726
+ flex: 1;
727
+ min-height: 0;
728
+ `;
715
729
  var EmptyState = styled2.div`
716
- padding: ${({ theme }) => theme.space[400]};
730
+ padding: ${({ theme }) => `${theme.space[300]} ${theme.space[350]}`};
717
731
  text-align: center;
718
732
  color: ${({ theme }) => theme.colors.text.subtext};
719
- ${({ theme }) => theme.typography[300]}
733
+ font-size: ${({ theme }) => theme.typography[200].fontSize};
734
+ line-height: ${({ theme }) => theme.typography[200].lineHeight};
720
735
  `;
721
736
  var NAV_KEYS = /* @__PURE__ */ new Set([
722
737
  "ArrowDown",
@@ -819,9 +834,17 @@ function TreeCombobox(props) {
819
834
  setFocusedId(result.nextFocusedId);
820
835
  }
821
836
  };
837
+ React3.useLayoutEffect(() => {
838
+ if (!focusedId) return;
839
+ const itemEl = findTreeItemEl(focusedId);
840
+ const row = itemEl?.querySelector("[data-treeitem-row]") ?? itemEl;
841
+ if (row && typeof row.scrollIntoView === "function") {
842
+ row.scrollIntoView({ block: "nearest", inline: "nearest" });
843
+ }
844
+ }, [focusedId]);
822
845
  const showEmpty = visibleItems.length === 0;
823
846
  return /* @__PURE__ */ jsxs2(Root, { className, children: [
824
- /* @__PURE__ */ jsxs2(InputGroup, { children: [
847
+ /* @__PURE__ */ jsx3(SearchSection, { children: /* @__PURE__ */ jsxs2(InputGroup, { children: [
825
848
  /* @__PURE__ */ jsx3(Icon2, { name: "magnifying-glass-outline", size: "small", "aria-hidden": true }),
826
849
  /* @__PURE__ */ jsx3(
827
850
  ComboboxInput,
@@ -842,29 +865,31 @@ function TreeCombobox(props) {
842
865
  onKeyDown: handleInputKeyDown
843
866
  }
844
867
  )
845
- ] }),
846
- /* @__PURE__ */ jsx3(
847
- Tree,
848
- {
849
- ref: treeRef,
850
- "aria-label": ariaLabel,
851
- "aria-labelledby": ariaLabelledBy,
852
- id: treeDomId,
853
- manageDomFocus: false,
854
- selectionMode,
855
- selectableNodes,
856
- expanded: effectiveExpanded,
857
- onExpandedChange: handleExpandedChange,
858
- selected: selectedProp,
859
- defaultSelected,
860
- onSelectionChange,
861
- renderSelectionIndicator,
862
- focusedId,
863
- onFocusedIdChange: setFocusedId,
864
- children: visibleItems.map((item) => /* @__PURE__ */ jsx3(TreeNode, { item }, item.id))
865
- }
866
- ),
867
- showEmpty ? /* @__PURE__ */ jsx3(EmptyState, { role: "status", "aria-live": "polite", children: emptyText }) : null
868
+ ] }) }),
869
+ /* @__PURE__ */ jsxs2(ListSection, { children: [
870
+ /* @__PURE__ */ jsx3(
871
+ Tree,
872
+ {
873
+ ref: treeRef,
874
+ "aria-label": ariaLabel,
875
+ "aria-labelledby": ariaLabelledBy,
876
+ id: treeDomId,
877
+ manageDomFocus: false,
878
+ selectionMode,
879
+ selectableNodes,
880
+ expanded: effectiveExpanded,
881
+ onExpandedChange: handleExpandedChange,
882
+ selected: selectedProp,
883
+ defaultSelected,
884
+ onSelectionChange,
885
+ renderSelectionIndicator,
886
+ focusedId,
887
+ onFocusedIdChange: setFocusedId,
888
+ children: visibleItems.map((item) => /* @__PURE__ */ jsx3(TreeNode, { item }, item.id))
889
+ }
890
+ ),
891
+ showEmpty ? /* @__PURE__ */ jsx3(EmptyState, { role: "status", "aria-live": "polite", children: emptyText }) : null
892
+ ] })
868
893
  ] });
869
894
  }
870
895
  function TreeNode({ item }) {
@@ -879,7 +904,339 @@ function TreeNode({ item }) {
879
904
  }
880
905
  );
881
906
  }
907
+
908
+ // src/SingleTreeSearchableSelect.tsx
909
+ import * as React5 from "react";
910
+
911
+ // src/Common/TreeSearchableSelectBase.tsx
912
+ import * as React4 from "react";
913
+ import styled3, { css as css2 } from "styled-components";
914
+ import { Icon as Icon3 } from "@sproutsocial/seeds-react-icon";
915
+ import { focusRing as focusRing2 } from "@sproutsocial/seeds-react-mixins";
916
+ import { Popout } from "@sproutsocial/seeds-react-popout/v2";
917
+
918
+ // src/Common/flattenTree.ts
919
+ function flattenTreeItems(items) {
920
+ const out = [];
921
+ const walk = (nodes) => {
922
+ for (const node of nodes) {
923
+ out.push(node);
924
+ if (node.children) walk(node.children);
925
+ }
926
+ };
927
+ walk(items);
928
+ return out;
929
+ }
930
+
931
+ // src/Common/TreeSearchableSelectBase.tsx
932
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
933
+ var invalidStyles = css2`
934
+ border-color: ${({ theme }) => theme.colors.form.border.error};
935
+ `;
936
+ var Trigger = styled3.button`
937
+ display: flex;
938
+ align-items: center;
939
+ justify-content: space-between;
940
+ gap: ${({ theme }) => theme.space[300]};
941
+ padding: ${({ theme }) => theme.space[200]} ${({ theme }) => theme.space[350]};
942
+ min-width: 160px;
943
+ width: ${({ $fullWidth }) => $fullWidth ? "100%" : "auto"};
944
+ border-radius: ${({ theme }) => theme.radii[500]};
945
+ border: 1px solid ${({ theme }) => theme.colors.form.border.base};
946
+ background: ${({ theme }) => theme.colors.form.background.base};
947
+ font-family: ${({ theme }) => theme.fontFamily};
948
+ font-size: ${({ theme }) => theme.typography[200].fontSize};
949
+ line-height: ${({ theme }) => theme.typography[200].lineHeight};
950
+ color: ${({ theme }) => theme.colors.text.body};
951
+ text-align: left;
952
+ cursor: default;
953
+ outline: none;
954
+ user-select: none;
955
+ transition: border-color ${({ theme }) => theme.duration.fast}
956
+ ${({ theme }) => theme.easing.ease_in},
957
+ box-shadow ${({ theme }) => theme.duration.fast}
958
+ ${({ theme }) => theme.easing.ease_in};
959
+
960
+ &:focus-visible {
961
+ ${focusRing2}
962
+ }
963
+
964
+ &[aria-disabled="true"],
965
+ &:disabled {
966
+ opacity: 0.4;
967
+ cursor: not-allowed;
968
+ }
969
+
970
+ ${({ $isInvalid }) => $isInvalid && invalidStyles}
971
+ `;
972
+ var TriggerLabel = styled3.span`
973
+ flex: 1;
974
+ min-width: 0;
975
+ overflow: hidden;
976
+ text-overflow: ellipsis;
977
+ white-space: nowrap;
978
+ `;
979
+ var PlaceholderText = styled3.span`
980
+ color: ${({ theme }) => theme.colors.text.subtext};
981
+ `;
982
+ var Chevron = styled3.span`
983
+ display: inline-flex;
984
+ align-items: center;
985
+ color: ${({ theme }) => theme.colors.icon.base};
986
+ transition: transform ${({ theme }) => theme.duration.fast}
987
+ ${({ theme }) => theme.easing.ease_in};
988
+ ${({ $open }) => $open && css2`
989
+ transform: rotate(-180deg);
990
+ `}
991
+ `;
992
+ var HiddenInput = styled3.input`
993
+ clip-path: inset(50%);
994
+ overflow: hidden;
995
+ white-space: nowrap;
996
+ border: 0;
997
+ padding: 0;
998
+ width: 1px;
999
+ height: 1px;
1000
+ margin: -1px;
1001
+ position: fixed;
1002
+ top: 0;
1003
+ left: 0;
1004
+ `;
1005
+ var PopoutContent = styled3.div`
1006
+ display: flex;
1007
+ flex-direction: column;
1008
+ /* Width sizes to content within bounds: at least the trigger width, never */
1009
+ /* wider than the available viewport space. Shallow popups stay flush with */
1010
+ /* the trigger; deeply nested trees expand horizontally as needed. */
1011
+ min-width: var(--radix-popover-trigger-width);
1012
+ max-width: var(--radix-popper-available-width);
1013
+ /* Height caps at 400px (or available viewport) so a popup with many */
1014
+ /* expanded branches scrolls vertically instead of growing off-screen. */
1015
+ max-height: min(var(--radix-popper-available-height), 400px);
1016
+ width: ${({ $width }) => $width === void 0 ? "max-content" : typeof $width === "number" ? `${$width}px` : $width};
1017
+ `;
1018
+ var MAX_INLINE_LABELS = 3;
1019
+ function defaultRenderTrigger(selected, placeholder) {
1020
+ if (selected.length === 0) {
1021
+ return /* @__PURE__ */ jsx4(PlaceholderText, { children: placeholder });
1022
+ }
1023
+ if (selected.length <= MAX_INLINE_LABELS) {
1024
+ return selected.map((s) => s.label).join(", ");
1025
+ }
1026
+ return `${selected.length} selected`;
1027
+ }
1028
+ function TreeSearchableSelectBase(props) {
1029
+ const {
1030
+ items,
1031
+ selectionMode,
1032
+ selectableNodes,
1033
+ selectedIds,
1034
+ onSelectedIdsChange,
1035
+ placeholder = "Select...",
1036
+ searchPlaceholder = "Search...",
1037
+ emptyText = "No results found.",
1038
+ renderTrigger,
1039
+ open: openProp,
1040
+ defaultOpen = false,
1041
+ onOpenChange,
1042
+ closeOnSelect,
1043
+ disabled,
1044
+ isInvalid,
1045
+ required,
1046
+ readOnly,
1047
+ name,
1048
+ fullWidth = true,
1049
+ contentWidth,
1050
+ renderSelectionIndicator,
1051
+ defaultExpanded,
1052
+ expanded,
1053
+ onExpandedChange,
1054
+ id,
1055
+ className
1056
+ } = props;
1057
+ const ariaLabel = props["aria-label"];
1058
+ const ariaLabelledBy = props["aria-labelledby"];
1059
+ const ariaDescribedBy = props["aria-describedby"];
1060
+ const isOpenControlled = openProp !== void 0;
1061
+ const [uncontrolledOpen, setUncontrolledOpen] = React4.useState(defaultOpen);
1062
+ const open = isOpenControlled ? !!openProp : uncontrolledOpen;
1063
+ const setOpen = (next) => {
1064
+ if (!isOpenControlled) setUncontrolledOpen(next);
1065
+ onOpenChange?.(next);
1066
+ };
1067
+ const [query, setQuery] = React4.useState("");
1068
+ const reactId = React4.useId();
1069
+ const popupId = `tree-select-popup-${reactId.replace(/:/g, "")}`;
1070
+ const flat = React4.useMemo(() => flattenTreeItems(items), [items]);
1071
+ const selectedItems = React4.useMemo(() => {
1072
+ const order = new Map(flat.map((it, i) => [it.id, i]));
1073
+ return selectedIds.map((id2) => flat.find((it) => it.id === id2)).filter((it) => it != null).sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0));
1074
+ }, [flat, selectedIds]);
1075
+ const handleSelectionChange = (next) => {
1076
+ onSelectedIdsChange(next);
1077
+ if (closeOnSelect) {
1078
+ setOpen(false);
1079
+ }
1080
+ };
1081
+ const triggerContent = renderTrigger ? renderTrigger(selectedItems) : defaultRenderTrigger(selectedItems, placeholder);
1082
+ const isMulti = selectionMode === "multiple";
1083
+ const primaryInputName = isMulti ? void 0 : name;
1084
+ const primaryInputId = id && primaryInputName == null ? `${id}-hidden-input` : void 0;
1085
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1086
+ /* @__PURE__ */ jsx4(
1087
+ HiddenInput,
1088
+ {
1089
+ type: "text",
1090
+ id: primaryInputId,
1091
+ name: primaryInputName,
1092
+ value: isMulti ? "" : selectedIds[0] ?? "",
1093
+ onChange: () => {
1094
+ },
1095
+ disabled,
1096
+ required: required && !isMulti,
1097
+ readOnly,
1098
+ tabIndex: -1,
1099
+ "aria-hidden": "true"
1100
+ }
1101
+ ),
1102
+ isMulti && name ? selectedIds.map((selectedId) => /* @__PURE__ */ jsx4(
1103
+ "input",
1104
+ {
1105
+ type: "hidden",
1106
+ name,
1107
+ value: selectedId
1108
+ },
1109
+ selectedId
1110
+ )) : null,
1111
+ /* @__PURE__ */ jsx4(
1112
+ Popout,
1113
+ {
1114
+ open,
1115
+ onOpenChange: setOpen,
1116
+ side: "bottom",
1117
+ align: "start",
1118
+ style: { padding: 0 },
1119
+ onEscapeKeyDown: (event) => {
1120
+ if (query.length > 0) {
1121
+ event.preventDefault();
1122
+ }
1123
+ },
1124
+ content: /* @__PURE__ */ jsx4(PopoutContent, { id: popupId, $width: contentWidth, children: /* @__PURE__ */ jsx4(
1125
+ TreeCombobox,
1126
+ {
1127
+ "aria-label": "Search",
1128
+ items,
1129
+ placeholder: searchPlaceholder,
1130
+ emptyText,
1131
+ query,
1132
+ onQueryChange: setQuery,
1133
+ selectionMode,
1134
+ selectableNodes,
1135
+ selected: selectedIds,
1136
+ onSelectionChange: handleSelectionChange,
1137
+ renderSelectionIndicator,
1138
+ defaultExpanded,
1139
+ expanded,
1140
+ onExpandedChange
1141
+ }
1142
+ ) }),
1143
+ children: /* @__PURE__ */ jsxs3(
1144
+ Trigger,
1145
+ {
1146
+ type: "button",
1147
+ id,
1148
+ className,
1149
+ $isInvalid: isInvalid,
1150
+ $fullWidth: fullWidth,
1151
+ disabled,
1152
+ role: "combobox",
1153
+ "aria-haspopup": "dialog",
1154
+ "aria-expanded": open,
1155
+ "aria-controls": open ? popupId : void 0,
1156
+ "aria-label": ariaLabel,
1157
+ "aria-labelledby": ariaLabelledBy,
1158
+ "aria-describedby": ariaDescribedBy,
1159
+ "aria-invalid": isInvalid || void 0,
1160
+ "aria-required": required || void 0,
1161
+ children: [
1162
+ /* @__PURE__ */ jsx4(TriggerLabel, { children: triggerContent }),
1163
+ /* @__PURE__ */ jsx4(Chevron, { $open: open, "aria-hidden": true, children: /* @__PURE__ */ jsx4(Icon3, { name: "chevron-down-outline", size: "small" }) })
1164
+ ]
1165
+ }
1166
+ )
1167
+ }
1168
+ )
1169
+ ] });
1170
+ }
1171
+
1172
+ // src/SingleTreeSearchableSelect.tsx
1173
+ import { jsx as jsx5 } from "react/jsx-runtime";
1174
+ function SingleTreeSearchableSelect(props) {
1175
+ const {
1176
+ selectedItemId: selectedItemIdProp,
1177
+ defaultSelectedItemId = null,
1178
+ onSelectedItemIdChange,
1179
+ ...rest
1180
+ } = props;
1181
+ const isControlled = selectedItemIdProp !== void 0;
1182
+ const [internalId, setInternalId] = React5.useState(
1183
+ defaultSelectedItemId
1184
+ );
1185
+ const selectedItemId = isControlled ? selectedItemIdProp ?? null : internalId;
1186
+ const selectedIds = React5.useMemo(
1187
+ () => selectedItemId ? [selectedItemId] : [],
1188
+ [selectedItemId]
1189
+ );
1190
+ const handleSelectedIdsChange = (ids) => {
1191
+ const next = ids[0] ?? null;
1192
+ if (!isControlled) setInternalId(next);
1193
+ onSelectedItemIdChange?.(next);
1194
+ };
1195
+ return /* @__PURE__ */ jsx5(
1196
+ TreeSearchableSelectBase,
1197
+ {
1198
+ ...rest,
1199
+ selectionMode: "single",
1200
+ selectedIds,
1201
+ onSelectedIdsChange: handleSelectedIdsChange,
1202
+ closeOnSelect: true
1203
+ }
1204
+ );
1205
+ }
1206
+
1207
+ // src/MultiTreeSearchableSelect.tsx
1208
+ import * as React6 from "react";
1209
+ import { jsx as jsx6 } from "react/jsx-runtime";
1210
+ function MultiTreeSearchableSelect(props) {
1211
+ const {
1212
+ selectedItemIds: selectedItemIdsProp,
1213
+ defaultSelectedItemIds,
1214
+ onSelectedItemIdsChange,
1215
+ ...rest
1216
+ } = props;
1217
+ const isControlled = selectedItemIdsProp !== void 0;
1218
+ const [internalIds, setInternalIds] = React6.useState(() => [
1219
+ ...defaultSelectedItemIds ?? []
1220
+ ]);
1221
+ const selectedIds = isControlled ? selectedItemIdsProp ?? [] : internalIds;
1222
+ const handleSelectedIdsChange = (ids) => {
1223
+ if (!isControlled) setInternalIds(ids);
1224
+ onSelectedItemIdsChange?.(ids);
1225
+ };
1226
+ return /* @__PURE__ */ jsx6(
1227
+ TreeSearchableSelectBase,
1228
+ {
1229
+ ...rest,
1230
+ selectionMode: "multiple",
1231
+ selectedIds,
1232
+ onSelectedIdsChange: handleSelectedIdsChange,
1233
+ closeOnSelect: false
1234
+ }
1235
+ );
1236
+ }
882
1237
  export {
1238
+ MultiTreeSearchableSelect,
1239
+ SingleTreeSearchableSelect,
883
1240
  Tree,
884
1241
  TreeCombobox,
885
1242
  TreeItem