@homebound/beam 2.219.0 → 2.220.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/inputs/internal/ListBox.d.ts +1 -0
- package/dist/inputs/internal/ListBox.js +3 -3
- package/dist/inputs/internal/ListBoxSection.d.ts +1 -0
- package/dist/inputs/internal/ListBoxSection.js +2 -2
- package/dist/inputs/internal/Option.d.ts +1 -0
- package/dist/inputs/internal/Option.js +21 -16
- package/dist/inputs/internal/SelectFieldBase.d.ts +4 -1
- package/dist/inputs/internal/SelectFieldBase.js +15 -4
- package/dist/inputs/internal/VirtualizedOptions.d.ts +1 -0
- package/dist/inputs/internal/VirtualizedOptions.js +2 -2
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ interface ListBoxProps<O, V extends Key> {
|
|
|
9
9
|
contrast?: boolean;
|
|
10
10
|
positionProps: React.HTMLAttributes<Element>;
|
|
11
11
|
loading?: boolean | (() => JSX.Element);
|
|
12
|
+
disabledOptionsWithReasons?: Record<string, string | undefined>;
|
|
12
13
|
}
|
|
13
14
|
/** A ListBox is an internal component used by SelectField and MultiSelectField to display the list of options */
|
|
14
15
|
export declare function ListBox<O, V extends Key>(props: ListBoxProps<O, V>): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -12,7 +12,7 @@ const VirtualizedOptions_1 = require("./VirtualizedOptions");
|
|
|
12
12
|
/** A ListBox is an internal component used by SelectField and MultiSelectField to display the list of options */
|
|
13
13
|
function ListBox(props) {
|
|
14
14
|
var _a;
|
|
15
|
-
const { state, listBoxRef, selectedOptions = [], getOptionLabel, getOptionValue, contrast = false, positionProps, loading, } = props;
|
|
15
|
+
const { state, listBoxRef, selectedOptions = [], getOptionLabel, getOptionValue, contrast = false, positionProps, loading, disabledOptionsWithReasons = {}, } = props;
|
|
16
16
|
const { listBoxProps } = (0, react_aria_1.useListBox)({ disallowEmptySelection: true, ...props }, state, listBoxRef);
|
|
17
17
|
const positionMaxHeight = (_a = positionProps.style) === null || _a === void 0 ? void 0 : _a.maxHeight;
|
|
18
18
|
// The popoverMaxHeight will be based on the value defined by the positionProps returned from `useOverlayPosition` (which will always be a defined as a `number` based on React-Aria's `calculatePosition`).
|
|
@@ -57,9 +57,9 @@ function ListBox(props) {
|
|
|
57
57
|
"&:hover": Css_1.Css.bshHover.$,
|
|
58
58
|
}, ref: listBoxRef }, listBoxProps, { children: [isMultiSelect && state.selectionManager.selectedKeys.size > 0 && ((0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.pt2.pl2.pb1.pr1.df.bb.bGray200.add("flexWrap", "wrap").$, ref: selectedList }, { children: selectedOptions.map((o) => ((0, jsx_runtime_1.jsx)(ListBoxToggleChip_1.ListBoxToggleChip, { state: state, option: o, getOptionValue: getOptionValue, getOptionLabel: getOptionLabel, disabled: state.disabledKeys.has(getOptionValue(o)) }, getOptionValue(o)))) }), void 0)), (0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.fg1.$ }, { children: hasSections ? ([...state.collection].map((section) => ((0, jsx_runtime_1.jsx)(ListBoxSection_1.ListBoxSection, { section: section, state: state, contrast: contrast, onListHeightChange: onListHeightChange, popoverHeight: popoverHeight,
|
|
59
59
|
// Only scroll on focus if using VirtualFocus (used for ComboBoxState (SelectField), but not SelectState (ChipSelectField))
|
|
60
|
-
scrollOnFocus: props.shouldUseVirtualFocus }, section.key)))) : ((0, jsx_runtime_1.jsx)(VirtualizedOptions_1.VirtualizedOptions, { state: state, items: [...state.collection], onListHeightChange: onListHeightChange, contrast: contrast,
|
|
60
|
+
scrollOnFocus: props.shouldUseVirtualFocus, disabledOptionsWithReasons: disabledOptionsWithReasons }, section.key)))) : ((0, jsx_runtime_1.jsx)(VirtualizedOptions_1.VirtualizedOptions, { state: state, items: [...state.collection], onListHeightChange: onListHeightChange, contrast: contrast,
|
|
61
61
|
// Only scroll on focus if using VirtualFocus (used for ComboBoxState (SelectField), but not SelectState (ChipSelectField))
|
|
62
|
-
scrollOnFocus: props.shouldUseVirtualFocus, loading: loading }, void 0)) }), void 0)] }), void 0));
|
|
62
|
+
scrollOnFocus: props.shouldUseVirtualFocus, loading: loading, disabledOptionsWithReasons: disabledOptionsWithReasons }, void 0)) }), void 0)] }), void 0));
|
|
63
63
|
}
|
|
64
64
|
exports.ListBox = ListBox;
|
|
65
65
|
// UX specified maximum height for a ListBox (in pixels)
|
|
@@ -7,6 +7,7 @@ interface ListBoxSectionProps<O> {
|
|
|
7
7
|
onListHeightChange: (height: number) => void;
|
|
8
8
|
popoverHeight: number;
|
|
9
9
|
scrollOnFocus?: boolean;
|
|
10
|
+
disabledOptionsWithReasons: Record<string, string | undefined>;
|
|
10
11
|
}
|
|
11
12
|
export declare function ListBoxSection<O>(props: ListBoxSectionProps<O>): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
12
13
|
export {};
|
|
@@ -10,11 +10,11 @@ const VirtualizedOptions_1 = require("./VirtualizedOptions");
|
|
|
10
10
|
// Creates a section of options within a ListBox.
|
|
11
11
|
// Currently only expects two possible sections; 1. The list of options, and 2. A persistent action (in that order).
|
|
12
12
|
function ListBoxSection(props) {
|
|
13
|
-
const { section, state, contrast, onListHeightChange, popoverHeight, scrollOnFocus } = props;
|
|
13
|
+
const { section, state, contrast, onListHeightChange, popoverHeight, scrollOnFocus, disabledOptionsWithReasons } = props;
|
|
14
14
|
const { itemProps, groupProps } = (0, react_aria_1.useListBoxSection)(section);
|
|
15
15
|
const { separatorProps } = (0, react_aria_1.useSeparator)({ elementType: "li" });
|
|
16
16
|
const isPersistentSection = section.key !== state.collection.getFirstKey();
|
|
17
17
|
const childNodes = [...section.childNodes];
|
|
18
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isPersistentSection && (0, jsx_runtime_1.jsx)("li", Object.assign({}, separatorProps, { css: Css_1.Css.bt.bGray200.$ }), void 0), (0, jsx_runtime_1.jsx)("li", Object.assign({}, itemProps, { css: Css_1.Css.if(!isPersistentSection).overflowAuto.$ }, { children: (0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.if(!isPersistentSection).hPx(popoverHeight - constants_1.sectionSeparatorHeight - constants_1.persistentItemHeight).$ }, groupProps, { children: isPersistentSection ? (childNodes.map((item) => (0, jsx_runtime_1.jsx)(Option_1.Option, { item: item, state: state, contrast: contrast }, item.key))) : ((0, jsx_runtime_1.jsx)(VirtualizedOptions_1.VirtualizedOptions, { state: state, items: childNodes, onListHeightChange: onListHeightChange, contrast: contrast, scrollOnFocus: scrollOnFocus }, void 0)) }), void 0) }), void 0)] }, void 0));
|
|
18
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isPersistentSection && (0, jsx_runtime_1.jsx)("li", Object.assign({}, separatorProps, { css: Css_1.Css.bt.bGray200.$ }), void 0), (0, jsx_runtime_1.jsx)("li", Object.assign({}, itemProps, { css: Css_1.Css.if(!isPersistentSection).overflowAuto.$ }, { children: (0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.if(!isPersistentSection).hPx(popoverHeight - constants_1.sectionSeparatorHeight - constants_1.persistentItemHeight).$ }, groupProps, { children: isPersistentSection ? (childNodes.map((item) => ((0, jsx_runtime_1.jsx)(Option_1.Option, { item: item, state: state, contrast: contrast, disabledReason: disabledOptionsWithReasons[item.key] }, item.key)))) : ((0, jsx_runtime_1.jsx)(VirtualizedOptions_1.VirtualizedOptions, { state: state, items: childNodes, onListHeightChange: onListHeightChange, contrast: contrast, scrollOnFocus: scrollOnFocus, disabledOptionsWithReasons: disabledOptionsWithReasons }, void 0)) }), void 0) }), void 0)] }, void 0));
|
|
19
19
|
}
|
|
20
20
|
exports.ListBoxSection = ListBoxSection;
|
|
@@ -5,6 +5,7 @@ interface OptionProps<O> {
|
|
|
5
5
|
state: ListState<O> | TreeState<O>;
|
|
6
6
|
contrast?: boolean;
|
|
7
7
|
scrollToIndex?: (index: number) => void;
|
|
8
|
+
disabledReason?: string;
|
|
8
9
|
}
|
|
9
10
|
/** Represents a single option within a ListBox - used by SelectField and MultiSelectField */
|
|
10
11
|
export declare function Option<O>(props: OptionProps<O>): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -4,12 +4,13 @@ exports.Option = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const react_aria_1 = require("react-aria");
|
|
7
|
+
const components_1 = require("../../components");
|
|
7
8
|
const Icon_1 = require("../../components/Icon");
|
|
8
9
|
const Css_1 = require("../../Css");
|
|
9
10
|
const ChipSelectField_1 = require("../ChipSelectField");
|
|
10
11
|
/** Represents a single option within a ListBox - used by SelectField and MultiSelectField */
|
|
11
12
|
function Option(props) {
|
|
12
|
-
const { item, state, contrast = false, scrollToIndex } = props;
|
|
13
|
+
const { item, state, contrast = false, scrollToIndex, disabledReason } = props;
|
|
13
14
|
const ref = (0, react_1.useRef)(null);
|
|
14
15
|
const { hoverProps, isHovered } = (0, react_aria_1.useHover)({});
|
|
15
16
|
const themeStyles = {
|
|
@@ -39,20 +40,24 @@ function Option(props) {
|
|
|
39
40
|
scrollToIndex(toItem.index);
|
|
40
41
|
}
|
|
41
42
|
}, [scrollToIndex, state]);
|
|
42
|
-
return (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
43
|
+
return (0, components_1.maybeTooltip)({
|
|
44
|
+
title: disabledReason,
|
|
45
|
+
placement: "right",
|
|
46
|
+
children: ((0, jsx_runtime_1.jsxs)("li", Object.assign({}, (0, react_aria_1.mergeProps)(optionProps, hoverProps, { onKeyDown }), { ref: ref, css: {
|
|
47
|
+
...Css_1.Css.df.aic.jcsb.py1.px2.mh("42px").outline0.cursorPointer.sm.$,
|
|
48
|
+
// Assumes only one Persistent Item per list - will need to change to utilize Sections if that assumption is incorrect.
|
|
49
|
+
...((0, ChipSelectField_1.isPersistentKey)(item.key) ? Css_1.Css.bt.bGray200.$ : {}),
|
|
50
|
+
...themeStyles.item,
|
|
51
|
+
...(isHovered && !isDisabled ? themeStyles.hover : {}),
|
|
52
|
+
...(isFocused ? themeStyles.focus : {}),
|
|
53
|
+
...(isDisabled ? themeStyles.disabled : {}),
|
|
54
|
+
} }, { children: [item.rendered, isSelected && ((0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.fs0.$ }, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { icon: "check", color: !contrast
|
|
55
|
+
? isDisabled
|
|
56
|
+
? Css_1.Palette.Gray400
|
|
57
|
+
: Css_1.Palette.LightBlue700
|
|
58
|
+
: isDisabled
|
|
59
|
+
? Css_1.Palette.Gray500
|
|
60
|
+
: Css_1.Palette.White }, void 0) }), void 0))] }), void 0)),
|
|
61
|
+
});
|
|
57
62
|
}
|
|
58
63
|
exports.Option = Option;
|
|
@@ -11,7 +11,10 @@ export interface BeamSelectFieldBaseProps<O, V extends Value> extends BeamFocusa
|
|
|
11
11
|
values: V[] | undefined;
|
|
12
12
|
onSelect: (values: V[], opts: O[]) => void;
|
|
13
13
|
multiselect?: boolean;
|
|
14
|
-
disabledOptions?: V
|
|
14
|
+
disabledOptions?: (V | {
|
|
15
|
+
value: V;
|
|
16
|
+
reason: string;
|
|
17
|
+
})[];
|
|
15
18
|
options: OptionsOrLoad<O>;
|
|
16
19
|
/** Whether the field is disabled. If a ReactNode, it's treated as a "disabled reason" that's shown in a tooltip. */
|
|
17
20
|
disabled?: boolean | ReactNode;
|
|
@@ -22,7 +22,7 @@ const utils_1 = require("../../utils");
|
|
|
22
22
|
* and so we cannot easily change them.
|
|
23
23
|
*/
|
|
24
24
|
function SelectFieldBase(props) {
|
|
25
|
-
var _a;
|
|
25
|
+
var _a, _b;
|
|
26
26
|
const { disabled, readOnly, onSelect, options, multiselect = false, values = [], nothingSelectedText = "", contrast, disabledOptions, borderless, unsetLabel, ...otherProps } = props;
|
|
27
27
|
// Call `initializeOptions` to prepend the `unset` option if the `unsetLabel` was provided.
|
|
28
28
|
const maybeOptions = (0, react_1.useMemo)(() => initializeOptions(options, unsetLabel), [options, unsetLabel]);
|
|
@@ -143,9 +143,12 @@ function SelectFieldBase(props) {
|
|
|
143
143
|
const inputWrapRef = (0, react_1.useRef)(null);
|
|
144
144
|
const listBoxRef = (0, react_1.useRef)(null);
|
|
145
145
|
const popoverRef = (0, react_1.useRef)(null);
|
|
146
|
+
// `disabledKeys` from ComboBoxState does not support additional meta for showing a disabled reason to the user
|
|
147
|
+
// This lookup map helps us cleanly prune out the optional reason text, then access it further down the component tree
|
|
148
|
+
const disabledOptionsWithReasons = Object.fromEntries((_a = disabledOptions === null || disabledOptions === void 0 ? void 0 : disabledOptions.map(disabledOptionToKeyedTuple)) !== null && _a !== void 0 ? _a : []);
|
|
146
149
|
const comboBoxProps = {
|
|
147
150
|
...otherProps,
|
|
148
|
-
disabledKeys:
|
|
151
|
+
disabledKeys: Object.keys(disabledOptionsWithReasons),
|
|
149
152
|
inputValue: fieldState.inputValue,
|
|
150
153
|
items: fieldState.filteredOptions,
|
|
151
154
|
isDisabled,
|
|
@@ -240,11 +243,11 @@ function SelectFieldBase(props) {
|
|
|
240
243
|
});
|
|
241
244
|
positionProps.style = {
|
|
242
245
|
...positionProps.style,
|
|
243
|
-
width: (
|
|
246
|
+
width: (_b = comboBoxRef === null || comboBoxRef === void 0 ? void 0 : comboBoxRef.current) === null || _b === void 0 ? void 0 : _b.clientWidth,
|
|
244
247
|
// Ensures the menu never gets too small.
|
|
245
248
|
minWidth: 200,
|
|
246
249
|
};
|
|
247
|
-
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.fdc.w100.maxw((0, Css_1.px)(550)).$, ref: comboBoxRef }, { children: [(0, jsx_runtime_1.jsx)(SelectFieldInput_1.SelectFieldInput, Object.assign({}, otherProps, { buttonProps: buttonProps, buttonRef: triggerRef, inputProps: inputProps, inputRef: inputRef, inputWrapRef: inputWrapRef, state: state, labelProps: labelProps, selectedOptions: fieldState.selectedOptions, getOptionValue: getOptionValue, getOptionLabel: getOptionLabel, contrast: contrast, nothingSelectedText: nothingSelectedText, borderless: borderless, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly), resetField: resetField }), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: triggerRef, popoverRef: popoverRef, positionProps: positionProps, onClose: () => state.close(), isOpen: state.isOpen, minWidth: 200 }, { children: (0, jsx_runtime_1.jsx)(ListBox_1.ListBox, Object.assign({}, listBoxProps, { positionProps: positionProps, state: state, listBoxRef: listBoxRef, selectedOptions: fieldState.selectedOptions, getOptionLabel: getOptionLabel, getOptionValue: (o) => (0, Value_1.valueToKey)(getOptionValue(o)), contrast: contrast, loading: fieldState.optionsLoading }), void 0) }), void 0))] }), void 0));
|
|
250
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.fdc.w100.maxw((0, Css_1.px)(550)).$, ref: comboBoxRef }, { children: [(0, jsx_runtime_1.jsx)(SelectFieldInput_1.SelectFieldInput, Object.assign({}, otherProps, { buttonProps: buttonProps, buttonRef: triggerRef, inputProps: inputProps, inputRef: inputRef, inputWrapRef: inputWrapRef, state: state, labelProps: labelProps, selectedOptions: fieldState.selectedOptions, getOptionValue: getOptionValue, getOptionLabel: getOptionLabel, contrast: contrast, nothingSelectedText: nothingSelectedText, borderless: borderless, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly), resetField: resetField }), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: triggerRef, popoverRef: popoverRef, positionProps: positionProps, onClose: () => state.close(), isOpen: state.isOpen, minWidth: 200 }, { children: (0, jsx_runtime_1.jsx)(ListBox_1.ListBox, Object.assign({}, listBoxProps, { positionProps: positionProps, state: state, listBoxRef: listBoxRef, selectedOptions: fieldState.selectedOptions, getOptionLabel: getOptionLabel, getOptionValue: (o) => (0, Value_1.valueToKey)(getOptionValue(o)), contrast: contrast, loading: fieldState.optionsLoading, disabledOptionsWithReasons: disabledOptionsWithReasons }), void 0) }), void 0))] }), void 0));
|
|
248
251
|
}
|
|
249
252
|
exports.SelectFieldBase = SelectFieldBase;
|
|
250
253
|
function getInputValue(selectedOptions, getOptionLabel, multiselect, nothingSelectedText) {
|
|
@@ -268,3 +271,11 @@ function getOptionsWithUnset(unsetLabel, options) {
|
|
|
268
271
|
return [exports.unsetOption, ...options];
|
|
269
272
|
}
|
|
270
273
|
exports.unsetOption = {};
|
|
274
|
+
function disabledOptionToKeyedTuple(disabledOption) {
|
|
275
|
+
if (typeof disabledOption === "object" && disabledOption !== null) {
|
|
276
|
+
return [(0, Value_1.valueToKey)(disabledOption.value), disabledOption.reason];
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
return [(0, Value_1.valueToKey)(disabledOption), undefined];
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -7,6 +7,7 @@ interface VirtualizedOptionsProps<O> {
|
|
|
7
7
|
contrast: boolean;
|
|
8
8
|
scrollOnFocus?: boolean;
|
|
9
9
|
loading?: boolean | (() => JSX.Element);
|
|
10
|
+
disabledOptionsWithReasons: Record<string, string | undefined>;
|
|
10
11
|
}
|
|
11
12
|
export declare function VirtualizedOptions<O>(props: VirtualizedOptionsProps<O>): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
12
13
|
export {};
|
|
@@ -8,7 +8,7 @@ const LoadingDots_1 = require("./LoadingDots");
|
|
|
8
8
|
const Option_1 = require("./Option");
|
|
9
9
|
// Displays ListBox options in a virtualized container for performance reasons
|
|
10
10
|
function VirtualizedOptions(props) {
|
|
11
|
-
const { state, items, onListHeightChange, contrast, scrollOnFocus, loading } = props;
|
|
11
|
+
const { state, items, onListHeightChange, contrast, scrollOnFocus, loading, disabledOptionsWithReasons } = props;
|
|
12
12
|
const virtuosoRef = (0, react_1.useRef)(null);
|
|
13
13
|
const focusedItem = state.collection.getItem(state.selectionManager.focusedKey);
|
|
14
14
|
const selectedItem = state.selectionManager.selectedKeys.size > 0
|
|
@@ -32,7 +32,7 @@ function VirtualizedOptions(props) {
|
|
|
32
32
|
if (item) {
|
|
33
33
|
return ((0, jsx_runtime_1.jsx)(Option_1.Option, { item: item, state: state, contrast: contrast,
|
|
34
34
|
// Only send scrollToIndex functionality forward if we are not auto-scrolling on focus.
|
|
35
|
-
scrollToIndex: scrollOnFocus ? undefined : (_a = virtuosoRef.current) === null || _a === void 0 ? void 0 : _a.scrollToIndex }, item.key));
|
|
35
|
+
scrollToIndex: scrollOnFocus ? undefined : (_a = virtuosoRef.current) === null || _a === void 0 ? void 0 : _a.scrollToIndex, disabledReason: disabledOptionsWithReasons[item.key] }, item.key));
|
|
36
36
|
}
|
|
37
37
|
}, components: !loading
|
|
38
38
|
? {}
|