@homebound/beam 4.61.0 → 4.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +104 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -28
- package/dist/index.d.ts +32 -28
- package/dist/index.js +104 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -8768,6 +8768,31 @@ type OptionsOrLoad<O> = O[] | {
|
|
|
8768
8768
|
options: O[] | undefined;
|
|
8769
8769
|
};
|
|
8770
8770
|
|
|
8771
|
+
type NestedOption<O> = O & {
|
|
8772
|
+
children?: NestedOption<O>[];
|
|
8773
|
+
defaultCollapsed?: boolean;
|
|
8774
|
+
};
|
|
8775
|
+
type NestedOptionsOrLoad<O> = NestedOption<O>[] | {
|
|
8776
|
+
current: NestedOption<O>[];
|
|
8777
|
+
load: () => Promise<{
|
|
8778
|
+
options: NestedOption<O>[];
|
|
8779
|
+
}>;
|
|
8780
|
+
};
|
|
8781
|
+
type TreeSelectResponse<O, V extends Value> = {
|
|
8782
|
+
all: {
|
|
8783
|
+
values: V[];
|
|
8784
|
+
options: O[];
|
|
8785
|
+
};
|
|
8786
|
+
leaf: {
|
|
8787
|
+
values: V[];
|
|
8788
|
+
options: O[];
|
|
8789
|
+
};
|
|
8790
|
+
root: {
|
|
8791
|
+
values: V[];
|
|
8792
|
+
options: O[];
|
|
8793
|
+
};
|
|
8794
|
+
};
|
|
8795
|
+
|
|
8771
8796
|
/** Props shared by `MenuSelectField`, `MenuMultiSelectField`, and `MenuTreeSelectField`. */
|
|
8772
8797
|
type MenuSelectFieldBaseProps<O, V extends Value> = {
|
|
8773
8798
|
label: string;
|
|
@@ -8781,7 +8806,7 @@ type MenuSelectFieldBaseProps<O, V extends Value> = {
|
|
|
8781
8806
|
getOptionMenuLabel?: (opt: O, isUnsetOpt: boolean) => ReactNode;
|
|
8782
8807
|
/** Extra text the menu search matches, in addition to `getOptionLabel`. */
|
|
8783
8808
|
getOptionSearchText?: (opt: O) => string | readonly string[];
|
|
8784
|
-
/** Sort options by `getOptionLabel`. On by default. `MenuTreeSelectField` defaults this to false
|
|
8809
|
+
/** Sort options by `getOptionLabel`. On by default. `MenuTreeSelectField` defaults this to false, and so does `MenuSelectField` when an option has `children`. */
|
|
8785
8810
|
autoSort?: boolean;
|
|
8786
8811
|
/** Debounced menu search text. The caller replaces `options` and should keep `mixedValues` in that list. Closing calls this with `""`. */
|
|
8787
8812
|
onSearch?: (search: string) => void;
|
|
@@ -8806,7 +8831,9 @@ type MenuSelectFieldBaseProps<O, V extends Value> = {
|
|
|
8806
8831
|
onFocus?: VoidFunction;
|
|
8807
8832
|
onBlur?: VoidFunction;
|
|
8808
8833
|
} & Pick<PresentationFieldProps, "labelStyle" | "compact" | "borderless" | "borderOnHover" | "fullWidth" | "visuallyDisabled" | "errorInTooltip" | "inputStylePalette">;
|
|
8809
|
-
type MenuSelectFieldProps<O, V extends Value> = MenuSelectFieldBaseProps<O, V> & {
|
|
8834
|
+
type MenuSelectFieldProps<O, V extends Value> = Omit<MenuSelectFieldBaseProps<O, V>, "options"> & {
|
|
8835
|
+
/** Flat `O[]`, or `NestedOption<O>[]` when a row has `children`. `{ current, load, options }` loads either list. */
|
|
8836
|
+
options: OptionsOrLoad<O> | OptionsOrLoad<NestedOption<O>>;
|
|
8810
8837
|
value: V | undefined;
|
|
8811
8838
|
/** Value proposed by an AI model; puts the field in AI mode. */
|
|
8812
8839
|
proposedValue?: V;
|
|
@@ -8846,31 +8873,6 @@ type BoundMenuSelectFieldProps<O, V extends Value> = Omit<MenuSelectFieldProps<O
|
|
|
8846
8873
|
/** Binds `MenuSelectField` to a form field. */
|
|
8847
8874
|
declare function BoundMenuSelectField<O, V extends Value>(props: BoundMenuSelectFieldProps<O, V>): JSX.Element;
|
|
8848
8875
|
|
|
8849
|
-
type NestedOption<O> = O & {
|
|
8850
|
-
children?: NestedOption<O>[];
|
|
8851
|
-
defaultCollapsed?: boolean;
|
|
8852
|
-
};
|
|
8853
|
-
type NestedOptionsOrLoad<O> = NestedOption<O>[] | {
|
|
8854
|
-
current: NestedOption<O>[];
|
|
8855
|
-
load: () => Promise<{
|
|
8856
|
-
options: NestedOption<O>[];
|
|
8857
|
-
}>;
|
|
8858
|
-
};
|
|
8859
|
-
type TreeSelectResponse<O, V extends Value> = {
|
|
8860
|
-
all: {
|
|
8861
|
-
values: V[];
|
|
8862
|
-
options: O[];
|
|
8863
|
-
};
|
|
8864
|
-
leaf: {
|
|
8865
|
-
values: V[];
|
|
8866
|
-
options: O[];
|
|
8867
|
-
};
|
|
8868
|
-
root: {
|
|
8869
|
-
values: V[];
|
|
8870
|
-
options: O[];
|
|
8871
|
-
};
|
|
8872
|
-
};
|
|
8873
|
-
|
|
8874
8876
|
type MenuTreeSelectFieldProps<O, V extends Value> = MenuSelectFieldBaseProps<NestedOption<O>, V> & {
|
|
8875
8877
|
/** Selected values. A parent selects its whole subtree; a parent whose children are all selected is selected too. */
|
|
8876
8878
|
values: V[];
|
|
@@ -12038,7 +12040,9 @@ type ErrorMessageProps = {
|
|
|
12038
12040
|
*/
|
|
12039
12041
|
declare function ErrorMessage(props: ErrorMessageProps): React$1.JSX.Element;
|
|
12040
12042
|
|
|
12041
|
-
/** Select whose trigger shows the value and opens a menu.
|
|
12043
|
+
/** Select whose trigger shows the value and opens a menu.
|
|
12044
|
+
*
|
|
12045
|
+
* Options with `children` are a tree: every node stays visible, and the trigger shows the path. Search is included when the list is longer than `searchOptionLimit`, or when `onSearch` is set. See `MenuSelectField.mdx`. */
|
|
12042
12046
|
declare function MenuSelectField<O, V extends Value>(props: MenuSelectFieldProps<O, V>): JSX.Element;
|
|
12043
12047
|
|
|
12044
12048
|
type ToggleButtonProps = {
|
package/dist/index.d.ts
CHANGED
|
@@ -8768,6 +8768,31 @@ type OptionsOrLoad<O> = O[] | {
|
|
|
8768
8768
|
options: O[] | undefined;
|
|
8769
8769
|
};
|
|
8770
8770
|
|
|
8771
|
+
type NestedOption<O> = O & {
|
|
8772
|
+
children?: NestedOption<O>[];
|
|
8773
|
+
defaultCollapsed?: boolean;
|
|
8774
|
+
};
|
|
8775
|
+
type NestedOptionsOrLoad<O> = NestedOption<O>[] | {
|
|
8776
|
+
current: NestedOption<O>[];
|
|
8777
|
+
load: () => Promise<{
|
|
8778
|
+
options: NestedOption<O>[];
|
|
8779
|
+
}>;
|
|
8780
|
+
};
|
|
8781
|
+
type TreeSelectResponse<O, V extends Value> = {
|
|
8782
|
+
all: {
|
|
8783
|
+
values: V[];
|
|
8784
|
+
options: O[];
|
|
8785
|
+
};
|
|
8786
|
+
leaf: {
|
|
8787
|
+
values: V[];
|
|
8788
|
+
options: O[];
|
|
8789
|
+
};
|
|
8790
|
+
root: {
|
|
8791
|
+
values: V[];
|
|
8792
|
+
options: O[];
|
|
8793
|
+
};
|
|
8794
|
+
};
|
|
8795
|
+
|
|
8771
8796
|
/** Props shared by `MenuSelectField`, `MenuMultiSelectField`, and `MenuTreeSelectField`. */
|
|
8772
8797
|
type MenuSelectFieldBaseProps<O, V extends Value> = {
|
|
8773
8798
|
label: string;
|
|
@@ -8781,7 +8806,7 @@ type MenuSelectFieldBaseProps<O, V extends Value> = {
|
|
|
8781
8806
|
getOptionMenuLabel?: (opt: O, isUnsetOpt: boolean) => ReactNode;
|
|
8782
8807
|
/** Extra text the menu search matches, in addition to `getOptionLabel`. */
|
|
8783
8808
|
getOptionSearchText?: (opt: O) => string | readonly string[];
|
|
8784
|
-
/** Sort options by `getOptionLabel`. On by default. `MenuTreeSelectField` defaults this to false
|
|
8809
|
+
/** Sort options by `getOptionLabel`. On by default. `MenuTreeSelectField` defaults this to false, and so does `MenuSelectField` when an option has `children`. */
|
|
8785
8810
|
autoSort?: boolean;
|
|
8786
8811
|
/** Debounced menu search text. The caller replaces `options` and should keep `mixedValues` in that list. Closing calls this with `""`. */
|
|
8787
8812
|
onSearch?: (search: string) => void;
|
|
@@ -8806,7 +8831,9 @@ type MenuSelectFieldBaseProps<O, V extends Value> = {
|
|
|
8806
8831
|
onFocus?: VoidFunction;
|
|
8807
8832
|
onBlur?: VoidFunction;
|
|
8808
8833
|
} & Pick<PresentationFieldProps, "labelStyle" | "compact" | "borderless" | "borderOnHover" | "fullWidth" | "visuallyDisabled" | "errorInTooltip" | "inputStylePalette">;
|
|
8809
|
-
type MenuSelectFieldProps<O, V extends Value> = MenuSelectFieldBaseProps<O, V> & {
|
|
8834
|
+
type MenuSelectFieldProps<O, V extends Value> = Omit<MenuSelectFieldBaseProps<O, V>, "options"> & {
|
|
8835
|
+
/** Flat `O[]`, or `NestedOption<O>[]` when a row has `children`. `{ current, load, options }` loads either list. */
|
|
8836
|
+
options: OptionsOrLoad<O> | OptionsOrLoad<NestedOption<O>>;
|
|
8810
8837
|
value: V | undefined;
|
|
8811
8838
|
/** Value proposed by an AI model; puts the field in AI mode. */
|
|
8812
8839
|
proposedValue?: V;
|
|
@@ -8846,31 +8873,6 @@ type BoundMenuSelectFieldProps<O, V extends Value> = Omit<MenuSelectFieldProps<O
|
|
|
8846
8873
|
/** Binds `MenuSelectField` to a form field. */
|
|
8847
8874
|
declare function BoundMenuSelectField<O, V extends Value>(props: BoundMenuSelectFieldProps<O, V>): JSX.Element;
|
|
8848
8875
|
|
|
8849
|
-
type NestedOption<O> = O & {
|
|
8850
|
-
children?: NestedOption<O>[];
|
|
8851
|
-
defaultCollapsed?: boolean;
|
|
8852
|
-
};
|
|
8853
|
-
type NestedOptionsOrLoad<O> = NestedOption<O>[] | {
|
|
8854
|
-
current: NestedOption<O>[];
|
|
8855
|
-
load: () => Promise<{
|
|
8856
|
-
options: NestedOption<O>[];
|
|
8857
|
-
}>;
|
|
8858
|
-
};
|
|
8859
|
-
type TreeSelectResponse<O, V extends Value> = {
|
|
8860
|
-
all: {
|
|
8861
|
-
values: V[];
|
|
8862
|
-
options: O[];
|
|
8863
|
-
};
|
|
8864
|
-
leaf: {
|
|
8865
|
-
values: V[];
|
|
8866
|
-
options: O[];
|
|
8867
|
-
};
|
|
8868
|
-
root: {
|
|
8869
|
-
values: V[];
|
|
8870
|
-
options: O[];
|
|
8871
|
-
};
|
|
8872
|
-
};
|
|
8873
|
-
|
|
8874
8876
|
type MenuTreeSelectFieldProps<O, V extends Value> = MenuSelectFieldBaseProps<NestedOption<O>, V> & {
|
|
8875
8877
|
/** Selected values. A parent selects its whole subtree; a parent whose children are all selected is selected too. */
|
|
8876
8878
|
values: V[];
|
|
@@ -12038,7 +12040,9 @@ type ErrorMessageProps = {
|
|
|
12038
12040
|
*/
|
|
12039
12041
|
declare function ErrorMessage(props: ErrorMessageProps): React$1.JSX.Element;
|
|
12040
12042
|
|
|
12041
|
-
/** Select whose trigger shows the value and opens a menu.
|
|
12043
|
+
/** Select whose trigger shows the value and opens a menu.
|
|
12044
|
+
*
|
|
12045
|
+
* Options with `children` are a tree: every node stays visible, and the trigger shows the path. Search is included when the list is longer than `searchOptionLimit`, or when `onSearch` is set. See `MenuSelectField.mdx`. */
|
|
12042
12046
|
declare function MenuSelectField<O, V extends Value>(props: MenuSelectFieldProps<O, V>): JSX.Element;
|
|
12043
12047
|
|
|
12044
12048
|
type ToggleButtonProps = {
|
package/dist/index.js
CHANGED
|
@@ -18823,7 +18823,7 @@ function valueToKey(value) {
|
|
|
18823
18823
|
}
|
|
18824
18824
|
|
|
18825
18825
|
// src/inputs/internal/selectFieldHelpers.ts
|
|
18826
|
-
function initializeOptions(optionsOrLoad, getOptionValue, getOptionLabel, unsetLabel, autoSort) {
|
|
18826
|
+
function initializeOptions(optionsOrLoad, getOptionValue, getOptionLabel, unsetLabel, autoSort, getChildren) {
|
|
18827
18827
|
const result = [];
|
|
18828
18828
|
if (unsetLabel) {
|
|
18829
18829
|
result.push(unsetOption);
|
|
@@ -18840,8 +18840,8 @@ function initializeOptions(optionsOrLoad, getOptionValue, getOptionLabel, unsetL
|
|
|
18840
18840
|
const toCheck = Array.isArray(current2) ? current2 : [current2];
|
|
18841
18841
|
toCheck.forEach((current3) => {
|
|
18842
18842
|
const value = getOptionValue(current3);
|
|
18843
|
-
const
|
|
18844
|
-
if (!
|
|
18843
|
+
const alreadyListed = options !== void 0 && optionsIncludeValue(options, value, getOptionValue, getChildren);
|
|
18844
|
+
if (!alreadyListed) {
|
|
18845
18845
|
userOptions.push(current3);
|
|
18846
18846
|
}
|
|
18847
18847
|
});
|
|
@@ -18851,6 +18851,13 @@ function initializeOptions(optionsOrLoad, getOptionValue, getOptionLabel, unsetL
|
|
|
18851
18851
|
return result;
|
|
18852
18852
|
}
|
|
18853
18853
|
var unsetOption = {};
|
|
18854
|
+
function optionsIncludeValue(options, value, getOptionValue, getChildren) {
|
|
18855
|
+
return options.some((option) => {
|
|
18856
|
+
if (getOptionValue(option) === value) return true;
|
|
18857
|
+
const children = getChildren?.(option);
|
|
18858
|
+
return children !== void 0 && optionsIncludeValue(children, value, getOptionValue, getChildren);
|
|
18859
|
+
});
|
|
18860
|
+
}
|
|
18854
18861
|
function disabledOptionToKeyedTuple(disabledOption) {
|
|
18855
18862
|
if (typeof disabledOption === "object" && disabledOption !== null) {
|
|
18856
18863
|
return [valueToKey(disabledOption.value), disabledOption.reason];
|
|
@@ -19620,7 +19627,9 @@ function BaseOptionRow(props) {
|
|
|
19620
19627
|
id,
|
|
19621
19628
|
disabledReason,
|
|
19622
19629
|
mixedLegendId,
|
|
19623
|
-
variant
|
|
19630
|
+
variant,
|
|
19631
|
+
indent,
|
|
19632
|
+
isPathRoot
|
|
19624
19633
|
} = props;
|
|
19625
19634
|
const entry = item.value;
|
|
19626
19635
|
const ref = useRef34(null);
|
|
@@ -19655,6 +19664,11 @@ function BaseOptionRow(props) {
|
|
|
19655
19664
|
ref,
|
|
19656
19665
|
...trussProps76({
|
|
19657
19666
|
...rowCss,
|
|
19667
|
+
...indent !== void 0 ? {
|
|
19668
|
+
paddingLeft: ["pl_var", {
|
|
19669
|
+
"--paddingLeft": `${indent}px`
|
|
19670
|
+
}]
|
|
19671
|
+
} : {},
|
|
19658
19672
|
...highlighted ? {
|
|
19659
19673
|
backgroundColor: ["bgColor_var", {
|
|
19660
19674
|
"--backgroundColor": "var(--b-surface-raised-hover)"
|
|
@@ -19671,7 +19685,17 @@ function BaseOptionRow(props) {
|
|
|
19671
19685
|
children: [
|
|
19672
19686
|
variant === "checkbox" && /* @__PURE__ */ jsx115(StyledCheckbox, { isSelected, isDisabled }),
|
|
19673
19687
|
variant === "checkbox" && mixedLegendId && /* @__PURE__ */ jsx115(MixedDot, {}),
|
|
19674
|
-
/* @__PURE__ */ jsx115("span", {
|
|
19688
|
+
/* @__PURE__ */ jsx115("span", { ...trussProps76({
|
|
19689
|
+
...{
|
|
19690
|
+
flexGrow: "fg1",
|
|
19691
|
+
minWidth: "mw0"
|
|
19692
|
+
},
|
|
19693
|
+
...isPathRoot ? {
|
|
19694
|
+
fontWeight: "fw6",
|
|
19695
|
+
fontSize: "fz_14px",
|
|
19696
|
+
lineHeight: "lh_20px"
|
|
19697
|
+
} : {}
|
|
19698
|
+
}), children: item.rendered }),
|
|
19675
19699
|
variant === "check" && isSelected && /* @__PURE__ */ jsx115("span", { className: "df aic fs0", children: /* @__PURE__ */ jsx115(Icon, { icon: "check", color: isDisabled ? "--b-text-disabled" /* TextDisabled */ : "--b-selection-indicator" /* SelectionIndicator */ }) }),
|
|
19676
19700
|
variant === "check" && mixedLegendId && // Centered in the check icon's 24px box.
|
|
19677
19701
|
/* @__PURE__ */ jsx115("span", { className: "df aic jcc fs0 h_24px w_24px", children: /* @__PURE__ */ jsx115(MixedDot, {}) })
|
|
@@ -19681,6 +19705,21 @@ function BaseOptionRow(props) {
|
|
|
19681
19705
|
});
|
|
19682
19706
|
}
|
|
19683
19707
|
function TreeOptionRow(props) {
|
|
19708
|
+
const {
|
|
19709
|
+
selectionMode,
|
|
19710
|
+
onExpandedChange,
|
|
19711
|
+
...rowProps
|
|
19712
|
+
} = props;
|
|
19713
|
+
if (selectionMode === "single") return /* @__PURE__ */ jsx115(SingleTreeOptionRow, { ...rowProps });
|
|
19714
|
+
return /* @__PURE__ */ jsx115(MultiTreeOptionRow, { ...rowProps, selectionMode, onExpandedChange });
|
|
19715
|
+
}
|
|
19716
|
+
function SingleTreeOptionRow({
|
|
19717
|
+
row,
|
|
19718
|
+
...rest
|
|
19719
|
+
}) {
|
|
19720
|
+
return /* @__PURE__ */ jsx115(BaseOptionRow, { ...rest, variant: "check", indent: rowPaddingX + row.level * singleTreeIndent, isPathRoot: row.level === 0 });
|
|
19721
|
+
}
|
|
19722
|
+
function MultiTreeOptionRow(props) {
|
|
19684
19723
|
const {
|
|
19685
19724
|
item,
|
|
19686
19725
|
state,
|
|
@@ -19771,6 +19810,7 @@ function TreeOptionRow(props) {
|
|
|
19771
19810
|
}
|
|
19772
19811
|
var menuRowHeight = 40;
|
|
19773
19812
|
var rowPaddingX = 16;
|
|
19813
|
+
var singleTreeIndent = 16;
|
|
19774
19814
|
var treeIndent = 28;
|
|
19775
19815
|
var rowCss = {
|
|
19776
19816
|
display: "df",
|
|
@@ -19848,7 +19888,7 @@ function OptionList(props) {
|
|
|
19848
19888
|
disabledReasons,
|
|
19849
19889
|
initialIndex,
|
|
19850
19890
|
loading,
|
|
19851
|
-
|
|
19891
|
+
selectionMode,
|
|
19852
19892
|
tree,
|
|
19853
19893
|
mixed
|
|
19854
19894
|
} = menu;
|
|
@@ -19877,8 +19917,7 @@ function OptionList(props) {
|
|
|
19877
19917
|
});
|
|
19878
19918
|
}, [focusedKey, state.collection]);
|
|
19879
19919
|
const [initialTop] = useState30(() => Math.max(0, Math.min(initialIndex, items.length - 1)));
|
|
19880
|
-
const Row2 =
|
|
19881
|
-
const isTree = rowVariant === "tree" && tree !== void 0;
|
|
19920
|
+
const Row2 = selectionMode === "multiple" ? MultiOptionRow : SingleOptionRow;
|
|
19882
19921
|
const isTest = process.env.NODE_ENV === "test";
|
|
19883
19922
|
return /* @__PURE__ */ jsx116("div", { ...listBoxProps, ...onKeyDown ? {
|
|
19884
19923
|
onKeyDown,
|
|
@@ -19902,10 +19941,10 @@ function OptionList(props) {
|
|
|
19902
19941
|
const item = items[index];
|
|
19903
19942
|
const entry = item?.value;
|
|
19904
19943
|
if (!item || !entry) return null;
|
|
19905
|
-
const treeRow =
|
|
19944
|
+
const treeRow = tree?.rows.get(String(item.key));
|
|
19906
19945
|
const mixedLegendId = mixed?.keys.has(entry.valueKey) ? mixed.legendId : void 0;
|
|
19907
19946
|
if (treeRow && tree) {
|
|
19908
|
-
return /* @__PURE__ */ jsx116(TreeOptionRow, { item, state, id: optionDomId(id, index), disabledReason: disabledReasons[entry.valueKey], mixedLegendId, row: treeRow, onExpandedChange: (expanded) => tree.setExpanded(String(item.key), expanded), ...tid });
|
|
19947
|
+
return /* @__PURE__ */ jsx116(TreeOptionRow, { item, state, id: optionDomId(id, index), disabledReason: disabledReasons[entry.valueKey], mixedLegendId, row: treeRow, selectionMode, onExpandedChange: (expanded) => tree.setExpanded(String(item.key), expanded), ...tid });
|
|
19909
19948
|
}
|
|
19910
19949
|
return /* @__PURE__ */ jsx116(Row2, { item, state, id: optionDomId(id, index), disabledReason: disabledReasons[entry.valueKey], mixedLegendId, ...tid });
|
|
19911
19950
|
} }, isTest ? items.length : "virtuoso"),
|
|
@@ -20178,10 +20217,10 @@ function useMenuSelectField(props) {
|
|
|
20178
20217
|
const getOptionLabel = (option) => unsetLabel && option === unsetOption ? unsetLabel : propGetOptionLabel(option);
|
|
20179
20218
|
const getOptionValue = (option) => unsetLabel && option === unsetOption ? void 0 : propGetOptionValue(option);
|
|
20180
20219
|
const options = useMemo28(
|
|
20181
|
-
() => initializeOptions(optionsProp, getOptionValue, getOptionLabel, unsetLabel, autoSort),
|
|
20220
|
+
() => initializeOptions(optionsProp, getOptionValue, getOptionLabel, unsetLabel, autoSort, getChildren),
|
|
20182
20221
|
// getOptionValue and getOptionLabel are typically inline lambdas
|
|
20183
20222
|
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
|
20184
|
-
[optionsProp, autoSort, unsetLabel]
|
|
20223
|
+
[optionsProp, autoSort, unsetLabel, getChildren]
|
|
20185
20224
|
);
|
|
20186
20225
|
const { hoverProps, isHovered } = useHover13({});
|
|
20187
20226
|
const { focusProps, isFocusVisible } = useFocusRing10();
|
|
@@ -20192,6 +20231,8 @@ function useMenuSelectField(props) {
|
|
|
20192
20231
|
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
|
20193
20232
|
[options, getChildren]
|
|
20194
20233
|
);
|
|
20234
|
+
const isSingleSelectTree = !multiple && menuTree !== void 0;
|
|
20235
|
+
const isMultiSelectTree = multiple && menuTree !== void 0;
|
|
20195
20236
|
const allOptions = useMemo28(
|
|
20196
20237
|
() => menuTree ? menuTree.orderedKeys.map((k) => menuTree.nodes.get(k).option) : options,
|
|
20197
20238
|
[menuTree, options]
|
|
@@ -20210,12 +20251,17 @@ function useMenuSelectField(props) {
|
|
|
20210
20251
|
const { effectiveValue, proposalProps } = useAiProposal(
|
|
20211
20252
|
propValues,
|
|
20212
20253
|
proposedValues,
|
|
20213
|
-
(vs) => labelsFor(
|
|
20254
|
+
(vs) => labelsFor(
|
|
20255
|
+
vs,
|
|
20256
|
+
allOptions,
|
|
20257
|
+
getOptionValue,
|
|
20258
|
+
(option) => isSingleSelectTree && menuTree ? optionPathLabel(menuTree, valueToKey(getOptionValue(option)), getOptionLabel) ?? getOptionLabel(option) : getOptionLabel(option)
|
|
20259
|
+
).join(", ")
|
|
20214
20260
|
);
|
|
20215
20261
|
const values = useMemo28(() => effectiveValue ?? [], [effectiveValue]);
|
|
20216
20262
|
const selectedKeys = useMemo28(
|
|
20217
|
-
() => menuTree ? normalizeTreeSelection(menuTree, values.map(valueToKey), disabledKeySet) : new Set(values.map(valueToKey)),
|
|
20218
|
-
[menuTree, values, disabledKeySet]
|
|
20263
|
+
() => isMultiSelectTree && menuTree ? normalizeTreeSelection(menuTree, values.map(valueToKey), disabledKeySet) : new Set(values.map(valueToKey)),
|
|
20264
|
+
[isMultiSelectTree, menuTree, values, disabledKeySet]
|
|
20219
20265
|
);
|
|
20220
20266
|
const selectedRowKeys = useMemo28(
|
|
20221
20267
|
() => menuTree ? new Set(menuTree.orderedKeys.filter((key) => selectedKeys.has(menuTree.nodes.get(key).valueKey))) : selectedKeys,
|
|
@@ -20259,10 +20305,11 @@ function useMenuSelectField(props) {
|
|
|
20259
20305
|
return visibleNestedRows(
|
|
20260
20306
|
roots,
|
|
20261
20307
|
(node) => childNodes(menuTree, node),
|
|
20262
|
-
|
|
20308
|
+
// A single-select hierarchy has no chevrons, so every node stays visible.
|
|
20309
|
+
isMultiSelectTree ? (node) => isExpanded(node.key) : () => true,
|
|
20263
20310
|
matchKeys ? (node) => matchKeys.has(node.valueKey) : void 0
|
|
20264
20311
|
);
|
|
20265
|
-
}, [menuTree, allOptions, search, serverSearch, contains, expandedKeys, searchCollapsedKeys]);
|
|
20312
|
+
}, [menuTree, isMultiSelectTree, allOptions, search, serverSearch, contains, expandedKeys, searchCollapsedKeys]);
|
|
20266
20313
|
const filteredOptions = useMemo28(
|
|
20267
20314
|
() => menuTree || !search || serverSearch ? options : options.filter(
|
|
20268
20315
|
(option) => unsetLabel && option === unsetOption ? contains(getOptionLabel(option), search) : matchesSearch(option, search, getOptionLabel, getOptionSearchText, contains)
|
|
@@ -20273,7 +20320,7 @@ function useMenuSelectField(props) {
|
|
|
20273
20320
|
);
|
|
20274
20321
|
function onSelectionChange(keys) {
|
|
20275
20322
|
if (keys === "all") return;
|
|
20276
|
-
if (menuTree) {
|
|
20323
|
+
if (isMultiSelectTree && menuTree) {
|
|
20277
20324
|
const added = [...keys].map(String).find((key2) => !selectedRowKeys.has(key2));
|
|
20278
20325
|
const removed = [...selectedRowKeys].find((key2) => !keys.has(key2));
|
|
20279
20326
|
const key = added ?? removed;
|
|
@@ -20290,7 +20337,7 @@ function useMenuSelectField(props) {
|
|
|
20290
20337
|
close({ restoreFocus: true });
|
|
20291
20338
|
return;
|
|
20292
20339
|
}
|
|
20293
|
-
const opt = optionsByKey.get(String(key));
|
|
20340
|
+
const opt = isSingleSelectTree && menuTree ? menuTree.nodes.get(String(key))?.option : optionsByKey.get(String(key));
|
|
20294
20341
|
proposalProps.onUserEdit?.();
|
|
20295
20342
|
onCommit(opt === void 0 ? [] : [getOptionValue(opt)], opt === void 0 ? [] : [opt]);
|
|
20296
20343
|
close({ restoreFocus: true });
|
|
@@ -20416,7 +20463,7 @@ function useMenuSelectField(props) {
|
|
|
20416
20463
|
switch (e.key) {
|
|
20417
20464
|
case "ArrowRight":
|
|
20418
20465
|
case "ArrowLeft":
|
|
20419
|
-
onTreeArrow(e, current2);
|
|
20466
|
+
if (isMultiSelectTree) onTreeArrow(e, current2);
|
|
20420
20467
|
break;
|
|
20421
20468
|
case "ArrowDown":
|
|
20422
20469
|
e.preventDefault();
|
|
@@ -20487,20 +20534,20 @@ function useMenuSelectField(props) {
|
|
|
20487
20534
|
0,
|
|
20488
20535
|
treeRows ? treeRows.findIndex(({ node }) => revealKeys.has(node.valueKey)) : filteredOptions.findIndex((o) => revealKeys.has(valueToKey(getOptionValue(o))))
|
|
20489
20536
|
);
|
|
20490
|
-
const selectedText = !multiple && selectedOptions[0] !== void 0 ? getOptionLabel(selectedOptions[0]) : "";
|
|
20537
|
+
const selectedText = !multiple && selectedOptions[0] !== void 0 ? isSingleSelectTree && menuTree ? optionPathLabel(menuTree, valueToKey(getOptionValue(selectedOptions[0])), getOptionLabel) ?? getOptionLabel(selectedOptions[0]) : getOptionLabel(selectedOptions[0]) : "";
|
|
20491
20538
|
const hasSelection = menuTree ? selectedKeys.size > 0 : values.length > 0;
|
|
20492
20539
|
const isMixed = dottedKeys.size > 0 && (multiple || !hasSelection);
|
|
20493
20540
|
const displayText = isMixed ? mixedLabel : selectedText || (hasSelection ? "" : nothingSelectedText || placeholder || "");
|
|
20494
20541
|
const isPlaceholder = !isMixed && !selectedText && !hasSelection && !nothingSelectedText && !!placeholder;
|
|
20495
|
-
const selectedLabels =
|
|
20542
|
+
const selectedLabels = isMultiSelectTree && getChildren && tree?.display ? bucketTreeSelection(selectedOptions, getChildren)[tree.display].map((option) => ({
|
|
20496
20543
|
key: valueToKey(getOptionValue(option)),
|
|
20497
20544
|
label: getOptionLabel(option)
|
|
20498
20545
|
})) : multiple ? selectedOptions.map((o) => ({ key: valueToKey(getOptionValue(o)), label: getOptionLabel(o) })) : [];
|
|
20499
20546
|
const badgeKeys = isMixed ? /* @__PURE__ */ new Set([...selectedLabels.map(({ key }) => key), ...dottedKeys]) : void 0;
|
|
20500
20547
|
const badgeLabels = badgeKeys ? [...optionsByKey].filter(([key]) => badgeKeys.has(key)).map(([key, option]) => ({ key, label: getOptionLabel(option) })) : selectedLabels;
|
|
20501
20548
|
const partialKeys = useMemo28(
|
|
20502
|
-
() => menuTree ? partiallySelectedKeys(menuTree, selectedKeys) : void 0,
|
|
20503
|
-
[menuTree, selectedKeys]
|
|
20549
|
+
() => isMultiSelectTree && menuTree ? partiallySelectedKeys(menuTree, selectedKeys) : void 0,
|
|
20550
|
+
[isMultiSelectTree, menuTree, selectedKeys]
|
|
20504
20551
|
);
|
|
20505
20552
|
const treeRowStates = treeRows ? new Map(
|
|
20506
20553
|
treeRows.map(({ node, level }) => [
|
|
@@ -20508,15 +20555,15 @@ function useMenuSelectField(props) {
|
|
|
20508
20555
|
{
|
|
20509
20556
|
level,
|
|
20510
20557
|
hasChildren: node.childKeys.length > 0,
|
|
20511
|
-
isExpanded: node.childKeys.length > 0 && isExpanded(node.key),
|
|
20512
|
-
isIndeterminate: !!partialKeys?.has(node.key)
|
|
20558
|
+
isExpanded: isMultiSelectTree ? node.childKeys.length > 0 && isExpanded(node.key) : true,
|
|
20559
|
+
isIndeterminate: isMultiSelectTree && !!partialKeys?.has(node.key)
|
|
20513
20560
|
}
|
|
20514
20561
|
])
|
|
20515
20562
|
) : void 0;
|
|
20516
20563
|
function deselect(key) {
|
|
20517
20564
|
if (!multiple || disabledKeys.includes(key)) return;
|
|
20518
20565
|
proposalProps.onUserEdit?.();
|
|
20519
|
-
if (menuTree) {
|
|
20566
|
+
if (isMultiSelectTree && menuTree) {
|
|
20520
20567
|
const toggledKeys = toggleTreeSelection(menuTree, selectedKeys, key, false, disabledKeySet);
|
|
20521
20568
|
commitTree(toggledKeys, key);
|
|
20522
20569
|
return;
|
|
@@ -20589,7 +20636,7 @@ function useMenuSelectField(props) {
|
|
|
20589
20636
|
loading: optionsLoading,
|
|
20590
20637
|
disabledReasons,
|
|
20591
20638
|
initialIndex,
|
|
20592
|
-
|
|
20639
|
+
selectionMode,
|
|
20593
20640
|
tree: treeRowStates ? { rows: treeRowStates, setExpanded: setTreeExpanded } : void 0,
|
|
20594
20641
|
mixed: dottedKeys.size > 0 ? { keys: dottedKeys, legendId } : void 0,
|
|
20595
20642
|
onKeyDown: onMenuKeyDown,
|
|
@@ -20659,6 +20706,17 @@ function labelsFor(values, options, getOptionValue, getOptionLabel) {
|
|
|
20659
20706
|
}
|
|
20660
20707
|
return labels;
|
|
20661
20708
|
}
|
|
20709
|
+
function optionPathLabel(tree, valueKey, getOptionLabel) {
|
|
20710
|
+
const node = tree.orderedKeys.map((key) => tree.nodes.get(key)).find((entry) => entry.valueKey === valueKey);
|
|
20711
|
+
if (!node) return void 0;
|
|
20712
|
+
const labels = [];
|
|
20713
|
+
let current2 = node;
|
|
20714
|
+
while (current2) {
|
|
20715
|
+
labels.unshift(getOptionLabel(current2.option));
|
|
20716
|
+
current2 = current2.parentKey === void 0 ? void 0 : tree.nodes.get(current2.parentKey);
|
|
20717
|
+
}
|
|
20718
|
+
return labels.join(" > ");
|
|
20719
|
+
}
|
|
20662
20720
|
function rootNodes(tree) {
|
|
20663
20721
|
return tree.orderedKeys.filter((key) => tree.nodes.get(key).parentKey === void 0).map((key) => tree.nodes.get(key));
|
|
20664
20722
|
}
|
|
@@ -20771,7 +20829,8 @@ function BaseMenuSelectField(props) {
|
|
|
20771
20829
|
// src/inputs/MenuSelectField/MenuSelectField.tsx
|
|
20772
20830
|
import { jsx as jsx119 } from "react/jsx-runtime";
|
|
20773
20831
|
function MenuSelectField(props) {
|
|
20774
|
-
const { value, proposedValue, onSelect, unsetLabel, ...rest } = props;
|
|
20832
|
+
const { value, proposedValue, onSelect, unsetLabel, options, autoSort, ...rest } = props;
|
|
20833
|
+
const nested = optionsHaveChildren(options);
|
|
20775
20834
|
const values = useMemo29(() => {
|
|
20776
20835
|
if (value !== void 0) return [value];
|
|
20777
20836
|
return unsetLabel ? [void 0] : [];
|
|
@@ -20781,10 +20840,13 @@ function MenuSelectField(props) {
|
|
|
20781
20840
|
BaseMenuSelectField,
|
|
20782
20841
|
{
|
|
20783
20842
|
...rest,
|
|
20843
|
+
options,
|
|
20784
20844
|
unsetLabel,
|
|
20845
|
+
autoSort: autoSort ?? !nested,
|
|
20785
20846
|
selectionMode: "single",
|
|
20786
20847
|
values,
|
|
20787
20848
|
proposedValues,
|
|
20849
|
+
tree: nested ? { getChildren: menuOptionChildren } : void 0,
|
|
20788
20850
|
onCommit: (next, opts) => {
|
|
20789
20851
|
const option = opts[0];
|
|
20790
20852
|
onSelect(next[0], option === unsetOption ? void 0 : option);
|
|
@@ -20792,6 +20854,19 @@ function MenuSelectField(props) {
|
|
|
20792
20854
|
}
|
|
20793
20855
|
);
|
|
20794
20856
|
}
|
|
20857
|
+
function optionsHaveChildren(options) {
|
|
20858
|
+
const list = Array.isArray(options) ? options : [
|
|
20859
|
+
...options.current === void 0 ? [] : Array.isArray(options.current) ? options.current : [options.current],
|
|
20860
|
+
...options.options ?? []
|
|
20861
|
+
];
|
|
20862
|
+
return list.some((option) => isNestedOption(option) && (option.children?.length ?? 0) > 0);
|
|
20863
|
+
}
|
|
20864
|
+
function menuOptionChildren(option) {
|
|
20865
|
+
return isNestedOption(option) ? option.children : void 0;
|
|
20866
|
+
}
|
|
20867
|
+
function isNestedOption(option) {
|
|
20868
|
+
return typeof option === "object" && option !== null && "children" in option && Array.isArray(option.children);
|
|
20869
|
+
}
|
|
20795
20870
|
|
|
20796
20871
|
// src/components/Filters/Filters.tsx
|
|
20797
20872
|
import { jsx as jsx120, jsxs as jsxs79 } from "react/jsx-runtime";
|