@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
JavaScript
/* 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))));
}