@homebound/beam 2.90.4 → 2.91.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.
|
@@ -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
|
});
|
|
@@ -128,23 +144,21 @@ function ChipSelectField(props) {
|
|
|
128
144
|
}, onBlur: removeCreateNewField }, tid.createNewField), void 0)), (0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: wrapperRef, css: {
|
|
129
145
|
...chipStyles,
|
|
130
146
|
...Css_1.Css.dif.relative.p0.mwPx(32).if(!value).bgGray200.$,
|
|
131
|
-
...(
|
|
147
|
+
...(visualFocus ? Css_1.Css.bshFocus.$ : {}),
|
|
132
148
|
...(showInput ? Css_1.Css.dn.$ : {}),
|
|
133
149
|
} }, { 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
150
|
...Css_1.Css.tl.br16.pxPx(10).pyPx(2).outline0.if(showClearButton).prPx(4).borderRadius("16px 0 0 16px").$,
|
|
135
151
|
...(isDisabled ? Css_1.Css.cursorNotAllowed.gray700.$ : {}),
|
|
136
152
|
"&: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: {
|
|
153
|
+
}, 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
154
|
...Css_1.Css.prPx(4).borderRadius("0 16px 16px 0").outline0.$,
|
|
142
155
|
"&:hover": Css_1.Css.bgGray400.$,
|
|
143
156
|
...(isClearFocused ? Css_1.Css.boxShadow(`0px 0px 0px 2px rgba(3,105,161,1)`).$ : {}),
|
|
144
157
|
}, onClick: () => {
|
|
145
158
|
onSelect(undefined, undefined);
|
|
159
|
+
(0, utils_1.maybeCall)(onBlur);
|
|
146
160
|
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));
|
|
161
|
+
}, "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
162
|
const tooltipText = selectHookProps.isDisabled && typeof disabled !== "boolean" ? disabled : undefined;
|
|
149
163
|
return tooltipText ? ((0, jsx_runtime_1.jsx)(components_1.Tooltip, Object.assign({ title: tooltipText, placement: "top" }, { children: field }), void 0)) : (field);
|
|
150
164
|
}
|
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();
|
|
@@ -70,6 +71,8 @@ function SelectFieldBase(props) {
|
|
|
70
71
|
selectedKeys: [firstKey],
|
|
71
72
|
selectedOptions: firstSelectedOption ? [firstSelectedOption] : [],
|
|
72
73
|
});
|
|
74
|
+
// When a single select menu item changes, then blur the field
|
|
75
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
73
76
|
}
|
|
74
77
|
selectionChanged && onSelect([...keys.values()].map(Value_1.keyToValue));
|
|
75
78
|
}
|