@homebound/beam 2.90.4 → 2.91.3
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/Table/GridTable.js +1 -1
- package/dist/inputs/ChipSelectField.d.ts +1 -1
- package/dist/inputs/ChipSelectField.js +31 -18
- package/dist/inputs/DateField.js +7 -0
- package/dist/inputs/NumberField.js +7 -0
- package/dist/inputs/TextAreaField.js +4 -1
- package/dist/inputs/TextField.js +10 -1
- package/dist/inputs/internal/SelectFieldBase.js +5 -0
- package/package.json +1 -1
|
@@ -340,7 +340,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
340
340
|
else {
|
|
341
341
|
throw new Error("as=virtual only supports px, percentage, or fr units");
|
|
342
342
|
}
|
|
343
|
-
}, { claimedPercentages: 0, claimedPixels: 0, totalFr: 0 });
|
|
343
|
+
}, { claimedPercentages: 0, claimedPixels: firstLastColumnWidth ? firstLastColumnWidth * 2 : 0, totalFr: 0 });
|
|
344
344
|
// This is our "fake but for some reason it lines up better" fr calc
|
|
345
345
|
function fr(myFr) {
|
|
346
346
|
return `calc((100% - ${claimedPercentages}% - ${claimedPixels}px) * (${myFr} / ${totalFr}))`;
|
|
@@ -12,7 +12,7 @@ export interface ChipSelectFieldProps<O, V extends Value> {
|
|
|
12
12
|
onBlur?: () => void;
|
|
13
13
|
onFocus?: () => void;
|
|
14
14
|
clearable?: boolean;
|
|
15
|
-
onCreateNew?: (value: string) => Promise<
|
|
15
|
+
onCreateNew?: (value: string) => Promise<void>;
|
|
16
16
|
disabled?: boolean | ReactNode;
|
|
17
17
|
}
|
|
18
18
|
export declare function ChipSelectField<O, V extends Value>(props: ChipSelectFieldProps<O, V>): JSX.Element;
|
|
@@ -25,7 +25,8 @@ function ChipSelectField(props) {
|
|
|
25
25
|
const isDisabled = !!disabled;
|
|
26
26
|
const showClearButton = !disabled && clearable && !!value;
|
|
27
27
|
const chipStyles = Css_1.Css[typeScale].tl.bgGray300.gray900.br16.pxPx(10).pyPx(2).$;
|
|
28
|
-
|
|
28
|
+
// Controls showing the focus border styles.
|
|
29
|
+
const [visualFocus, setVisualFocus] = (0, react_1.useState)(false);
|
|
29
30
|
const [isClearFocused, setIsClearFocused] = (0, react_1.useState)(false);
|
|
30
31
|
const { focusProps } = (0, react_aria_1.useFocus)({
|
|
31
32
|
onFocus: (e) => {
|
|
@@ -35,10 +36,15 @@ function ChipSelectField(props) {
|
|
|
35
36
|
}
|
|
36
37
|
(0, utils_1.maybeCall)(onFocus);
|
|
37
38
|
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
onBlur: (e) => {
|
|
40
|
+
// Do not call onBlur if focus moved to within the Popover
|
|
41
|
+
if (popoverRef.current && popoverRef.current.contains(e.relatedTarget)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
(0, utils_1.maybeCall)(onBlur);
|
|
45
|
+
},
|
|
46
|
+
// Do not change visual focus state if select menu is opened
|
|
47
|
+
onFocusChange: (isFocused) => !state.isOpen && setVisualFocus(isFocused),
|
|
42
48
|
});
|
|
43
49
|
const { focusProps: clearFocusProps } = (0, react_aria_1.useFocus)({ onFocusChange: setIsClearFocused });
|
|
44
50
|
const buttonRef = (0, react_1.useRef)(null);
|
|
@@ -72,12 +78,12 @@ function ChipSelectField(props) {
|
|
|
72
78
|
isDisabled,
|
|
73
79
|
items: listData.items,
|
|
74
80
|
children: selectChildren,
|
|
81
|
+
autoFocus: true,
|
|
75
82
|
};
|
|
76
83
|
const state = (0, react_stately_1.useSelectState)({
|
|
77
84
|
...selectHookProps,
|
|
78
|
-
autoFocus: false,
|
|
79
85
|
selectedKey: (0, Value_1.valueToKey)(value),
|
|
80
|
-
disallowEmptySelection:
|
|
86
|
+
disallowEmptySelection: false,
|
|
81
87
|
onSelectionChange: (key) => {
|
|
82
88
|
if (key === createNewOpt.id) {
|
|
83
89
|
setShowInput(true);
|
|
@@ -87,11 +93,21 @@ function ChipSelectField(props) {
|
|
|
87
93
|
if (selectedItem) {
|
|
88
94
|
onSelect(key, selectedItem);
|
|
89
95
|
}
|
|
96
|
+
// Per UX, when an option is selected then we want to call our `onBlur` callback and remove the focus styles. The field _is_ still in focus but that is only to retain tab position in the DOM.
|
|
97
|
+
// We cannot simply call `buttonRef.current.blur()` here because `state.isOpen === true` and we keep the visualFocus shown when the menu is open.
|
|
98
|
+
setVisualFocus(false);
|
|
99
|
+
(0, utils_1.maybeCall)(onBlur);
|
|
90
100
|
},
|
|
91
101
|
onOpenChange: (isOpen) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
var _a;
|
|
103
|
+
if (!isOpen) {
|
|
104
|
+
// When closing, reset the focus to the button element. This is to retain "tab position" in the document, allowing hte user to hit "Tab" and move to the next tabbable element.
|
|
105
|
+
// If the menu closed due to a user selecting an option, then the field will not visually appear focused.
|
|
106
|
+
(_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// If opened, set visual focus to true. It is possible to be in a state where the browser focus is on this element, but we are not "visually" focused (see `onSelectionChange`). If the user opens the menu again, we should trigger the visual focus.
|
|
110
|
+
setVisualFocus(true);
|
|
95
111
|
}
|
|
96
112
|
},
|
|
97
113
|
});
|
|
@@ -122,29 +138,26 @@ function ChipSelectField(props) {
|
|
|
122
138
|
(_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
123
139
|
}, [setShowInput, setInputValue]);
|
|
124
140
|
const field = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showInput && onCreateNew && ((0, jsx_runtime_1.jsx)(ChipTextField_1.ChipTextField, Object.assign({ autoFocus: true, label: "Add new", value: inputValue, onChange: setInputValue, onEnter: async () => {
|
|
125
|
-
|
|
126
|
-
listData.insertBefore(createNewOpt.id, newOption);
|
|
141
|
+
await onCreateNew(inputValue);
|
|
127
142
|
removeCreateNewField();
|
|
128
143
|
}, onBlur: removeCreateNewField }, tid.createNewField), void 0)), (0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: wrapperRef, css: {
|
|
129
144
|
...chipStyles,
|
|
130
145
|
...Css_1.Css.dif.relative.p0.mwPx(32).if(!value).bgGray200.$,
|
|
131
|
-
...(
|
|
146
|
+
...(visualFocus ? Css_1.Css.bshFocus.$ : {}),
|
|
132
147
|
...(showInput ? Css_1.Css.dn.$ : {}),
|
|
133
148
|
} }, { children: [(0, jsx_runtime_1.jsx)(Label_1.Label, Object.assign({ label: label, labelProps: labelProps, hidden: true }, tid.label), void 0), (0, jsx_runtime_1.jsx)("button", Object.assign({}, (0, react_aria_1.mergeProps)(focusProps, buttonProps), { ref: buttonRef, css: {
|
|
134
149
|
...Css_1.Css.tl.br16.pxPx(10).pyPx(2).outline0.if(showClearButton).prPx(4).borderRadius("16px 0 0 16px").$,
|
|
135
150
|
...(isDisabled ? Css_1.Css.cursorNotAllowed.gray700.$ : {}),
|
|
136
151
|
"&:hover:not(:disabled)": Css_1.Css.bgGray400.if(!value).bgGray300.$,
|
|
137
|
-
}, title: state.selectedItem ? state.selectedItem.textValue : placeholder }, tid, { children: (0, jsx_runtime_1.jsx)("span", Object.assign({}, valueProps, { css: Css_1.Css.lineClamp1.breakAll.$ }, { children: state.selectedItem ? state.selectedItem.textValue : placeholder }), void 0) }), void 0), showClearButton && (
|
|
138
|
-
// Apply a tabIndex=-1 to remove need for addresses this focus behavior separately from the rest of the button.
|
|
139
|
-
// This will require the user to click on the button if they want to remove it.
|
|
140
|
-
(0, jsx_runtime_1.jsx)("button", Object.assign({}, clearFocusProps, { css: {
|
|
152
|
+
}, title: state.selectedItem ? state.selectedItem.textValue : placeholder }, tid, { children: (0, jsx_runtime_1.jsx)("span", Object.assign({}, valueProps, { css: Css_1.Css.lineClamp1.breakAll.$ }, { children: state.selectedItem ? state.selectedItem.textValue : placeholder }), void 0) }), void 0), showClearButton && ((0, jsx_runtime_1.jsx)("button", Object.assign({}, clearFocusProps, { css: {
|
|
141
153
|
...Css_1.Css.prPx(4).borderRadius("0 16px 16px 0").outline0.$,
|
|
142
154
|
"&:hover": Css_1.Css.bgGray400.$,
|
|
143
155
|
...(isClearFocused ? Css_1.Css.boxShadow(`0px 0px 0px 2px rgba(3,105,161,1)`).$ : {}),
|
|
144
156
|
}, onClick: () => {
|
|
145
157
|
onSelect(undefined, undefined);
|
|
158
|
+
(0, utils_1.maybeCall)(onBlur);
|
|
146
159
|
setIsClearFocused(false);
|
|
147
|
-
}, "aria-label": "Remove" }, tid.clearButton, { children: (0, jsx_runtime_1.jsx)(components_1.Icon, { icon: "x", inc: typeScale === "xs" ? 2 : undefined }, void 0) }), void 0))] }), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: buttonRef, popoverRef: popoverRef, positionProps: overlayProps, onClose: state.close, isOpen: state.isOpen, shouldCloseOnBlur: true }, { children: (0, jsx_runtime_1.jsx)(ListBox_1.ListBox, Object.assign({}, menuProps, { listBoxRef: listBoxRef, state: state, getOptionLabel: getOptionLabel, getOptionValue: getOptionValue, positionProps: overlayProps }), void 0) }), void 0))] }, void 0));
|
|
160
|
+
}, "aria-label": "Remove" }, tid.clearButton, { children: (0, jsx_runtime_1.jsx)(components_1.Icon, { icon: "x", inc: typeScale === "xs" ? 2 : undefined }, void 0) }), void 0))] }), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: buttonRef, popoverRef: popoverRef, positionProps: overlayProps, onClose: state.close, isOpen: state.isOpen, shouldCloseOnBlur: true }, { children: (0, jsx_runtime_1.jsx)(ListBox_1.ListBox, Object.assign({}, menuProps, { listBoxRef: listBoxRef, state: state, getOptionLabel: getOptionLabel, getOptionValue: getOptionValue, positionProps: overlayProps, positionOffset: 8 }), void 0) }), void 0))] }, void 0));
|
|
148
161
|
const tooltipText = selectHookProps.isDisabled && typeof disabled !== "boolean" ? disabled : undefined;
|
|
149
162
|
return tooltipText ? ((0, jsx_runtime_1.jsx)(components_1.Tooltip, Object.assign({ title: tooltipText, placement: "top" }, { children: field }), void 0)) : (field);
|
|
150
163
|
}
|
package/dist/inputs/DateField.js
CHANGED
|
@@ -75,6 +75,13 @@ function DateField(props) {
|
|
|
75
75
|
state.close();
|
|
76
76
|
(0, utils_1.maybeCall)(onBlur);
|
|
77
77
|
},
|
|
78
|
+
onKeyDown: (e) => {
|
|
79
|
+
var _a;
|
|
80
|
+
if (e.key === "Enter") {
|
|
81
|
+
// Blur the field when the user hits the enter key - as if they are "committing" the value and done with the field
|
|
82
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
78
85
|
}, inputRef);
|
|
79
86
|
const { triggerProps, overlayProps } = (0, react_aria_1.useOverlayTrigger)({ type: "dialog" }, state, buttonRef);
|
|
80
87
|
const { buttonProps } = (0, react_aria_1.useButton)({
|
|
@@ -47,6 +47,13 @@ function NumberField(props) {
|
|
|
47
47
|
onBlur: () => {
|
|
48
48
|
valueRef.current = { wip: false };
|
|
49
49
|
},
|
|
50
|
+
onKeyDown: (e) => {
|
|
51
|
+
var _a;
|
|
52
|
+
if (e.key === "Enter") {
|
|
53
|
+
// Blur the field when the user hits the enter key - as if they are "committing" the value and done with the field
|
|
54
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
50
57
|
validationState: errorMsg !== undefined ? "invalid" : "valid",
|
|
51
58
|
label: label,
|
|
52
59
|
isDisabled: disabled,
|
|
@@ -43,9 +43,12 @@ function TextAreaField(props) {
|
|
|
43
43
|
...(preventNewLines
|
|
44
44
|
? {
|
|
45
45
|
onKeyDown: (e) => {
|
|
46
|
+
var _a;
|
|
46
47
|
// Prevent user from typing the new line character
|
|
47
|
-
if (e.
|
|
48
|
+
if (e.key === "Enter") {
|
|
48
49
|
e.preventDefault();
|
|
50
|
+
// And then leave the field
|
|
51
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
49
52
|
}
|
|
50
53
|
},
|
|
51
54
|
onInput: (e) => {
|
package/dist/inputs/TextField.js
CHANGED
|
@@ -16,7 +16,16 @@ function TextField(props) {
|
|
|
16
16
|
value,
|
|
17
17
|
};
|
|
18
18
|
const inputRef = (0, react_1.useRef)(null);
|
|
19
|
-
const { labelProps, inputProps } = (0, react_aria_1.useTextField)(
|
|
19
|
+
const { labelProps, inputProps } = (0, react_aria_1.useTextField)({
|
|
20
|
+
...textFieldProps,
|
|
21
|
+
onKeyDown: (e) => {
|
|
22
|
+
var _a;
|
|
23
|
+
if (e.key === "Enter") {
|
|
24
|
+
// Blur the field when the user hits the enter key - as if they are "committing" the value and done with the field
|
|
25
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
}, inputRef);
|
|
20
29
|
// Construct our TextFieldApi to give access to some imperative methods
|
|
21
30
|
if (api) {
|
|
22
31
|
api.current = {
|
|
@@ -24,6 +24,7 @@ function SelectFieldBase(props) {
|
|
|
24
24
|
const { compact, disabled: isDisabled = false, errorMsg, helperText, label, hideLabel, required, inlineLabel, readOnly: isReadOnly = false, onSelect, fieldDecoration, options, onBlur, onFocus, multiselect = false, getOptionLabel, getOptionValue, getOptionMenuLabel = getOptionLabel, sizeToContent = false, values, nothingSelectedText = "", contrast, disabledOptions, borderless, ...otherProps } = props;
|
|
25
25
|
const { contains } = (0, react_aria_1.useFilter)({ sensitivity: "base" });
|
|
26
26
|
function onSelectionChange(keys) {
|
|
27
|
+
var _a;
|
|
27
28
|
// Close menu upon selection change only for Single selection mode
|
|
28
29
|
if (!multiselect) {
|
|
29
30
|
state.close();
|
|
@@ -72,6 +73,10 @@ function SelectFieldBase(props) {
|
|
|
72
73
|
});
|
|
73
74
|
}
|
|
74
75
|
selectionChanged && onSelect([...keys.values()].map(Value_1.keyToValue));
|
|
76
|
+
if (!multiselect) {
|
|
77
|
+
// When a single select menu item changes, then blur the field AFTER `onSelect` has been called
|
|
78
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
79
|
+
}
|
|
75
80
|
}
|
|
76
81
|
function onInputChange(value) {
|
|
77
82
|
setFieldState((prevState) => ({
|