UNPKG

@spaced-out/ui-design-system

Version:
157 lines (148 loc) 6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SkipElementFromNavigation = exports.FocusManagerWithArrowKeyNavigation = void 0; var React = _interopRequireWildcard(require("react")); var _react2 = require("@floating-ui/react"); var _classify = _interopRequireDefault(require("../../utils/classify")); var _qa = require("../../utils/qa"); var _FocusManagerWithArrowKeyNavigationModule = _interopRequireDefault(require("./FocusManagerWithArrowKeyNavigation.module.css")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const SKIP_ELEMENT_DISPLAY_NAME = 'SkipElementFromNavigation'; const SkipElementFromNavigation = exports.SkipElementFromNavigation = /*#__PURE__*/React.forwardRef((_ref, ref) => { let { children, className, testId, ...restProps } = _ref; return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { ...restProps, "data-testid": (0, _qa.generateTestId)({ base: testId, slot: 'skipElement' }), className: className, tabIndex: -1, ref: ref, children: children }); }); SkipElementFromNavigation.displayName = SKIP_ELEMENT_DISPLAY_NAME; // Type for React elements with onClick handler // Type for React elements that might be SkipElementFromNavigation const FocusManagerWithArrowKeyNavigation = props => { const { classNames, children, initialFocus = -1, orientation = 'vertical', modal = false, cols = 1, focusItemOnOpen = 'auto', loop = false, listReference, testId, ...restFloatingFocusManagerProps } = props; const { refs, context } = (0, _react2.useFloating)({ open: true }); const [activeIndex, setActiveIndex] = React.useState(null); const listRef = React.useRef([]); const childrenArray = React.Children.toArray(children).filter(Boolean); // Note(Nishant): This is to correctly call the onClick handler which could have been on child // we also need to set the active index correctly on click for list navigation to work const childOnClickPassthrough = function (childOnClickHandler, index) { for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } if (childOnClickHandler) { childOnClickHandler(...args); } setActiveIndex(index); }; // Add childOnClickPassthrough for the list of references passed in case of custom nodes passed if (listReference) { listReference.current.map((element, index) => { const childClickHandler = element.onclick; element.onclick = function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } childOnClickPassthrough(childClickHandler, index, ...args); }; }); } // Note(Nishant): Force the list navigation props onto the children // while using this component make sure your all the passed children have a focus state let skippedChildrenCount = 0; const clonedChildren = listReference ? children : childrenArray.map((child, index) => { // Type guard to ensure child is a ReactElement if (! /*#__PURE__*/React.isValidElement(child)) { return child; } // Type assertion for React element with onClick const elementWithOnClick = child; const { onClick: childClickHandler } = elementWithOnClick.props; let adjustedIndex = index - skippedChildrenCount; // Check if this is a SkipElementFromNavigation by checking displayName const elementWithDisplayName = child; if (elementWithDisplayName?.type?.displayName === SKIP_ELEMENT_DISPLAY_NAME) { skippedChildrenCount++; adjustedIndex = null; } return /*#__PURE__*/React.cloneElement(elementWithOnClick, { ...elementWithOnClick.props, tabIndex: activeIndex === index ? 0 : -1, ref: node => { if (adjustedIndex !== null) { listRef.current[adjustedIndex] = node; } }, onClick: function () { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } childOnClickPassthrough(childClickHandler, adjustedIndex, ...args); } }); }); const listNavigation = (0, _react2.useListNavigation)(context, { orientation, cols, listRef: listReference ? listReference : listRef, activeIndex, onNavigate: setActiveIndex, focusItemOnOpen, loop }); const { getFloatingProps } = (0, _react2.useInteractions)([listNavigation]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.FloatingFocusManager, { context: context, modal: modal, initialFocus: initialFocus, ...restFloatingFocusManagerProps, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { ref: refs.setFloating, "data-testid": (0, _qa.generateTestId)({ base: testId, slot: 'focusManager' }), ...getFloatingProps(), className: (0, _classify.default)(_FocusManagerWithArrowKeyNavigationModule.default.wrapper, classNames?.wrapper), children: clonedChildren }) }); }; exports.FocusManagerWithArrowKeyNavigation = FocusManagerWithArrowKeyNavigation;