UNPKG

@atlaskit/drawer

Version:

A drawer is a panel that slides in from the left side of the screen.

237 lines (229 loc) • 10.2 kB
/* drawer-top-layer.tsx generated by @compiled/babel-plugin v3.0.2 */ "use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof3 = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.DrawerTopLayer = DrawerTopLayer; require("./drawer-top-layer.compiled.css"); var _react = _interopRequireWildcard(require("react")); var React = _react; var _runtime = require("@compiled/react/runtime"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _react2 = require("@compiled/react"); var _bindEventListener = require("bind-event-listener"); var _usePlatformLeafEventHandler = require("@atlaskit/analytics-next/usePlatformLeafEventHandler"); var _createCloseEvent = require("@atlaskit/top-layer/create-close-event"); var _dialogContent = require("@atlaskit/top-layer/dialog-content"); var _dialogScrollLock = require("@atlaskit/top-layer/dialog-scroll-lock"); var _ensureIsInsideDrawerContext = require("../ensure-is-inside-drawer-context"); var _onCloseContext = require("../on-close-context"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof3(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _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); } var LOCAL_CURRENT_SURFACE_CSS_VAR = '--ds-elevation-surface-current'; var slideInKeyframes = null; var slideOutKeyframes = null; var styles = { root: "_19pkidpf _2hwxidpf _otyridpf _18u0idpf _152tidpf _1e02idpf _rjxp1wug _4t3i1496 _p12fauwl", enter: "_j7hqntq4", exit: "_j7hqcljl", surface: "_1reo15vq _18m915vq _1e0c1txw _1bsb1osq _4t3i1osq _bfhk1bhr _1q1l1bhr _ect4ttxp" }; var widthStyles = { narrow: "_1bsb1gwv", medium: "_1bsb1y37", wide: "_1bsb1ogm", extended: "_1bsb1mwr", full: "_1bsbauwl" }; var enterFromStyles = { left: "_1s8jpwvu _1c2rf1ug", right: "_1s8j1osq _1c2rf1ug", top: "_1s8jf1ug _1c2rpwvu", bottom: "_1s8jf1ug _1c2r1osq" }; /** * Resolve the native `<dialog>` accessible name props. Prefer the consumer's * `label`, then their `titleId`. If neither is supplied (legacy allowed this), * fall back to a generic name so the dialog is never unlabelled. Note: * `@atlaskit/drawer` has no i18n setup, so this fallback is English only; * consumers should pass a localised `label` or `titleId`. */ function getAccessibleName(_ref) { var label = _ref.label, titleId = _ref.titleId; if (label) { return { label: label }; } if (titleId) { return { labelledBy: titleId }; } return { label: 'Drawer' }; } /** * **DrawerTopLayer** * * Top-layer (`platform-dst-top-layer`) implementation of `Drawer`. Renders a * native `<dialog>` via `@atlaskit/top-layer`, replacing Portal, Blanket, * react-focus-lock, react-scrolllock and `@atlaskit/layering` with native * modality, `::backdrop`, focus trap and return, and `DialogScrollLock`. * * The `Dialog` primitive owns the entry and exit animation lifecycle (it keeps * the host element mounted through the exit transition, then fires * `onExitFinish`), so no `ExitingPersistence` wrapper is needed: the drawer * renders `<Dialog isOpen={isOpen}>` directly. `useDrawerStack` tracks stack * depth so only the foreground drawer shows a `::backdrop`. * * `isFocusLockEnabled` is intentionally unsupported: a native modal `<dialog>` * always traps focus, so `isFocusLockEnabled={false}` is a no-op under this gate. */ function DrawerTopLayer(_ref2) { var _ref2$width = _ref2.width, width = _ref2$width === void 0 ? 'narrow' : _ref2$width, isOpen = _ref2.isOpen, _ref2$shouldReturnFoc = _ref2.shouldReturnFocus, shouldReturnFocus = _ref2$shouldReturnFoc === void 0 ? true : _ref2$shouldReturnFoc, onKeyDown = _ref2.onKeyDown, testId = _ref2.testId, children = _ref2.children, onClose = _ref2.onClose, onCloseComplete = _ref2.onCloseComplete, onOpenComplete = _ref2.onOpenComplete, label = _ref2.label, titleId = _ref2.titleId, _ref2$enterFrom = _ref2.enterFrom, enterFrom = _ref2$enterFrom === void 0 ? 'left' : _ref2$enterFrom; /** * Points to the panel surface. Passed to `onOpenComplete` / `onCloseComplete`. */ var contentRef = (0, _react.useRef)(null); // Cache the last content element so `onCloseComplete` still receives a node // after children unmount (with reduced motion `contentRef` can clear before // `onExitFinish` fires). var lastContentElRef = (0, _react.useRef)(null); // Callback ref runs at commit (not during render), so both refs stay // populated without a render-time side effect. `lastContentElRef` only // overwrites with a non-null node, preserving it across the unmount. var setContentEl = (0, _react.useCallback)(function (el) { contentRef.current = el; if (el) { lastContentElRef.current = el; } }, []); // Analytics-wrapped close handlers, one per legacy trigger. var handleEscapeClose = (0, _usePlatformLeafEventHandler.usePlatformLeafEventHandler)({ fn: function fn(evt, analyticsEvent) { return onClose === null || onClose === void 0 ? void 0 : onClose(evt, analyticsEvent); }, action: 'dismissed', componentName: 'drawer', packageName: "@atlaskit/drawer", packageVersion: "14.3.5", analyticsData: { trigger: 'escKey' } }); var handleBlanketClose = (0, _usePlatformLeafEventHandler.usePlatformLeafEventHandler)({ fn: function fn(evt, analyticsEvent) { return onClose === null || onClose === void 0 ? void 0 : onClose(evt, analyticsEvent); }, action: 'dismissed', componentName: 'drawer', packageName: "@atlaskit/drawer", packageVersion: "14.3.5", analyticsData: { trigger: 'blanket' } }); var handleBackButtonClose = (0, _usePlatformLeafEventHandler.usePlatformLeafEventHandler)({ fn: function fn(evt, analyticsEvent) { return onClose === null || onClose === void 0 ? void 0 : onClose(evt, analyticsEvent); }, action: 'dismissed', componentName: 'drawer', packageName: "@atlaskit/drawer", packageVersion: "14.3.5", analyticsData: { trigger: 'backButton' } }); // Bridge the Dialog primitive's `onClose({ reason })` to the legacy // `onClose(event, analyticsEvent)` contract via a synthetic event. Drawer // has no `shouldCloseOn*` props, so both reasons always forward. var handleDialogClose = (0, _react.useCallback)(function (_ref3) { var reason = _ref3.reason; var event = (0, _createCloseEvent.createCloseEvent)({ reason: reason }); if (reason === 'escape') { handleEscapeClose(event); } else { handleBlanketClose(event); } }, [handleEscapeClose, handleBlanketClose]); // Mirror the legacy window `keydown` listener so `onKeyDown` still fires // while the drawer is open. var handleKeyDown = (0, _react.useCallback)(function (evt) { onKeyDown === null || onKeyDown === void 0 || onKeyDown(evt); }, [onKeyDown]); (0, _react.useEffect)(function () { if (!isOpen) { return; } return (0, _bindEventListener.bind)(window, { type: 'keydown', listener: handleKeyDown }); }, [isOpen, handleKeyDown]); // `onOpenComplete` once the entry animation settles (via `Dialog`'s // `onEnterFinish`, which the underlying hook fires for animated, // non-animated and reduced-motion paths). var handleEnterFinish = (0, _react.useCallback)(function () { onOpenComplete === null || onOpenComplete === void 0 || onOpenComplete(contentRef.current); }, [onOpenComplete]); // `onCloseComplete` once the exit animation settles (via `Dialog`'s // `onExitFinish`). This is also where a custom `shouldReturnFocus={ref}` is // honoured: native `<dialog>` restores focus to the trigger at the start of // close, so the consumer's ref is focused now that the exit is done. // `shouldReturnFocus={false}` is a documented best-effort limitation; native // always restores focus to the trigger. var handleExitFinish = (0, _react.useCallback)(function () { var _contentRef$current; onCloseComplete === null || onCloseComplete === void 0 || onCloseComplete((_contentRef$current = contentRef.current) !== null && _contentRef$current !== void 0 ? _contentRef$current : lastContentElRef.current); lastContentElRef.current = null; if ((0, _typeof2.default)(shouldReturnFocus) === 'object' && shouldReturnFocus !== null && shouldReturnFocus !== void 0 && shouldReturnFocus.current) { shouldReturnFocus.current.focus(); } }, [onCloseComplete, shouldReturnFocus]); var accessibleName = getAccessibleName({ label: label, titleId: titleId }); return /*#__PURE__*/React.createElement(_dialogContent.Dialog, (0, _extends2.default)({ isOpen: isOpen, onClose: handleDialogClose, onEnterFinish: handleEnterFinish, onExitFinish: handleExitFinish, shouldAnimate: true, xcss: (0, _react2.cx)(styles.root, widthStyles[width], enterFromStyles[enterFrom]), enteringAnimationXcss: styles.enter, exitingAnimationXcss: styles.exit, testId: testId }, accessibleName), /*#__PURE__*/React.createElement(_dialogScrollLock.DialogScrollLock, { isOpen: true }), /*#__PURE__*/React.createElement("div", { ref: setContentEl, className: (0, _runtime.ax)([styles.surface]) }, /*#__PURE__*/React.createElement(_ensureIsInsideDrawerContext.EnsureIsInsideDrawerContext.Provider, { value: true }, /*#__PURE__*/React.createElement(_onCloseContext.OnCloseContext.Provider, { value: handleBackButtonClose }, children)))); }