@lumx/react 3.6.5-alpha.3 → 3.6.5-alpha.5
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/index.d.ts +5 -0
- package/index.js +66 -51
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/autocomplete/Autocomplete.tsx +7 -0
- package/src/components/popover/useRestoreFocusOnClose.tsx +30 -16
- package/src/components/popover-dialog/PopoverDialog.stories.tsx +18 -18
- package/src/components/popover-dialog/PopoverDialog.test.tsx +58 -45
- package/src/components/tooltip/Tooltip.test.tsx +19 -0
- package/src/components/tooltip/useInjectTooltipRef.tsx +12 -12
- package/src/utils/OnBeforeUnmount.tsx +20 -0
- package/src/utils/isFocusVisible.ts +1 -1
- package/src/utils/useBeforeUnmountSentinel.tsx +0 -17
package/index.d.ts
CHANGED
|
@@ -155,6 +155,11 @@ interface AutocompleteProps extends GenericProps, HasTheme {
|
|
|
155
155
|
* @see {@link DropdownProps#closeOnEscape}
|
|
156
156
|
*/
|
|
157
157
|
closeOnEscape?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Whether the focus should go back on the anchor when dropdown closes and focus is within.
|
|
160
|
+
* @see {@link DropdownProps#focusAnchorOnClose}
|
|
161
|
+
*/
|
|
162
|
+
focusAnchorOnClose?: DropdownProps['focusAnchorOnClose'];
|
|
158
163
|
/**
|
|
159
164
|
* The function called on blur.
|
|
160
165
|
* @see {@link TextFieldProps#onBlur}
|
package/index.js
CHANGED
|
@@ -839,7 +839,7 @@ const useMergeRefs = function () {
|
|
|
839
839
|
refs);
|
|
840
840
|
};
|
|
841
841
|
|
|
842
|
-
const _excluded$2 = ["anchorToInput", "children", "chips", "className", "closeOnClick", "closeOnClickAway", "closeOnEscape", "disabled", "error", "fitToAnchorWidth", "hasError", "helper", "icon", "inputRef", "clearButtonProps", "isDisabled", "isRequired", "isOpen", "isValid", "label", "name", "offset", "onBlur", "onChange", "onClose", "onFocus", "onInfiniteScroll", "placeholder", "placement", "shouldFocusOnClose", "theme", "value", "textFieldProps"];
|
|
842
|
+
const _excluded$2 = ["anchorToInput", "children", "chips", "className", "closeOnClick", "closeOnClickAway", "closeOnEscape", "disabled", "error", "fitToAnchorWidth", "hasError", "helper", "icon", "inputRef", "clearButtonProps", "isDisabled", "isRequired", "isOpen", "isValid", "label", "name", "offset", "onBlur", "onChange", "onClose", "onFocus", "onInfiniteScroll", "placeholder", "placement", "shouldFocusOnClose", "theme", "value", "textFieldProps", "focusAnchorOnClose"];
|
|
843
843
|
|
|
844
844
|
/**
|
|
845
845
|
* Defines the props of the component.
|
|
@@ -907,7 +907,8 @@ const Autocomplete = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
907
907
|
shouldFocusOnClose,
|
|
908
908
|
theme,
|
|
909
909
|
value,
|
|
910
|
-
textFieldProps = {}
|
|
910
|
+
textFieldProps = {},
|
|
911
|
+
focusAnchorOnClose
|
|
911
912
|
} = props,
|
|
912
913
|
forwardedProps = _objectWithoutProperties(props, _excluded$2);
|
|
913
914
|
const inputAnchorRef = useRef(null);
|
|
@@ -944,6 +945,7 @@ const Autocomplete = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
944
945
|
closeOnClick: closeOnClick,
|
|
945
946
|
closeOnClickAway: closeOnClickAway,
|
|
946
947
|
closeOnEscape: closeOnEscape,
|
|
948
|
+
focusAnchorOnClose: focusAnchorOnClose,
|
|
947
949
|
fitToAnchorWidth: fitToAnchorWidth,
|
|
948
950
|
isOpen: isOpen,
|
|
949
951
|
offset: offset,
|
|
@@ -4058,52 +4060,67 @@ const skipRender = (predicate, Component) => {
|
|
|
4058
4060
|
return Wrapper;
|
|
4059
4061
|
};
|
|
4060
4062
|
|
|
4061
|
-
/**
|
|
4062
|
-
|
|
4063
|
+
/**
|
|
4064
|
+
* Helper component using useLayoutEffect to trigger a callback on before unmount.
|
|
4065
|
+
*
|
|
4066
|
+
* The callback must be wrapped in a React ref to avoid updating the `useLayoutEffect` before the un-mount
|
|
4067
|
+
*/
|
|
4068
|
+
const OnBeforeUnmount = _ref => {
|
|
4063
4069
|
let {
|
|
4064
|
-
|
|
4070
|
+
callbackRef
|
|
4065
4071
|
} = _ref;
|
|
4066
|
-
useLayoutEffect(() =>
|
|
4072
|
+
useLayoutEffect(() => {
|
|
4073
|
+
return () => {
|
|
4074
|
+
var _callbackRef$current;
|
|
4075
|
+
// On unmount
|
|
4076
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4077
|
+
(_callbackRef$current = callbackRef.current) === null || _callbackRef$current === void 0 ? void 0 : _callbackRef$current.call(callbackRef);
|
|
4078
|
+
};
|
|
4079
|
+
},
|
|
4080
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4081
|
+
[]);
|
|
4067
4082
|
return null;
|
|
4068
4083
|
};
|
|
4069
4084
|
|
|
4070
|
-
/**
|
|
4071
|
-
* Provides a sentinel to inject the React tree that triggers the callback on before unmount.
|
|
4072
|
-
*/
|
|
4073
|
-
function useBeforeUnmountSentinel(onBeforeUnmount) {
|
|
4074
|
-
return React.useMemo(() => {
|
|
4075
|
-
if (!onBeforeUnmount) return undefined;
|
|
4076
|
-
return /*#__PURE__*/React.createElement(OnUnmount, {
|
|
4077
|
-
onBeforeUnmount: onBeforeUnmount
|
|
4078
|
-
});
|
|
4079
|
-
}, [onBeforeUnmount]);
|
|
4080
|
-
}
|
|
4081
|
-
|
|
4082
4085
|
/**
|
|
4083
4086
|
* Provides an unmount sentinel to inject in the popover to detect when it closes and restore the focus to the
|
|
4084
4087
|
* anchor if needed.
|
|
4085
4088
|
*/
|
|
4086
|
-
function useRestoreFocusOnClose(
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4089
|
+
function useRestoreFocusOnClose(_ref, popoverElement) {
|
|
4090
|
+
let {
|
|
4091
|
+
focusAnchorOnClose,
|
|
4092
|
+
anchorRef,
|
|
4093
|
+
parentElement
|
|
4094
|
+
} = _ref;
|
|
4095
|
+
const onBeforeUnmountRef = React.useRef();
|
|
4096
|
+
React.useEffect(() => {
|
|
4097
|
+
if (!popoverElement || !focusAnchorOnClose) {
|
|
4098
|
+
onBeforeUnmountRef.current = undefined;
|
|
4099
|
+
return;
|
|
4100
|
+
}
|
|
4101
|
+
onBeforeUnmountRef.current = () => {
|
|
4091
4102
|
const isFocusWithin = popoverElement === null || popoverElement === void 0 ? void 0 : popoverElement.contains(document.activeElement);
|
|
4092
4103
|
if (!isFocusWithin) return;
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
+
|
|
4105
|
+
// On next render
|
|
4106
|
+
setTimeout(() => {
|
|
4107
|
+
const anchor = anchorRef.current;
|
|
4108
|
+
const elementToFocus =
|
|
4109
|
+
// Provided parent element
|
|
4110
|
+
(parentElement === null || parentElement === void 0 ? void 0 : parentElement.current) || (
|
|
4111
|
+
// Or first focusable element in anchor
|
|
4112
|
+
anchor ? getFirstAndLastFocusable(anchor).first : undefined) ||
|
|
4113
|
+
// Fallback to anchor
|
|
4114
|
+
anchor;
|
|
4115
|
+
elementToFocus === null || elementToFocus === void 0 ? void 0 : elementToFocus.focus({
|
|
4116
|
+
preventScroll: true
|
|
4117
|
+
});
|
|
4118
|
+
}, 0);
|
|
4104
4119
|
};
|
|
4105
|
-
}, [
|
|
4106
|
-
return
|
|
4120
|
+
}, [anchorRef, focusAnchorOnClose, parentElement, popoverElement]);
|
|
4121
|
+
return /*#__PURE__*/React.createElement(OnBeforeUnmount, {
|
|
4122
|
+
callbackRef: onBeforeUnmountRef
|
|
4123
|
+
});
|
|
4107
4124
|
}
|
|
4108
4125
|
|
|
4109
4126
|
/**
|
|
@@ -12851,7 +12868,7 @@ Toolbar.defaultProps = DEFAULT_PROPS$10;
|
|
|
12851
12868
|
/**
|
|
12852
12869
|
* Add ref and ARIA attribute(s) in tooltip children or wrapped children.
|
|
12853
12870
|
* Button, IconButton, Icon and React HTML elements don't need to be wrapped but any other kind of children (array, fragment, custom components)
|
|
12854
|
-
* will be wrapped
|
|
12871
|
+
* will be wrapped in a <span>.
|
|
12855
12872
|
*
|
|
12856
12873
|
* @param children Original tooltip anchor.
|
|
12857
12874
|
* @param setAnchorElement Set tooltip anchor element.
|
|
@@ -12861,30 +12878,28 @@ Toolbar.defaultProps = DEFAULT_PROPS$10;
|
|
|
12861
12878
|
* @return tooltip anchor.
|
|
12862
12879
|
*/
|
|
12863
12880
|
const useInjectTooltipRef = (children, setAnchorElement, isOpen, id, label) => {
|
|
12864
|
-
|
|
12865
|
-
const
|
|
12881
|
+
// Only add description when open
|
|
12882
|
+
const describedBy = isOpen ? id : undefined;
|
|
12866
12883
|
return useMemo(() => {
|
|
12867
|
-
var _element$props, _element$props2;
|
|
12868
12884
|
// Non-disabled element
|
|
12869
|
-
if (
|
|
12870
|
-
const
|
|
12885
|
+
if ( /*#__PURE__*/React.isValidElement(children) && children.props.disabled !== true && children.props.isDisabled !== true) {
|
|
12886
|
+
const ref = mergeRefs(children.ref, setAnchorElement);
|
|
12887
|
+
const props = _objectSpread2(_objectSpread2({}, children.props), {}, {
|
|
12871
12888
|
ref
|
|
12872
12889
|
});
|
|
12873
12890
|
|
|
12874
12891
|
// Add current tooltip to the aria-describedby if the label is not already present
|
|
12875
|
-
if (label !== props['aria-label']) {
|
|
12876
|
-
props['aria-describedby'] = [props['aria-describedby'],
|
|
12892
|
+
if (label !== props['aria-label'] && describedBy) {
|
|
12893
|
+
props['aria-describedby'] = [props['aria-describedby'], describedBy].filter(Boolean).join(' ');
|
|
12877
12894
|
}
|
|
12878
|
-
return /*#__PURE__*/cloneElement(
|
|
12895
|
+
return /*#__PURE__*/cloneElement(children, props);
|
|
12879
12896
|
}
|
|
12880
|
-
|
|
12881
|
-
// Else add a wrapper around the children
|
|
12882
12897
|
return /*#__PURE__*/React.createElement("div", {
|
|
12883
12898
|
className: "lumx-tooltip-anchor-wrapper",
|
|
12884
|
-
ref:
|
|
12885
|
-
"aria-describedby":
|
|
12899
|
+
ref: setAnchorElement,
|
|
12900
|
+
"aria-describedby": describedBy
|
|
12886
12901
|
}, children);
|
|
12887
|
-
}, [
|
|
12902
|
+
}, [children, setAnchorElement, describedBy, label]);
|
|
12888
12903
|
};
|
|
12889
12904
|
|
|
12890
12905
|
/** Return true if the browser does not support pointer hover */
|
|
@@ -12900,7 +12915,7 @@ const isFocusVisible = element => {
|
|
|
12900
12915
|
return element === null || element === void 0 ? void 0 : (_element$matches = element.matches) === null || _element$matches === void 0 ? void 0 : _element$matches.call(element, ':focus-visible, [data-focus-visible-added]');
|
|
12901
12916
|
} catch (_ignored) {
|
|
12902
12917
|
// Can fail on non browser env
|
|
12903
|
-
return
|
|
12918
|
+
return true;
|
|
12904
12919
|
}
|
|
12905
12920
|
};
|
|
12906
12921
|
|