@lumx/react 3.6.5-alpha.3 → 3.6.5-alpha.4

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,65 @@ 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
+ callback
4065
4071
  } = _ref;
4066
- useLayoutEffect(() => onBeforeUnmount, [onBeforeUnmount]);
4072
+ useLayoutEffect(() => {
4073
+ return () => {
4074
+ var _callback$current;
4075
+ // On unmount
4076
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4077
+ (_callback$current = callback.current) === null || _callback$current === void 0 ? void 0 : _callback$current.call(callback);
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
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
4096
+ const onBeforeUnmountRef = React.useRef(() => {});
4097
+ const anchor = anchorRef.current;
4098
+ const elementToFocus =
4099
+ // Provided parent element
4100
+ (parentElement === null || parentElement === void 0 ? void 0 : parentElement.current) || (
4101
+ // Or first focusable element in anchor
4102
+ anchor ? getFirstAndLastFocusable(anchor).first : undefined) ||
4103
+ // Fallback to anchor
4104
+ anchor;
4105
+ React.useEffect(() => {
4106
+ if (!popoverElement || !focusAnchorOnClose || !elementToFocus) return;
4107
+ onBeforeUnmountRef.current = () => {
4091
4108
  const isFocusWithin = popoverElement === null || popoverElement === void 0 ? void 0 : popoverElement.contains(document.activeElement);
4092
4109
  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
- });
4110
+
4111
+ // Focus on next render
4112
+ setTimeout(() => {
4113
+ elementToFocus.focus({
4114
+ preventScroll: true
4115
+ });
4116
+ }, 0);
4104
4117
  };
4105
- }, [popoverElement, props.anchorRef, props.focusAnchorOnClose, props.parentElement]);
4106
- return useBeforeUnmountSentinel(onBeforeUnmount);
4118
+ }, [anchor, elementToFocus, focusAnchorOnClose, popoverElement]);
4119
+ return /*#__PURE__*/React.createElement(OnBeforeUnmount, {
4120
+ callback: onBeforeUnmountRef
4121
+ });
4107
4122
  }
4108
4123
 
4109
4124
  /**
@@ -12851,7 +12866,7 @@ Toolbar.defaultProps = DEFAULT_PROPS$10;
12851
12866
  /**
12852
12867
  * Add ref and ARIA attribute(s) in tooltip children or wrapped children.
12853
12868
  * 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.
12869
+ * will be wrapped in a <span>.
12855
12870
  *
12856
12871
  * @param children Original tooltip anchor.
12857
12872
  * @param setAnchorElement Set tooltip anchor element.
@@ -12861,30 +12876,28 @@ Toolbar.defaultProps = DEFAULT_PROPS$10;
12861
12876
  * @return tooltip anchor.
12862
12877
  */
12863
12878
  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);
12879
+ // Only add description when open
12880
+ const describedBy = isOpen ? id : undefined;
12866
12881
  return useMemo(() => {
12867
- var _element$props, _element$props2;
12868
12882
  // 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), {}, {
12883
+ if ( /*#__PURE__*/React.isValidElement(children) && children.props.disabled !== true && children.props.isDisabled !== true) {
12884
+ const ref = mergeRefs(children.ref, setAnchorElement);
12885
+ const props = _objectSpread2(_objectSpread2({}, children.props), {}, {
12871
12886
  ref
12872
12887
  });
12873
12888
 
12874
12889
  // 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(' ');
12890
+ if (label !== props['aria-label'] && describedBy) {
12891
+ props['aria-describedby'] = [props['aria-describedby'], describedBy].filter(Boolean).join(' ');
12877
12892
  }
12878
- return /*#__PURE__*/cloneElement(element, props);
12893
+ return /*#__PURE__*/cloneElement(children, props);
12879
12894
  }
12880
-
12881
- // Else add a wrapper around the children
12882
12895
  return /*#__PURE__*/React.createElement("div", {
12883
12896
  className: "lumx-tooltip-anchor-wrapper",
12884
- ref: ref,
12885
- "aria-describedby": isOpen ? id : undefined
12897
+ ref: setAnchorElement,
12898
+ "aria-describedby": describedBy
12886
12899
  }, children);
12887
- }, [element, children, isOpen, id, ref, label]);
12900
+ }, [children, setAnchorElement, describedBy, label]);
12888
12901
  };
12889
12902
 
12890
12903
  /** Return true if the browser does not support pointer hover */
@@ -12900,7 +12913,7 @@ const isFocusVisible = element => {
12900
12913
  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
12914
  } catch (_ignored) {
12902
12915
  // Can fail on non browser env
12903
- return false;
12916
+ return true;
12904
12917
  }
12905
12918
  };
12906
12919