UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

345 lines (340 loc) • 19.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.DropdownMenuItem = DropdownMenuItem; exports.default = exports.DropdownMenuWithKeyboardNavigation = void 0; var _objectDestructuringEmpty2 = _interopRequireDefault(require("@babel/runtime/helpers/objectDestructuringEmpty")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral")); var _react = _interopRequireWildcard(require("react")); var _react2 = require("@emotion/react"); var _editorSharedStyles = require("@atlaskit/editor-shared-styles"); var _menu = require("@atlaskit/menu"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _colors = require("@atlaskit/theme/colors"); var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip")); var _styles = require("../../styles"); var _ToolbarArrowKeyNavigationProvider = require("../../ui-menu/ToolbarArrowKeyNavigationProvider"); var _uiReact = require("../../ui-react"); var _DropList = _interopRequireDefault(require("../../ui/DropList")); var _Popup = _interopRequireDefault(require("../../ui/Popup")); var _ArrowKeyNavigationProvider = require("../ArrowKeyNavigationProvider"); var _types = require("../ArrowKeyNavigationProvider/types"); var _excluded = ["children"]; var _templateObject, _templateObject2, _templateObject3, _templateObject4; /** @jsx jsx */ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } var wrapper = (0, _react2.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n /* tooltip in ToolbarButton is display:block */\n & > div > div {\n display: flex;\n }\n"]))); var focusedMenuItemStyle = (0, _react2.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n box-shadow: inset 0px 0px 0px 2px ", ";\n outline: none;\n"])), "var(--ds-border-focused, ".concat(_colors.B100, ")")); var buttonStyles = function buttonStyles(isActive, submenuActive) { if (isActive) { /** * Hack for item to imitate old dropdown-menu selected styles */ return (0, _react2.css)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2.default)(["\n > span,\n > span:hover,\n > span:active {\n background: ", ";\n color: ", ";\n }\n :focus > span[aria-disabled='false'] {\n ", ";\n }\n :focus-visible,\n :focus-visible > span[aria-disabled='false'] {\n outline: none;\n }\n "])), "var(--ds-background-selected, #6c798f)", "var(--ds-text, #fff)", focusedMenuItemStyle); } else { return (0, _react2.css)(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2.default)(["\n > span:hover[aria-disabled='false'] {\n color: ", ";\n background-color: ", ";\n }\n ", "\n > span[aria-disabled='true'] {\n color: ", ";\n }\n :focus > span[aria-disabled='false'] {\n ", ";\n }\n :focus-visible,\n :focus-visible > span[aria-disabled='false'] {\n outline: none;\n }\n "])), "var(--ds-text, ".concat(_colors.N900, ")"), "var(--ds-background-neutral-subtle-hovered, rgb(244, 245, 247))", !submenuActive && "\n > span:active[aria-disabled='false'] {\n background-color: ".concat("var(--ds-background-neutral-subtle-pressed, rgb(179, 212, 255))", ";\n }"), "var(--ds-text-disabled, ".concat(_colors.N70, ")"), focusedMenuItemStyle); // The default focus-visible style is removed to ensure consistency across browsers } }; var DropListWithOutsideListeners = (0, _uiReact.withReactEditorViewOuterListeners)(_DropList.default); /** * Wrapper around @atlaskit/droplist which uses Popup and Portal to render * dropdown-menu outside of "overflow: hidden" containers when needed. * * Also it controls popper's placement. */ var DropdownMenuWrapper = exports.default = /*#__PURE__*/function (_PureComponent) { (0, _inherits2.default)(DropdownMenuWrapper, _PureComponent); var _super = _createSuper(DropdownMenuWrapper); function DropdownMenuWrapper() { var _this; (0, _classCallCheck2.default)(this, DropdownMenuWrapper); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _super.call.apply(_super, [this].concat(args)); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "state", { popupPlacement: ['bottom', 'left'], selectionIndex: -1 }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "popupRef", /*#__PURE__*/_react.default.createRef()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleRef", function (target) { _this.setState({ target: target || undefined }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updatePopupPlacement", function (placement) { var previousPlacement = _this.state.popupPlacement; if (placement[0] !== previousPlacement[0] || placement[1] !== previousPlacement[1]) { _this.setState({ popupPlacement: placement }); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleCloseAndFocus", function () { var _this$state$target; (_this$state$target = _this.state.target) === null || _this$state$target === void 0 || (_this$state$target = _this$state$target.querySelector('button')) === null || _this$state$target === void 0 || _this$state$target.focus(); _this.handleClose(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleClose", function () { if (_this.props.onOpenChange) { _this.props.onOpenChange({ isOpen: false }); } }); return _this; } (0, _createClass2.default)(DropdownMenuWrapper, [{ key: "renderDropdownMenu", value: function renderDropdownMenu() { var _this2 = this; var _this$state = this.state, target = _this$state.target, popupPlacement = _this$state.popupPlacement; var _this$props = this.props, items = _this$props.items, mountTo = _this$props.mountTo, boundariesElement = _this$props.boundariesElement, scrollableElement = _this$props.scrollableElement, offset = _this$props.offset, fitHeight = _this$props.fitHeight, fitWidth = _this$props.fitWidth, isOpen = _this$props.isOpen, zIndex = _this$props.zIndex, shouldUseDefaultRole = _this$props.shouldUseDefaultRole, onItemActivated = _this$props.onItemActivated, arrowKeyNavigationProviderOptions = _this$props.arrowKeyNavigationProviderOptions, section = _this$props.section; // Note that this onSelection function can't be refactored to useMemo for // performance gains as it is being used as a dependency in a useEffect in // MenuArrowKeyNavigationProvider in order to check for re-renders to adjust // focus for accessibility. If this needs to be refactored in future refer // back to ED-16740 for context. var navigationProviderProps = arrowKeyNavigationProviderOptions.type === _types.ArrowKeyNavigationType.COLOR ? arrowKeyNavigationProviderOptions : _objectSpread(_objectSpread({}, arrowKeyNavigationProviderOptions), {}, { onSelection: function onSelection(index) { var result = []; if (typeof onItemActivated === 'function') { result = items.reduce(function (result, group) { return result.concat(group.items); }, result); onItemActivated({ item: result[index], shouldCloseMenu: false }); } } }); return (0, _react2.jsx)(_Popup.default, { target: isOpen ? target : undefined, mountTo: mountTo, boundariesElement: boundariesElement, scrollableElement: scrollableElement, onPlacementChanged: this.updatePopupPlacement, fitHeight: fitHeight, fitWidth: fitWidth, zIndex: zIndex || _editorSharedStyles.akEditorFloatingPanelZIndex, offset: offset }, (0, _react2.jsx)(_ArrowKeyNavigationProvider.ArrowKeyNavigationProvider, (0, _extends2.default)({}, navigationProviderProps, { handleClose: this.handleCloseAndFocus, closeOnTab: true }), (0, _react2.jsx)(DropListWithOutsideListeners, { isOpen: true, appearance: "tall", position: popupPlacement.join(' '), shouldFlip: false, shouldFitContainer: true, isTriggerNotTabbable: true, handleClickOutside: this.handleClose, handleEscapeKeydown: this.handleCloseAndFocus, handleEnterKeydown: function handleEnterKeydown(e) { e.preventDefault(); e.stopPropagation(); }, targetRef: this.state.target }, (0, _react2.jsx)("div", { style: { height: 0, minWidth: fitWidth || 0 } }), (0, _react2.jsx)("div", { ref: this.popupRef }, (0, _platformFeatureFlags.getBooleanFF)('platform.editor.menu.group-items') && (0, _react2.jsx)(_menu.MenuGroup, { role: shouldUseDefaultRole ? 'group' : 'menu' }, items.map(function (group, index) { return (0, _react2.jsx)(_menu.Section, { hasSeparator: (section === null || section === void 0 ? void 0 : section.hasSeparator) && index > 0, title: section === null || section === void 0 ? void 0 : section.title, key: index }, group.items.map(function (item) { var _item$key; return (0, _react2.jsx)(DropdownMenuItem, { key: (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : String(item.content), item: item, onItemActivated: _this2.props.onItemActivated, shouldUseDefaultRole: _this2.props.shouldUseDefaultRole, onMouseEnter: _this2.props.onMouseEnter, onMouseLeave: _this2.props.onMouseLeave }); })); })), !(0, _platformFeatureFlags.getBooleanFF)('platform.editor.menu.group-items') && items.map(function (group, index) { return (0, _react2.jsx)(_menu.MenuGroup, { key: index, role: shouldUseDefaultRole ? 'group' : 'menu' }, group.items.map(function (item) { var _item$key2; return (0, _react2.jsx)(DropdownMenuItem, { key: (_item$key2 = item.key) !== null && _item$key2 !== void 0 ? _item$key2 : String(item.content), item: item, onItemActivated: _this2.props.onItemActivated, shouldUseDefaultRole: _this2.props.shouldUseDefaultRole, onMouseEnter: _this2.props.onMouseEnter, onMouseLeave: _this2.props.onMouseLeave }); })); }))))); } }, { key: "render", value: function render() { var _this$props2 = this.props, children = _this$props2.children, isOpen = _this$props2.isOpen; return (0, _react2.jsx)("div", { css: wrapper }, (0, _react2.jsx)("div", { ref: this.handleRef }, children), isOpen ? this.renderDropdownMenu() : null); } }, { key: "componentDidUpdate", value: function componentDidUpdate(previousProps) { var isOpenToggled = this.props.isOpen !== previousProps.isOpen; if (this.props.isOpen && isOpenToggled) { if (typeof this.props.shouldFocusFirstItem === 'function' && this.props.shouldFocusFirstItem()) { var _this$state$target2; var keyboardEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }); (_this$state$target2 = this.state.target) === null || _this$state$target2 === void 0 || _this$state$target2.dispatchEvent(keyboardEvent); } } } }]); return DropdownMenuWrapper; }(_react.PureComponent); var DropdownMenuItemCustomComponent = /*#__PURE__*/_react.default.forwardRef(function (props, ref) { var children = props.children, rest = (0, _objectWithoutProperties2.default)(props, _excluded); return (0, _react2.jsx)("span", (0, _extends2.default)({ ref: ref }, rest, { style: { // This forces the item container back to be `position: static`, the default value. // This ensures the custom nested menu for table color picker still works as now // menu items from @atlaskit/menu all have `position: relative` set for the selected borders. // The current implementation unfortunately is very brittle. Design System Team will // be prioritizing official support for accessible nested menus that we want you to move // to in the future. position: 'static' } }), children); }); function DropdownMenuItem(_ref) { var _item$key3; var item = _ref.item, onItemActivated = _ref.onItemActivated, shouldUseDefaultRole = _ref.shouldUseDefaultRole, _onMouseEnter = _ref.onMouseEnter, _onMouseLeave = _ref.onMouseLeave; var _React$useState = _react.default.useState(false), _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2), submenuActive = _React$useState2[0], setSubmenuActive = _React$useState2[1]; // onClick and value.name are the action indicators in the handlers // If neither are present, don't wrap in an Item. if (!item.onClick && !(item.value && item.value.name)) { return (0, _react2.jsx)("span", { key: String(item.content) }, item.content); } var _handleSubmenuActive = function _handleSubmenuActive(event) { setSubmenuActive(!!event.target.closest(".".concat(_styles.DropdownMenuSharedCssClassName.SUBMENU))); }; var dropListItem = (0, _react2.jsx)("div", { css: function css() { return buttonStyles(item.isActive, submenuActive); }, tabIndex: -1, "aria-disabled": item.isDisabled ? 'true' : 'false', onMouseDown: _handleSubmenuActive }, (0, _react2.jsx)(_menu.CustomItem, { item: item, key: (_item$key3 = item.key) !== null && _item$key3 !== void 0 ? _item$key3 : String(item.content), testId: "dropdown-item__".concat(String(item.content)), role: shouldUseDefaultRole ? 'button' : 'menuitem', iconBefore: item.elemBefore, iconAfter: item.elemAfter, isDisabled: item.isDisabled, onClick: function onClick() { return onItemActivated && onItemActivated({ item: item }); }, "aria-label": item['aria-label'] || String(item.content), "aria-pressed": shouldUseDefaultRole ? item.isActive : undefined, "aria-keyshortcuts": item['aria-keyshortcuts'], onMouseDown: function onMouseDown(e) { e.preventDefault(); }, component: DropdownMenuItemCustomComponent, onMouseEnter: function onMouseEnter() { return _onMouseEnter && _onMouseEnter({ item: item }); }, onMouseLeave: function onMouseLeave() { return _onMouseLeave && _onMouseLeave({ item: item }); } }, item.content)); if (item.tooltipDescription) { var _item$key4; return (0, _react2.jsx)(_tooltip.default, { key: (_item$key4 = item.key) !== null && _item$key4 !== void 0 ? _item$key4 : String(item.content), content: item.tooltipDescription, position: item.tooltipPosition }, dropListItem); } return dropListItem; } var DropdownMenuWithKeyboardNavigation = exports.DropdownMenuWithKeyboardNavigation = /*#__PURE__*/_react.default.memo(function (_ref2) { var props = (0, _extends2.default)({}, ((0, _objectDestructuringEmpty2.default)(_ref2), _ref2)); var keyDownHandlerContext = (0, _react.useContext)(_ToolbarArrowKeyNavigationProvider.KeyDownHandlerContext); // This context is to handle the tab, Arrow Right/Left key events for dropdown. // Default context has the void callbacks for above key events return (0, _react2.jsx)(DropdownMenuWrapper, (0, _extends2.default)({ arrowKeyNavigationProviderOptions: _objectSpread(_objectSpread({}, props.arrowKeyNavigationProviderOptions), {}, { keyDownHandlerContext: keyDownHandlerContext }) }, props)); });