UNPKG

@atlaskit/editor-plugin-floating-toolbar

Version:

Floating toolbar plugin for @atlaskit/editor-core

277 lines (273 loc) 13.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.default = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _react2 = require("@emotion/react"); var _ui = require("@atlaskit/editor-common/ui"); var _uiMenu = require("@atlaskit/editor-common/ui-menu"); var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-down")); var _Divider = require("./Divider"); var _DropdownMenu = _interopRequireWildcard(require("./DropdownMenu")); 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" != _typeof(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); } 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 _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /** * @jsxRuntime classic * @jsx jsx * @jsxFrag */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage var dropdownExpandContainer = (0, _react2.css)({ margin: "0px ".concat("var(--ds-space-negative-050, -4px)") }); // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage var iconGroup = (0, _react2.css)({ display: 'flex' }); var CompositeIcon = function CompositeIcon(_ref) { var icon = _ref.icon; return (0, _react2.jsx)("div", { css: iconGroup }, icon, (0, _react2.jsx)("span", { css: dropdownExpandContainer }, (0, _react2.jsx)(_chevronDown.default, { color: "currentColor", spacing: "spacious", label: "Expand dropdown menu", size: "small" }))); }; // eslint-disable-next-line @repo/internal/react/no-class-components var Dropdown = exports.default = /*#__PURE__*/function (_Component) { function Dropdown() { var _this; (0, _classCallCheck2.default)(this, Dropdown); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Dropdown, [].concat(args)); (0, _defineProperty2.default)(_this, "state", { isOpen: false, isOpenedByKeyboard: false }); (0, _defineProperty2.default)(_this, "triggerRef", /*#__PURE__*/_react.default.createRef()); (0, _defineProperty2.default)(_this, "makeArrayOptionsFromCallback", function (makeOptions) { var options = makeOptions(); return options; }); (0, _defineProperty2.default)(_this, "renderArrayOptions", function (options) { var _this$props = _this.props, showSelected = _this$props.showSelected, dispatchCommand = _this$props.dispatchCommand, editorView = _this$props.editorView, areAnyNewToolbarFlagsEnabled = _this$props.areAnyNewToolbarFlagsEnabled; return (0, _react2.jsx)(_DropdownMenu.default, { hide: _this.hide, dispatchCommand: dispatchCommand, items: options, showSelected: showSelected, editorView: editorView, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }); }); (0, _defineProperty2.default)(_this, "toggleOpen", function () { var onClick = _this.props.onClick; if (onClick) { onClick(); } _this.setState({ isOpen: !_this.state.isOpen, isOpenedByKeyboard: false }); var onToggle = _this.props.onToggle; if (!onToggle) { return; } requestAnimationFrame(function () { _this.props.dispatchCommand(onToggle); }); }); (0, _defineProperty2.default)(_this, "toggleOpenByKeyboard", function (event) { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); _this.setState({ isOpen: !_this.state.isOpen, isOpenedByKeyboard: true }); } }); (0, _defineProperty2.default)(_this, "hide", function () { _this.setState(_objectSpread(_objectSpread({}, _this.state), {}, { isOpen: false })); }); (0, _defineProperty2.default)(_this, "hideOnEsc", function () { var _document$querySelect; // Focus the trigger button only on Escape // Focus is done before hiding to ensure onBlur is called // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting (_document$querySelect = document.querySelector("[data-testid=".concat(_this.props.buttonTestId, "]"))) === null || _document$querySelect === void 0 || _document$querySelect.focus(); _this.hide(); }); (0, _defineProperty2.default)(_this, "onOpenChanged", function (openChangedEvent) { if (!openChangedEvent.isOpen && openChangedEvent.event instanceof KeyboardEvent) { var _openChangedEvent$eve; ((_openChangedEvent$eve = openChangedEvent.event) === null || _openChangedEvent$eve === void 0 ? void 0 : _openChangedEvent$eve.key) === 'Escape' ? _this.hideOnEsc() : _this.hide(); } }); return _this; } (0, _inherits2.default)(Dropdown, _Component); return (0, _createClass2.default)(Dropdown, [{ key: "render", value: function render() { var isOpen = this.state.isOpen; var _this$props2 = this.props, title = _this$props2.title, icon = _this$props2.icon, iconBefore = _this$props2.iconBefore, options = _this$props2.options, dispatchCommand = _this$props2.dispatchCommand, mountPoint = _this$props2.mountPoint, boundariesElement = _this$props2.boundariesElement, scrollableElement = _this$props2.scrollableElement, hideExpandIcon = _this$props2.hideExpandIcon, disabled = _this$props2.disabled, tooltip = _this$props2.tooltip, buttonTestId = _this$props2.buttonTestId, dropdownWidth = _this$props2.dropdownWidth, dropdownListId = _this$props2.dropdownListId, alignDropdownWithToolbar = _this$props2.alignDropdownWithToolbar, footer = _this$props2.footer, onMount = _this$props2.onMount, pulse = _this$props2.pulse, shouldFitContainer = _this$props2.shouldFitContainer, alignX = _this$props2.alignX, areAnyNewToolbarFlagsEnabled = _this$props2.areAnyNewToolbarFlagsEnabled; var trigger; if (icon) { var TriggerIcon = hideExpandIcon ? icon : (0, _react2.jsx)(CompositeIcon, { icon: icon }); trigger = (0, _react2.jsx)(_ui.FloatingToolbarButton, { testId: buttonTestId, title: title, icon: TriggerIcon, onClick: this.toggleOpen, onKeyDown: this.toggleOpenByKeyboard, selected: isOpen, disabled: disabled, tooltipContent: tooltip, ariaHasPopup: areAnyNewToolbarFlagsEnabled ? true : undefined, onMount: onMount, pulse: pulse, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }); } else { trigger = (0, _react2.jsx)(_ui.FloatingToolbarButton, { testId: buttonTestId, iconAfter: (0, _react2.jsx)("span", { css: dropdownExpandContainer }, (0, _react2.jsx)(_chevronDown.default, { color: "currentColor", spacing: "spacious", label: "Expand dropdown menu", size: "small" })), icon: iconBefore, onClick: this.toggleOpen, onKeyDown: this.toggleOpenByKeyboard, selected: isOpen, disabled: disabled, tooltipContent: tooltip, ariaHasPopup: true, areaControls: dropdownListId, onMount: onMount, pulse: pulse, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }, title); } /** * We want to change direction of our dropdowns a bit early, * not exactly when it hits the boundary. */ var fitTolerance = 10; var fitWidth = Array.isArray(options) || typeof options === 'function' ? dropdownWidth || _DropdownMenu.menuItemDimensions.width : options.width; var fitHeight = Array.isArray(options) ? options.length * _DropdownMenu.menuItemDimensions.height + _DropdownMenu.itemSpacing * 2 : typeof options === 'function' ? this.makeArrayOptionsFromCallback(options).length : options.height; return ( /** * At the moment footer diver is rendered along with footer, if it's provided * This is to provide some level of consistency * Refer to the PR for more details: * https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/137394/overview?commentId=8130003 */ (0, _react2.jsx)(_uiMenu.DropdownContainer, { alignX: alignX, mountTo: mountPoint, boundariesElement: boundariesElement, scrollableElement: scrollableElement, isOpen: isOpen, handleClickOutside: this.hide, handleEscapeKeydown: this.hideOnEsc, onOpenChange: this.onOpenChanged, fitWidth: fitWidth + fitTolerance, fitHeight: fitHeight + fitTolerance, trigger: trigger, dropdownListId: dropdownListId, alignDropdownWithParentElement: alignDropdownWithToolbar // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , arrowKeyNavigationProviderOptions: { type: _uiMenu.ArrowKeyNavigationType.MENU }, shouldFitContainer: shouldFitContainer }, Array.isArray(options) ? this.renderArrayOptions(options) : typeof options === 'function' ? this.renderArrayOptions(this.makeArrayOptionsFromCallback(options)) : options.render({ hide: this.hide, dispatchCommand: dispatchCommand }), footer && (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)(_Divider.Divider, null), footer)) ); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps, prevState) { if (prevState.isOpen !== this.state.isOpen) { if (this.props.setDisableParentScroll) { this.props.setDisableParentScroll(this.state.isOpen); } // ECA11Y-235: no sense in sending keyboard event since the menu popup mounted to the custom element, // we will ensure first element focused asap as 'MenuArrowKeyNavigationProvider' is mounted if (this.props.mountPoint) { return; } if (this.state.isOpen && this.state.isOpenedByKeyboard) { var dropList = document.querySelector('[data-role="droplistContent"]'); if (dropList) { // Add setTimeout so that if a dropdown item has tooltip, // the tooltip won't be rendered until next render cycle // when the droplist is correctly positioned. // This makes tooltip appears at the correct position for the first dropdown item. setTimeout(function () { var keyboardEvent = new KeyboardEvent('keydown', { bubbles: true, key: 'ArrowDown' }); dropList.dispatchEvent(keyboardEvent); }, 0); } } } } }]); }(_react.Component);