@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 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
- /** Small helper component using useLayoutEffect to trigger a callback on before unmount. */
4062
- const OnUnmount = _ref => {
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
- onBeforeUnmount
4070
+ callbackRef
4065
4071
  } = _ref;
4066
- useLayoutEffect(() => onBeforeUnmount, [onBeforeUnmount]);
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(props, popoverElement) {
4087
- const onBeforeUnmount = React.useMemo(() => {
4088
- if (!popoverElement || !props.focusAnchorOnClose) return undefined;
4089
- return () => {
4090
- var _props$parentElement;
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
- const anchor = props.anchorRef.current;
4094
- const elementToFocus =
4095
- // Provided parent element
4096
- ((_props$parentElement = props.parentElement) === null || _props$parentElement === void 0 ? void 0 : _props$parentElement.current) || (
4097
- // Or first focusable element in anchor
4098
- anchor ? getFirstAndLastFocusable(anchor).first : undefined) ||
4099
- // Fallback to anchor
4100
- anchor;
4101
- elementToFocus === null || elementToFocus === void 0 ? void 0 : elementToFocus.focus({
4102
- preventScroll: true
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
- }, [popoverElement, props.anchorRef, props.focusAnchorOnClose, props.parentElement]);
4106
- return useBeforeUnmountSentinel(onBeforeUnmount);
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
- const element = /*#__PURE__*/React.isValidElement(children) ? children : null;
12865
- const ref = useMergeRefs(element === null || element === void 0 ? void 0 : element.ref, setAnchorElement);
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 (element && ((_element$props = element.props) === null || _element$props === void 0 ? void 0 : _element$props.disabled) !== true && ((_element$props2 = element.props) === null || _element$props2 === void 0 ? void 0 : _element$props2.isDisabled) !== true) {
12870
- const props = _objectSpread2(_objectSpread2({}, element.props), {}, {
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'], id].filter(Boolean).join(' ');
12892
+ if (label !== props['aria-label'] && describedBy) {
12893
+ props['aria-describedby'] = [props['aria-describedby'], describedBy].filter(Boolean).join(' ');
12877
12894
  }
12878
- return /*#__PURE__*/cloneElement(element, props);
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: ref,
12885
- "aria-describedby": isOpen ? id : undefined
12899
+ ref: setAnchorElement,
12900
+ "aria-describedby": describedBy
12886
12901
  }, children);
12887
- }, [element, children, isOpen, id, ref, label]);
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 false;
12918
+ return true;
12904
12919
  }
12905
12920
  };
12906
12921