@atlaskit/inline-dialog
Version:
An inline dialog is a pop-up container for small amounts of information. It can also contain controls.
155 lines (150 loc) • 5.49 kB
JavaScript
/* inline-dialog-top-layer.tsx generated by @compiled/babel-plugin v0.39.1 */
import "./inline-dialog-top-layer.compiled.css";
import * as React from 'react';
import { ax, ix } from "@compiled/react/runtime";
import { Fragment, memo, useCallback, useEffect, useMemo, useRef } from 'react';
import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next';
import noop from '@atlaskit/ds-lib/noop';
import { slideAndFade } from '@atlaskit/top-layer/animations';
import { getAriaForTrigger } from '@atlaskit/top-layer/get-aria-for-trigger';
import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map';
import { createPopoverCloseEvent, Popover } from '@atlaskit/top-layer/popover';
import { useAnchorPosition } from '@atlaskit/top-layer/use-anchor-position';
import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
const displayContentsStyles = {
root: "_1e0c1bgi"
};
const styles = {
container: "_2rkofajl _vchh1ntv _p12flti4 _c71llti4 _bfhk1bhr _16qs130s _syazi7uo _85i5pxbi _1q51pxbi _y4ti1ejb _bozg1ejb"
};
const animation = slideAndFade();
/**
* Applies ARIA attributes to the child trigger element via an effect,
* keeping them in sync with popup state.
*/
function TriggerWrapper({
children,
triggerRef,
ariaAttributes
}) {
useEffect(() => {
const trigger = triggerRef.current;
if (!trigger) {
return;
}
// Apply each attribute. When a value is `undefined` (e.g.
// `aria-controls` while the popover host is not in the DOM),
// remove the attribute so the trigger does not retain a stale
// reference from a previous open.
Object.entries(ariaAttributes).forEach(([key, value]) => {
if (value === undefined) {
trigger.removeAttribute(key);
return;
}
trigger.setAttribute(key, String(value));
});
}, [ariaAttributes, triggerRef]);
return /*#__PURE__*/React.createElement("div", {
ref: node => {
var _node$firstElementChi;
const firstElementChild = (_node$firstElementChi = node === null || node === void 0 ? void 0 : node.firstElementChild) !== null && _node$firstElementChi !== void 0 ? _node$firstElementChi : null;
triggerRef.current = firstElementChild;
},
className: ax([displayContentsStyles.root])
}, children);
}
/**
* Top-layer implementation of InlineDialog.
*
* Replaces the legacy rendering pipeline (Popper.js + Portal + @atlaskit/layering)
* with the native Popover API + CSS Anchor Positioning via @atlaskit/top-layer.
*
* Gated behind the `platform-dst-top-layer` feature flag.
*/
const InlineDialogTopLayer = /*#__PURE__*/memo(function InlineDialogTopLayer({
isOpen = false,
onContentBlur = noop,
onContentClick = noop,
onContentFocus = noop,
onClose: providedOnClose = noop,
placement = 'bottom-start',
testId,
content,
children,
// No-op props.
// These props are accepted for API compatibility but have no effect
// in the top-layer path. Each is documented with why it is unnecessary.
// top-layer: CSS Anchor Positioning replaces Popper strategy. No-op.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
strategy: _strategy,
// top-layer: Popper.js fallbackPlacements not applicable. No-op.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fallbackPlacements: _fallbackPlacements
}) {
const triggerRef = useRef(null);
const popoverRef = useRef(null);
const popoverId = usePopoverId();
const onClose = usePlatformLeafEventHandler({
fn: event => providedOnClose(event),
action: 'closed',
componentName: 'inlineDialog',
packageName: "@atlaskit/inline-dialog",
packageVersion: "19.0.1"
});
// Placement conversion.
const topLayerPlacement = useMemo(() => fromLegacyPlacement({
legacy: placement
}), [placement]);
// `isOpen` is included so the anchor positioning effect re-runs when
// the Popover host element is unmounted/remounted across open cycles.
useAnchorPosition({
anchorRef: triggerRef,
popoverRef,
placement: topLayerPlacement,
isOpen
});
// onClose bridge.
// Translates top-layer's { reason } into the legacy onClose({ isOpen, event }) shape.
// Focus restoration is handled automatically by the Popover based on the content role
// (role="dialog" -> auto-restore).
const handleOnClose = useCallback(({
reason
}) => {
const syntheticEvent = createPopoverCloseEvent({
reason
});
onClose({
isOpen: false,
event: syntheticEvent
});
}, [onClose]);
const ariaAttributes = getAriaForTrigger({
role: 'dialog',
isOpen,
popoverId
});
return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(TriggerWrapper, {
triggerRef: triggerRef,
ariaAttributes: ariaAttributes
}, children), /*#__PURE__*/React.createElement(Popover, {
ref: popoverRef,
id: popoverId,
role: "dialog"
// TODO: i18n. Hardcoded label is not translatable.
// Acceptable given this component is intent-to-deprecate.
,
label: "Inline dialog",
isOpen: isOpen,
onClose: handleOnClose,
animate: animation,
placement: topLayerPlacement,
testId: testId
}, /*#__PURE__*/React.createElement("div", {
role: "presentation",
onBlur: onContentBlur,
onClick: onContentClick,
onFocus: onContentFocus,
className: ax([styles.container])
}, typeof content === 'function' ? content() : content)));
});
export default InlineDialogTopLayer;