@homebound/beam 2.319.0 → 2.320.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/components/Filters/SingleFilter.js +1 -1
- package/dist/components/ScrollShadows.js +1 -1
- package/dist/inputs/SelectField.js +3 -1
- package/dist/inputs/TreeSelectField/TreeSelectField.js +1 -1
- package/dist/inputs/TreeSelectField/utils.d.ts +1 -1
- package/dist/inputs/internal/ComboBoxBase.d.ts +9 -4
- package/dist/inputs/internal/ComboBoxBase.js +31 -41
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ class SingleFilter extends BaseFilter_1.BaseFilter {
|
|
|
15
15
|
const { label, defaultValue, options: maybeOptions, getOptionLabel, getOptionValue, nothingSelectedText, ...props } = this.props;
|
|
16
16
|
const options = Array.isArray(maybeOptions)
|
|
17
17
|
? [allOption, ...maybeOptions]
|
|
18
|
-
: { ...maybeOptions,
|
|
18
|
+
: { ...maybeOptions, current: maybeOptions.current };
|
|
19
19
|
return ((0, jsx_runtime_1.jsx)(SelectField_1.SelectField, { ...props, options: options, getOptionValue: (o) => (o === allOption ? undefined : getOptionValue(o)), getOptionLabel: (o) => (o === allOption ? nothingSelectedText !== null && nothingSelectedText !== void 0 ? nothingSelectedText : "All" : getOptionLabel(o)), compact: !vertical, value: value, label: this.label, labelStyle: inModal ? "hidden" : !inModal && !vertical ? "inline" : "above", sizeToContent: !inModal && !vertical, nothingSelectedText: nothingSelectedText !== null && nothingSelectedText !== void 0 ? nothingSelectedText : "All", onSelect: (value) => setValue(value || undefined), ...this.testId(tid) }));
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -20,7 +20,7 @@ function ScrollShadows(props) {
|
|
|
20
20
|
// The shadow styles will rarely every change. Memoize them to avoid recomputing them when we don't have to.
|
|
21
21
|
const [startShadowStyles, endShadowStyles] = (0, react_1.useMemo)(() => {
|
|
22
22
|
const transparentBgColor = bgColor.replace(/,1\)$/, ",0)");
|
|
23
|
-
const commonStyles = src_1.Css.absolute.z3.$;
|
|
23
|
+
const commonStyles = src_1.Css.absolute.z3.add({ pointerEvents: "none" }).$;
|
|
24
24
|
const startShadowStyles = !horizontal ? src_1.Css.top0.left0.right0.hPx(40).$ : src_1.Css.left0.top0.bottom0.wPx(25).$;
|
|
25
25
|
const endShadowStyles = !horizontal ? src_1.Css.bottom0.left0.right0.hPx(40).$ : src_1.Css.right0.top0.bottom0.wPx(25).$;
|
|
26
26
|
const startGradient = `linear-gradient(${!horizontal ? 180 : 90}deg, ${bgColor} 0%, ${transparentBgColor} 92%);`;
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SelectField = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
5
6
|
const ComboBoxBase_1 = require("./internal/ComboBoxBase");
|
|
6
7
|
function SelectField(props) {
|
|
7
8
|
const { getOptionValue = (opt) => opt.id, // if unset, assume O implements HasId
|
|
8
9
|
getOptionLabel = (opt) => opt.name, // if unset, assume O implements HasName
|
|
9
10
|
options, onSelect, value, ...otherProps } = props;
|
|
10
|
-
|
|
11
|
+
const values = (0, react_1.useMemo)(() => [value], [value]);
|
|
12
|
+
return ((0, jsx_runtime_1.jsx)(ComboBoxBase_1.ComboBoxBase, { ...otherProps, options: options, getOptionLabel: getOptionLabel, getOptionValue: getOptionValue, values: values, onSelect: (values, options) => {
|
|
11
13
|
// If the user used `unsetLabel`, then values will be `[undefined]` and options `[unsetOption]`
|
|
12
14
|
if (values.length > 0 && options.length > 0) {
|
|
13
15
|
const option = options[0];
|
|
@@ -64,7 +64,7 @@ function TreeSelectFieldBase(props) {
|
|
|
64
64
|
const { values, options, getOptionValue, getOptionLabel, getOptionMenuLabel = getOptionLabel, disabled, readOnly, labelStyle, borderless, contrast = false, nothingSelectedText = "", onSelect, defaultCollapsed = false, placeholder, ...otherProps } = props;
|
|
65
65
|
const isDisabled = !!disabled;
|
|
66
66
|
const isReadOnly = !!readOnly;
|
|
67
|
-
const initialOptions = Array.isArray(options) ? options : options.
|
|
67
|
+
const initialOptions = Array.isArray(options) ? options : options.current;
|
|
68
68
|
const { contains } = (0, react_aria_1.useFilter)({ sensitivity: "base" });
|
|
69
69
|
const { collapsedKeys } = useTreeSelectFieldProvider();
|
|
70
70
|
function levelOptions(o, level, filtering) {
|
|
@@ -2,6 +2,7 @@ import React, { ReactNode } from "react";
|
|
|
2
2
|
import { PresentationFieldProps } from "../../components/PresentationContext";
|
|
3
3
|
import { Value } from "../Value";
|
|
4
4
|
import { BeamFocusableProps } from "../../interfaces";
|
|
5
|
+
/** Base props for either `SelectField` or `MultiSelectField`. */
|
|
5
6
|
export interface ComboBoxBaseProps<O, V extends Value> extends BeamFocusableProps, PresentationFieldProps {
|
|
6
7
|
/** Renders `opt` in the dropdown menu, defaults to the `getOptionLabel` prop. `isUnsetOpt` is only defined for single SelectField */
|
|
7
8
|
getOptionMenuLabel?: (opt: O, isUnsetOpt?: boolean) => string | ReactNode;
|
|
@@ -62,13 +63,17 @@ export interface ComboBoxBaseProps<O, V extends Value> extends BeamFocusableProp
|
|
|
62
63
|
* and so we cannot easily change them.
|
|
63
64
|
*/
|
|
64
65
|
export declare function ComboBoxBase<O, V extends Value>(props: ComboBoxBaseProps<O, V>): JSX.Element;
|
|
66
|
+
/** Allows lazy-loading select fields, which is useful for pages w/lots of fields the user may not actually use. */
|
|
65
67
|
export type OptionsOrLoad<O> = O[] | {
|
|
66
|
-
initial
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
/** The initial option to show before the user interacts with the dropdown. */
|
|
69
|
+
current: O | undefined;
|
|
70
|
+
/** Fired when the user interacts with the dropdown, to load the real options. */
|
|
71
|
+
load: () => Promise<unknown>;
|
|
72
|
+
/** The full list of options, after load() has been fired. */
|
|
73
|
+
options: O[] | undefined;
|
|
70
74
|
};
|
|
71
75
|
export declare function initializeOptions<O>(options: OptionsOrLoad<O>, unsetLabel: string | undefined): OptionsOrLoad<O>;
|
|
76
|
+
/** A marker option to automatically add an "Unset" option to the start of options. */
|
|
72
77
|
export declare const unsetOption: {};
|
|
73
78
|
export declare function disabledOptionToKeyedTuple(disabledOption: Value | {
|
|
74
79
|
value: Value;
|
|
@@ -25,31 +25,20 @@ const utils_1 = require("../../utils");
|
|
|
25
25
|
function ComboBoxBase(props) {
|
|
26
26
|
var _a, _b, _c, _d;
|
|
27
27
|
const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
|
|
28
|
-
const { disabled, readOnly, onSelect, options, multiselect = false, values = [], nothingSelectedText = "", contrast, disabledOptions, borderless, unsetLabel, ...otherProps } = props;
|
|
28
|
+
const { disabled, readOnly, onSelect, options, multiselect = false, values = [], nothingSelectedText = "", contrast, disabledOptions, borderless, unsetLabel, getOptionLabel: propOptionLabel, getOptionValue: propOptionValue, getOptionMenuLabel: propOptionMenuLabel, ...otherProps } = props;
|
|
29
29
|
const labelStyle = (_b = (_a = otherProps.labelStyle) !== null && _a !== void 0 ? _a : fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.labelStyle) !== null && _b !== void 0 ? _b : "above";
|
|
30
30
|
// Call `initializeOptions` to prepend the `unset` option if the `unsetLabel` was provided.
|
|
31
31
|
const maybeOptions = (0, react_1.useMemo)(() => initializeOptions(options, unsetLabel), [options, unsetLabel]);
|
|
32
32
|
// Memoize the callback functions and handle the `unset` option if provided.
|
|
33
|
-
const getOptionLabel = (0, react_1.useCallback)((o) => (unsetLabel && o === exports.unsetOption ? unsetLabel :
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[props.getOptionLabel, unsetLabel]);
|
|
37
|
-
const getOptionValue = (0, react_1.useCallback)((o) => (unsetLabel && o === exports.unsetOption ? undefined : props.getOptionValue(o)),
|
|
38
|
-
// 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
|
|
39
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
-
[props.getOptionValue, unsetLabel]);
|
|
41
|
-
const getOptionMenuLabel = (0, react_1.useCallback)((o) => props.getOptionMenuLabel
|
|
42
|
-
? props.getOptionMenuLabel(o, Boolean(unsetLabel) && o === exports.unsetOption)
|
|
43
|
-
: getOptionLabel(o),
|
|
44
|
-
// 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
|
|
45
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
46
|
-
[props.getOptionValue, unsetLabel, getOptionLabel]);
|
|
33
|
+
const getOptionLabel = (0, react_1.useCallback)((o) => (unsetLabel && o === exports.unsetOption ? unsetLabel : propOptionLabel(o)), [propOptionLabel, unsetLabel]);
|
|
34
|
+
const getOptionValue = (0, react_1.useCallback)((o) => (unsetLabel && o === exports.unsetOption ? undefined : propOptionValue(o)), [propOptionValue, unsetLabel]);
|
|
35
|
+
const getOptionMenuLabel = (0, react_1.useCallback)((o) => propOptionMenuLabel ? propOptionMenuLabel(o, Boolean(unsetLabel) && o === exports.unsetOption) : getOptionLabel(o), [propOptionMenuLabel, unsetLabel, getOptionLabel]);
|
|
47
36
|
const { contains } = (0, react_aria_1.useFilter)({ sensitivity: "base" });
|
|
48
37
|
const isDisabled = !!disabled;
|
|
49
38
|
const isReadOnly = !!readOnly;
|
|
50
39
|
const [fieldState, setFieldState] = (0, react_1.useState)(() => {
|
|
51
40
|
var _a;
|
|
52
|
-
const initOptions = Array.isArray(maybeOptions) ? maybeOptions : maybeOptions.
|
|
41
|
+
const initOptions = Array.isArray(maybeOptions) ? maybeOptions : asArray(maybeOptions.current);
|
|
53
42
|
const selectedOptions = initOptions.filter((o) => values.includes(getOptionValue(o)));
|
|
54
43
|
return {
|
|
55
44
|
selectedKeys: (_a = selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.map((o) => (0, Value_1.valueToKey)(getOptionValue(o)))) !== null && _a !== void 0 ? _a : [],
|
|
@@ -125,15 +114,8 @@ function ComboBoxBase(props) {
|
|
|
125
114
|
async function maybeInitLoad() {
|
|
126
115
|
if (!Array.isArray(maybeOptions)) {
|
|
127
116
|
setFieldState((prevState) => ({ ...prevState, optionsLoading: true }));
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const options = !unsetLabel ? loadedOptions : getOptionsWithUnset(unsetLabel, loadedOptions);
|
|
131
|
-
setFieldState((prevState) => ({
|
|
132
|
-
...prevState,
|
|
133
|
-
filteredOptions: options,
|
|
134
|
-
allOptions: options,
|
|
135
|
-
optionsLoading: false,
|
|
136
|
-
}));
|
|
117
|
+
await maybeOptions.load();
|
|
118
|
+
setFieldState((prevState) => ({ ...prevState, optionsLoading: false }));
|
|
137
119
|
}
|
|
138
120
|
}
|
|
139
121
|
const firstOpen = (0, react_1.useRef)(true);
|
|
@@ -216,19 +198,22 @@ function ComboBoxBase(props) {
|
|
|
216
198
|
// 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
|
|
217
199
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
218
200
|
[values]);
|
|
201
|
+
// When options are an array, then use them as-is.
|
|
202
|
+
// If options are an object, then use the `initial` array if the menu has not been opened
|
|
203
|
+
// Otherwise, use the current fieldState array options.
|
|
204
|
+
const maybeUpdatedOptions = Array.isArray(maybeOptions)
|
|
205
|
+
? maybeOptions
|
|
206
|
+
: firstOpen.current === false && !fieldState.optionsLoading
|
|
207
|
+
? maybeOptions.options
|
|
208
|
+
: maybeOptions.current;
|
|
219
209
|
(0, react_1.useEffect)(() => {
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
? maybeOptions
|
|
225
|
-
: firstOpen.current === false
|
|
226
|
-
? fieldState.allOptions
|
|
227
|
-
: maybeOptions.initial;
|
|
228
|
-
if (maybeUpdatedOptions !== fieldState.allOptions) {
|
|
210
|
+
// We leave `maybeOptions.initial` as a non-array so that it's stable, but now that we're inside the
|
|
211
|
+
// useEffect, array-ize it if needed.
|
|
212
|
+
const maybeUpdatedArray = asArray(maybeUpdatedOptions);
|
|
213
|
+
if (maybeUpdatedArray !== fieldState.allOptions) {
|
|
229
214
|
setFieldState((prevState) => {
|
|
230
215
|
var _a;
|
|
231
|
-
const selectedOptions =
|
|
216
|
+
const selectedOptions = maybeUpdatedArray.filter((o) => values === null || values === void 0 ? void 0 : values.includes(getOptionValue(o)));
|
|
232
217
|
return {
|
|
233
218
|
...prevState,
|
|
234
219
|
selectedKeys: (_a = selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.map((o) => (0, Value_1.valueToKey)(getOptionValue(o)))) !== null && _a !== void 0 ? _a : [],
|
|
@@ -238,15 +223,16 @@ function ComboBoxBase(props) {
|
|
|
238
223
|
? nothingSelectedText
|
|
239
224
|
: "",
|
|
240
225
|
selectedOptions: selectedOptions,
|
|
241
|
-
filteredOptions:
|
|
242
|
-
allOptions:
|
|
226
|
+
filteredOptions: maybeUpdatedArray,
|
|
227
|
+
allOptions: maybeUpdatedArray,
|
|
243
228
|
};
|
|
244
229
|
});
|
|
245
230
|
}
|
|
246
231
|
},
|
|
247
|
-
//
|
|
232
|
+
// I started working on fixing this deps array, but seems like `getOptionLabel` & friends
|
|
233
|
+
// would very rarely be stable anyway, so going to hold off on further fixes for now...
|
|
248
234
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
249
|
-
[
|
|
235
|
+
[maybeUpdatedOptions, getOptionLabel, getOptionValue]);
|
|
250
236
|
// For the most part, the returned props contain `aria-*` and `id` attributes for accessibility purposes.
|
|
251
237
|
const { buttonProps: triggerProps, inputProps, listBoxProps, labelProps, } = (0, react_aria_1.useComboBox)({
|
|
252
238
|
...comboBoxProps,
|
|
@@ -290,12 +276,13 @@ function initializeOptions(options, unsetLabel) {
|
|
|
290
276
|
if (Array.isArray(options)) {
|
|
291
277
|
return getOptionsWithUnset(unsetLabel, options);
|
|
292
278
|
}
|
|
293
|
-
return { ...options,
|
|
279
|
+
return { ...options, options: getOptionsWithUnset(unsetLabel, options.options) };
|
|
294
280
|
}
|
|
295
281
|
exports.initializeOptions = initializeOptions;
|
|
296
282
|
function getOptionsWithUnset(unsetLabel, options) {
|
|
297
|
-
return [exports.unsetOption, ...options];
|
|
283
|
+
return [exports.unsetOption, ...(options ? options : [])];
|
|
298
284
|
}
|
|
285
|
+
/** A marker option to automatically add an "Unset" option to the start of options. */
|
|
299
286
|
exports.unsetOption = {};
|
|
300
287
|
function disabledOptionToKeyedTuple(disabledOption) {
|
|
301
288
|
if (typeof disabledOption === "object" && disabledOption !== null) {
|
|
@@ -306,3 +293,6 @@ function disabledOptionToKeyedTuple(disabledOption) {
|
|
|
306
293
|
}
|
|
307
294
|
}
|
|
308
295
|
exports.disabledOptionToKeyedTuple = disabledOptionToKeyedTuple;
|
|
296
|
+
function asArray(arrayOrElement) {
|
|
297
|
+
return Array.isArray(arrayOrElement) ? arrayOrElement : arrayOrElement ? [arrayOrElement] : [];
|
|
298
|
+
}
|