@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
200 lines (196 loc) • 7.81 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
/**
* @jsxRuntime classic
* @jsx jsx
*/
import { Component } from 'react';
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
import { css, jsx, keyframes } from '@emotion/react';
import createAndFireEvent from '@atlaskit/analytics-next/createAndFireEvents';
import withAnalyticsContext from '@atlaskit/analytics-next/withAnalyticsContext';
import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
import { fg } from '@atlaskit/platform-feature-flags';
import Layer from '../Layer';
const packageName = "@atlaskit/editor-common";
const packageVersion = "114.41.0";
const halfFocusRing = 1;
const dropOffset = '0, 8';
const fadeIn = keyframes({
'0%': {
opacity: 0
},
'100%': {
opacity: 1
}
});
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/react/no-class-components
class DropList extends Component {
constructor(...args) {
super(...args);
_defineProperty(this, "wrapperStyles", css({
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
display: this.props.shouldFitContainer ? 'block' : 'inline-flex',
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
flex: this.props.shouldFitContainer ? '1 1 auto' : undefined,
transitionDuration: '0.2s',
transition: 'box-shadow 0.15s cubic-bezier(0.47, 0.03, 0.49, 1.38)'
}));
_defineProperty(this, "triggerStyles", css({
transitionDuration: '0.2s',
transition: 'box-shadow 0.15s cubic-bezier(0.47, 0.03, 0.49, 1.38)',
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
display: this.props.shouldFitContainer ? 'block' : 'inline-flex',
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
boxSizing: this.props.shouldFitContainer ? 'border-box' : undefined
}));
_defineProperty(this, "motionStyles", css({
animationName: `${fadeIn}`,
animationDuration: '360ms',
animationTimingFunction: 'cubic-bezier(0.8, 0, 0, 1)'
}));
/* eslint-disable @atlaskit/design-system/ensure-design-token-usage */
_defineProperty(this, "menuWrapper", () => {
return css({
color: "var(--ds-text-subtle, #505258)",
backgroundColor: "var(--ds-surface-overlay, #FFFFFF)",
borderRadius: "var(--ds-radius-small, 3px)",
boxShadow: "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)",
boxSizing: 'border-box',
overflow: 'auto',
padding: `${"var(--ds-space-050, 4px)"} 0`,
maxHeight: '90vh'
});
});
/* eslint-enable @atlaskit/design-system/ensure-design-token-usage */
_defineProperty(this, "componentDidMount", () => {
this.setContentWidth();
// We use a captured event here to avoid a radio or checkbox dropdown item firing its
// click event first, which would cause a re-render of the element and prevent DropList
// from detecting the actual source of this original click event.
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
document.addEventListener('click', this.handleClickOutside, true);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
document.addEventListener('keydown', this.handleEsc);
});
_defineProperty(this, "componentDidUpdate", () => {
if (this.props.isOpen) {
this.setContentWidth();
}
});
_defineProperty(this, "componentWillUnmount", () => {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
document.removeEventListener('click', this.handleClickOutside, true);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
document.removeEventListener('keydown', this.handleEsc);
});
_defineProperty(this, "setContentWidth", () => {
const {
dropContentRef,
triggerRef
} = this;
const {
shouldFitContainer
} = this.props;
// We need to manually set the content width to match the trigger width
if (shouldFitContainer && dropContentRef && triggerRef) {
dropContentRef.style.width = `${triggerRef.offsetWidth - halfFocusRing * 2}px`;
}
});
_defineProperty(this, "handleEsc", event => {
if ((event.key === 'Escape' || event.key === 'Esc') && this.props.isOpen) {
this.close(event);
}
});
_defineProperty(this, "handleClickOutside", event => {
if (this.props.isOpen) {
if (event.target instanceof Node) {
// Rather than check for the target within the entire DropList, we specify the trigger/content.
// This aids with future effort in scroll-locking DropList when isMenuFixed is enabled; the scroll
// blanket which stretches to the viewport should not stop 'close' from being triggered.
const withinTrigger = this.triggerRef && this.triggerRef.contains(event.target);
const withinContent = this.dropContentRef && this.dropContentRef.contains(event.target);
if (!withinTrigger && !withinContent) {
this.close(event);
}
}
}
});
_defineProperty(this, "close", event => {
if (this.props.onOpenChange) {
this.props.onOpenChange({
isOpen: false,
event
});
}
});
_defineProperty(this, "handleContentRef", ref => {
this.dropContentRef = ref;
// If the dropdown has just been opened, we focus on the containing element so the
// user can tab to the first dropdown item. We will only receive this ref if isOpen
// is true or null, so no need to check for truthiness here.
if (ref) {
ref.focus();
}
});
_defineProperty(this, "handleDroplistRef", ref => {
var _this$props$onDroplis, _this$props;
(_this$props$onDroplis = (_this$props = this.props).onDroplistRef) === null || _this$props$onDroplis === void 0 ? void 0 : _this$props$onDroplis.call(_this$props, ref);
});
_defineProperty(this, "handleTriggerRef", ref => {
this.triggerRef = ref;
});
}
render() {
const {
children,
isOpen,
position,
trigger,
onPositioned,
testId,
id
} = this.props;
const layerContent = isOpen ? jsx("div", {
css: this.menuWrapper,
"data-role": "droplistContent",
"data-testid": testId && `${testId}--content`,
ref: this.handleContentRef,
id: id,
role: "presentation"
}, children) : null;
return jsx("div", {
css: [this.wrapperStyles, fg('p2m-drop-down-motion') && this.motionStyles],
ref: this.handleDroplistRef
}, jsx(Layer, {
content: layerContent,
offset: dropOffset,
position: position,
onPositioned: onPositioned
}, jsx("div", {
css: [this.triggerStyles, fg('p2m-drop-down-motion') && this.motionStyles],
ref: this.handleTriggerRef
}, trigger)));
}
}
const createAndFireEventOnAtlaskit = createAndFireEvent('atlaskit');
const _default_1 = withAnalyticsContext({
componentName: 'droplist',
packageName,
packageVersion
})(withAnalyticsEvents({
onOpenChange: createAndFireEventOnAtlaskit({
action: 'toggled',
actionSubject: 'droplist',
attributes: {
componentName: 'droplist',
packageName,
packageVersion
}
})
})(DropList));
export default _default_1;