UNPKG

@atlaskit/editor-common

Version:

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

501 lines (489 loc) • 22.7 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 _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _react = _interopRequireWildcard(require("react")); var _react2 = require("@emotion/react"); var _reactIntl = require("react-intl"); var _withAnalyticsContext = _interopRequireDefault(require("@atlaskit/analytics-next/withAnalyticsContext")); var _withAnalyticsEvents = _interopRequireDefault(require("@atlaskit/analytics-next/withAnalyticsEvents")); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _analytics = require("../../analytics"); var _getEditorUgcToken = _interopRequireDefault(require("../../ugc-tokens/get-editor-ugc-token")); var _ViewMore = require("../components/ViewMore"); var _constants = require("../constants"); var _useContainerWidth2 = _interopRequireDefault(require("../hooks/use-container-width")); var _useSelectAndFocusOnArrowNavigation = _interopRequireDefault(require("../hooks/use-select-and-focus-on-arrow-navigation")); var _CategoryList = _interopRequireDefault(require("./CategoryList")); var _ElementList = _interopRequireDefault(require("./ElementList/ElementList")); var _ElementSearch = _interopRequireDefault(require("./ElementSearch")); 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); } /** * @jsxRuntime classic * @jsx jsx */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766 var wrapper = (0, _react2.css)({ width: '100%', maxHeight: 'inherit', overflow: 'hidden' }); var baseBrowserContainerStyles = (0, _react2.css)({ display: 'flex', height: '100%', minHeight: '-webkit-fill-available' }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var mobileElementBrowserContainer = (0, _react2.css)(baseBrowserContainerStyles, { flexDirection: 'column' }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var elementBrowserContainer = (0, _react2.css)(baseBrowserContainerStyles, { flexDirection: 'row' }); var baseSidebarStyles = (0, _react2.css)({ display: 'flex', flexDirection: 'column', overflowX: 'auto', overflowY: 'hidden' }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var mobileSideBar = (0, _react2.css)(baseSidebarStyles, { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 flex: "0 0 ".concat(_constants.INLINE_SIDEBAR_HEIGHT), padding: "var(--ds-space-150, 12px)".concat(" ", "var(--ds-space-150, 12px)", " 0 ", "var(--ds-space-150, 12px)") }); var mobileSideBarShowCategories = (0, _react2.css)({ flex: '0 0 auto' }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var sideBar = (0, _react2.css)(baseSidebarStyles, { flex: "0 0 'auto'" }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var sideBarShowCategories = (0, _react2.css)(baseSidebarStyles, { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 flex: "0 0 ".concat(_constants.SIDEBAR_WIDTH) }); var sidebarHeading = (0, _react2.css)({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 flex: "0 0 ".concat(_constants.SIDEBAR_HEADING_WRAPPER_HEIGHT), display: 'inline-flex', alignItems: 'center', paddingLeft: "var(--ds-space-150, 12px)", // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values font: (0, _getEditorUgcToken.default)('editor.font.heading.h1') }); var mobileMainContent = (0, _react2.css)({ flex: '1 1 auto', display: 'flex', flexDirection: 'column', overflowY: 'auto', height: '100%' }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var mainContent = (0, _react2.css)(mobileMainContent, { marginLeft: "var(--ds-space-200, 16px)", height: 'auto' }); var searchContainer = (0, _react2.css)({ paddingBottom: "var(--ds-space-200, 16px)" }); var mobileCategoryListWrapper = (0, _react2.css)({ display: 'flex', overflowX: 'auto', padding: "var(--ds-space-200, 16px)".concat(" 0 ", "var(--ds-space-200, 16px)", " 0"), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 minHeight: "".concat(_constants.GRID_SIZE * 4, "px"), overflow: '-moz-scrollbars-none', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766 '&::-webkit-scrollbar': { display: 'none' }, scrollbarWidth: 'none', MsOverflowStyle: 'none' }); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 var categoryListWrapper = (0, _react2.css)(mobileCategoryListWrapper, { padding: 0, marginTop: "var(--ds-space-200, 16px)", flexDirection: 'column' }); function StatelessElementBrowser(props) { var _props$categories; var items = props.items, onSelectItem = props.onSelectItem, onInsertItem = props.onInsertItem, onViewMore = props.onViewMore, selectedCategory = props.selectedCategory, onSelectCategory = props.onSelectCategory, searchTerm = props.searchTerm, showCategories = props.showCategories, cache = props.cache, _props$autoFocusSearc = props.autoFocusSearch, autoFocusSearch = _props$autoFocusSearc === void 0 ? true : _props$autoFocusSearc; var _useContainerWidth = (0, _useContainerWidth2.default)(), containerWidth = _useContainerWidth.containerWidth, ContainerWidthMonitor = _useContainerWidth.ContainerWidthMonitor; var categoryBeenChosen = (0, _react.useRef)(false); var _useState = (0, _react.useState)(1), _useState2 = (0, _slicedToArray2.default)(_useState, 2), columnCount = _useState2[0], setColumnCount = _useState2[1]; var isFocusSearch; var selectedCategoryIndex = (_props$categories = props.categories) === null || _props$categories === void 0 ? void 0 : _props$categories.findIndex(function (category) { return category.name === selectedCategory; }); var _useState3 = (0, _react.useState)(autoFocusSearch), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), canFocusSearch = _useState4[0], setCanFocusSearch = _useState4[1]; if (showCategories) { var isEmptySearchTerm = !searchTerm || (searchTerm === null || searchTerm === void 0 ? void 0 : searchTerm.length) === 0; if (!isEmptySearchTerm) { // clear the flag if the search happens after a user has chosen the category categoryBeenChosen.current = false; } // A11Y: if categories exists and search can be focused, on the initial render it should receive focus. // After user pick some category the category should stay focused. isFocusSearch = canFocusSearch && (!categoryBeenChosen.current || !isEmptySearchTerm); } var itemIsDisabled = (0, _react.useCallback)(function (index) { var _items$index$isDisabl, _items$index; return (_items$index$isDisabl = (_items$index = items[index]) === null || _items$index === void 0 ? void 0 : _items$index.isDisabled) !== null && _items$index$isDisabl !== void 0 ? _items$index$isDisabl : false; }, [items]); var _useSelectAndFocusOnA = (0, _useSelectAndFocusOnArrowNavigation.default)(items.length - 1, columnCount, !!onViewMore, itemIsDisabled, isFocusSearch, autoFocusSearch), selectedItemIndex = _useSelectAndFocusOnA.selectedItemIndex, focusedItemIndex = _useSelectAndFocusOnA.focusedItemIndex, setFocusedItemIndex = _useSelectAndFocusOnA.setFocusedItemIndex, setFocusedCategoryIndex = _useSelectAndFocusOnA.setFocusedCategoryIndex, focusOnEmptyStateButton = _useSelectAndFocusOnA.focusOnEmptyStateButton, focusedCategoryIndex = _useSelectAndFocusOnA.focusedCategoryIndex, focusOnSearch = _useSelectAndFocusOnA.focusOnSearch, focusOnViewMore = _useSelectAndFocusOnA.focusOnViewMore, onKeyDown = _useSelectAndFocusOnA.onKeyDown, setFocusOnSearch = _useSelectAndFocusOnA.setFocusOnSearch; (0, _react.useEffect)(function () { (0, _analytics.fireAnalyticsEvent)(props.createAnalyticsEvent)({ payload: { action: _analytics.ACTION.OPENED, actionSubject: _analytics.ACTION_SUBJECT.ELEMENT_BROWSER, eventType: _analytics.EVENT_TYPE.UI, attributes: { mode: props.mode } } }); return function () { (0, _analytics.fireAnalyticsEvent)(props.createAnalyticsEvent)({ payload: { action: _analytics.ACTION.CLOSED, actionSubject: _analytics.ACTION_SUBJECT.ELEMENT_BROWSER, eventType: _analytics.EVENT_TYPE.UI, attributes: { mode: props.mode } } }); }; }, [props.createAnalyticsEvent, props.mode]); /* Only for hitting enter to select item when focused on search bar, * The actual enter key press is handled on individual items level. */ var selectedItem = selectedItemIndex !== undefined ? items[selectedItemIndex] : null; var onItemsEnterTabKeyPress = (0, _react.useCallback)(function (e) { var _selectedItem$isDisab; if (e.key !== 'Enter' && (e.key !== 'Tab' || !showCategories)) { return; } if (showCategories && e.key === 'Tab' && selectedCategoryIndex !== undefined) { // A11Y: Set focus on first category if tab pressed on search setFocusedCategoryIndex(selectedCategoryIndex); e.preventDefault(); return; } if (onInsertItem && selectedItem != null && !((_selectedItem$isDisab = selectedItem.isDisabled) !== null && _selectedItem$isDisab !== void 0 ? _selectedItem$isDisab : false)) { onInsertItem(selectedItem); } e.preventDefault(); }, [onInsertItem, selectedItem, setFocusedCategoryIndex, showCategories, selectedCategoryIndex]); /** * On arrow key selection and clicks the selectedItemIndex will change. * Making sure to update parent component. */ (0, _react.useEffect)(function () { if (onSelectItem && selectedItem != null) { onSelectItem(selectedItem); } }, [onSelectItem, selectedItem]); var onSelectCategoryCB = (0, _react.useCallback)(function (category) { onSelectCategory(category); categoryBeenChosen.current = true; }, [categoryBeenChosen, onSelectCategory]); var handleKeyPress = function handleKeyPress(e) { if (e.key === 'Tab') { // only Tab key can change focus from close button (if present) setCanFocusSearch(true); } }; var handleClick = function handleClick() { setCanFocusSearch(true); }; var browserContent = (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)(ContainerWidthMonitor, null), containerWidth < _constants.DEVICE_BREAKPOINT_NUMBERS.medium ? (0, _react2.jsx)(MobileBrowser // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading , (0, _extends2.default)({}, props, { selectedItemIndex: selectedItemIndex, focusOnEmptyStateButton: focusOnEmptyStateButton, focusedItemIndex: focusedItemIndex, setFocusedItemIndex: setFocusedItemIndex, focusedCategoryIndex: focusedCategoryIndex, setFocusedCategoryIndex: setFocusedCategoryIndex, focusOnSearch: focusOnSearch, columnCount: columnCount, setColumnCount: setColumnCount, setFocusOnSearch: setFocusOnSearch, onKeyPress: onItemsEnterTabKeyPress, onKeyDown: onKeyDown, onViewMore: onViewMore, focusOnViewMore: focusOnViewMore, cache: cache })) : (0, _react2.jsx)(DesktopBrowser // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading , (0, _extends2.default)({}, props, { selectedItemIndex: selectedItemIndex, focusOnEmptyStateButton: focusOnEmptyStateButton, focusedItemIndex: focusedItemIndex, setFocusedItemIndex: setFocusedItemIndex, focusOnSearch: focusOnSearch, setColumnCount: setColumnCount, columnCount: columnCount, setFocusOnSearch: setFocusOnSearch, onKeyPress: onItemsEnterTabKeyPress, onKeyDown: onKeyDown, focusedCategoryIndex: focusedCategoryIndex, setFocusedCategoryIndex: setFocusedCategoryIndex, selectedCategoryIndex: selectedCategoryIndex, onSelectCategory: onSelectCategoryCB, cache: cache }))); if ((0, _expValEquals.expValEquals)('editor_a11y__enghealth-46814_fy26', 'isEnabled', true)) { return (0, _react2.jsx)("div", { css: wrapper, "data-testid": "element-browser", id: _constants.ELEMENT_BROWSER_ID, role: "none", onKeyUp: canFocusSearch ? undefined : handleKeyPress, onClick: canFocusSearch ? undefined : handleClick }, browserContent); } return ( // eslint-disable-next-line @atlassian/a11y/interactive-element-not-keyboard-focusable (0, _react2.jsx)("div", { css: wrapper, "data-testid": "element-browser", id: _constants.ELEMENT_BROWSER_ID, onKeyUp: canFocusSearch ? undefined : handleKeyPress, onClick: canFocusSearch ? undefined : handleClick }, browserContent) ); } function MobileBrowser(_ref) { var showCategories = _ref.showCategories, showSearch = _ref.showSearch, onSearch = _ref.onSearch, mode = _ref.mode, categories = _ref.categories, onSelectCategory = _ref.onSelectCategory, items = _ref.items, onInsertItem = _ref.onInsertItem, selectedCategory = _ref.selectedCategory, selectedItemIndex = _ref.selectedItemIndex, focusedItemIndex = _ref.focusedItemIndex, setFocusedItemIndex = _ref.setFocusedItemIndex, focusedCategoryIndex = _ref.focusedCategoryIndex, setFocusedCategoryIndex = _ref.setFocusedCategoryIndex, focusOnSearch = _ref.focusOnSearch, focusOnViewMore = _ref.focusOnViewMore, columnCount = _ref.columnCount, setColumnCount = _ref.setColumnCount, setFocusOnSearch = _ref.setFocusOnSearch, onKeyPress = _ref.onKeyPress, onKeyDown = _ref.onKeyDown, searchTerm = _ref.searchTerm, createAnalyticsEvent = _ref.createAnalyticsEvent, emptyStateHandler = _ref.emptyStateHandler, onViewMore = _ref.onViewMore, cache = _ref.cache, _ref$focusOnEmptyStat = _ref.focusOnEmptyStateButton, focusOnEmptyStateButton = _ref$focusOnEmptyStat === void 0 ? false : _ref$focusOnEmptyStat; return (0, _react2.jsx)("div", { css: mobileElementBrowserContainer, role: (0, _expValEquals.expValEquals)('editor_a11y__enghealth-46814_fy26', 'isEnabled', true) ? 'none' : undefined, onKeyDown: onKeyDown, "data-testid": "mobile__element-browser" }, (0, _react2.jsx)("div", { css: showCategories ? [mobileSideBar, mobileSideBarShowCategories] : mobileSideBar }, showSearch && (0, _react2.jsx)(_ElementSearch.default, { onSearch: onSearch, onKeyDown: onKeyPress, mode: mode, focus: focusOnSearch, onClick: setFocusOnSearch, searchTerm: searchTerm, items: items, selectedItemIndex: selectedItemIndex, ariaControlsId: (0, _expValEquals.expValEquals)('platform_editor_august_a11y', 'isEnabled', true) ? _constants.ELEMENT_BROWSER_LIST_ID : undefined }), showCategories && (0, _react2.jsx)("nav", { css: mobileCategoryListWrapper, tabIndex: -1 }, (0, _react2.jsx)(_CategoryList.default, { categories: categories, onSelectCategory: onSelectCategory, selectedCategory: selectedCategory, focusedCategoryIndex: focusedCategoryIndex, setFocusedCategoryIndex: setFocusedCategoryIndex, setFocusedItemIndex: setFocusedItemIndex, setFocusOnSearch: setFocusOnSearch }))), (0, _react2.jsx)("div", { css: mobileMainContent, id: (0, _expValEquals.expValEquals)('platform_editor_august_a11y', 'isEnabled', true) ? _constants.ELEMENT_BROWSER_LIST_ID : undefined }, (0, _react2.jsx)(_ElementList.default, { items: items, mode: mode, onInsertItem: onInsertItem, selectedItemIndex: selectedItemIndex, focusedItemIndex: focusedItemIndex, focusOnEmptyStateButton: focusOnEmptyStateButton, setFocusedItemIndex: setFocusedItemIndex, columnCount: columnCount, setColumnCount: setColumnCount, createAnalyticsEvent: createAnalyticsEvent, emptyStateHandler: emptyStateHandler, selectedCategory: selectedCategory, searchTerm: searchTerm, cache: cache, hasTabListContext: false })), onViewMore && (0, _react2.jsx)(_ViewMore.ViewMore, { onViewMore: onViewMore, focus: focusOnViewMore })); } function DesktopBrowser(_ref2) { var showCategories = _ref2.showCategories, showSearch = _ref2.showSearch, onSearch = _ref2.onSearch, mode = _ref2.mode, categories = _ref2.categories, onSelectCategory = _ref2.onSelectCategory, items = _ref2.items, onInsertItem = _ref2.onInsertItem, selectedCategory = _ref2.selectedCategory, selectedItemIndex = _ref2.selectedItemIndex, focusedItemIndex = _ref2.focusedItemIndex, setFocusedItemIndex = _ref2.setFocusedItemIndex, focusedCategoryIndex = _ref2.focusedCategoryIndex, setFocusedCategoryIndex = _ref2.setFocusedCategoryIndex, selectedCategoryIndex = _ref2.selectedCategoryIndex, focusOnSearch = _ref2.focusOnSearch, columnCount = _ref2.columnCount, setColumnCount = _ref2.setColumnCount, setFocusOnSearch = _ref2.setFocusOnSearch, onKeyPress = _ref2.onKeyPress, onKeyDown = _ref2.onKeyDown, searchTerm = _ref2.searchTerm, createAnalyticsEvent = _ref2.createAnalyticsEvent, emptyStateHandler = _ref2.emptyStateHandler, cache = _ref2.cache, _ref2$focusOnEmptySta = _ref2.focusOnEmptyStateButton, focusOnEmptyStateButton = _ref2$focusOnEmptySta === void 0 ? false : _ref2$focusOnEmptySta; return (0, _react2.jsx)("div", { css: elementBrowserContainer, "data-testid": "desktop__element-browser" }, showCategories && (0, _react2.jsx)("div", { css: showCategories ? sideBarShowCategories : sideBar }, (0, _react2.jsx)("div", { css: sidebarHeading, "data-testid": "sidebar-heading", id: "sidebar-heading" }, (0, _react2.jsx)(_reactIntl.FormattedMessage, { id: "fabric.editor.elementbrowser.sidebar.heading", defaultMessage: "Browse", description: "Sidebar heading" })), (0, _expValEquals.expValEquals)('editor_a11y__enghealth-46814_fy26', 'isEnabled', true) ? (0, _react2.jsx)("div", { role: "tablist", "aria-labelledby": "sidebar-heading", css: categoryListWrapper }, (0, _react2.jsx)(_CategoryList.default, { categories: categories, onSelectCategory: onSelectCategory, selectedCategory: selectedCategory, createAnalyticsEvent: createAnalyticsEvent, focusedCategoryIndex: focusedCategoryIndex, setFocusedCategoryIndex: setFocusedCategoryIndex, setFocusedItemIndex: setFocusedItemIndex, setFocusOnSearch: setFocusOnSearch })) : // eslint-disable-next-line @atlassian/a11y/no-noninteractive-element-to-interactive-role (0, _react2.jsx)("nav", { role: "tablist", "aria-labelledby": "sidebar-heading", css: categoryListWrapper }, (0, _react2.jsx)(_CategoryList.default, { categories: categories, onSelectCategory: onSelectCategory, selectedCategory: selectedCategory, createAnalyticsEvent: createAnalyticsEvent, focusedCategoryIndex: focusedCategoryIndex, setFocusedCategoryIndex: setFocusedCategoryIndex, setFocusedItemIndex: setFocusedItemIndex, setFocusOnSearch: setFocusOnSearch }))), (0, _react2.jsx)("div", { css: mainContent, role: (0, _expValEquals.expValEquals)('editor_a11y__enghealth-46814_fy26', 'isEnabled', true) ? 'none' : undefined, onKeyDown: onKeyDown, "data-testid": "main-content" }, showSearch && // eslint-disable-next-line (0, _react2.jsx)("div", { css: searchContainer }, (0, _react2.jsx)(_ElementSearch.default, { onSearch: onSearch, onKeyDown: onKeyPress, mode: mode, focus: focusOnSearch, onClick: setFocusOnSearch, searchTerm: searchTerm, items: items, selectedItemIndex: selectedItemIndex, ariaControlsId: selectedCategory ? "browse-category-".concat(selectedCategory, "-tab") : 'browse-category-tab' })), (0, _react2.jsx)(_ElementList.default, { items: items, mode: mode, onInsertItem: onInsertItem, selectedItemIndex: selectedItemIndex, focusedItemIndex: focusedItemIndex, focusOnEmptyStateButton: focusOnEmptyStateButton, setFocusedItemIndex: setFocusedItemIndex, columnCount: columnCount, setColumnCount: setColumnCount, createAnalyticsEvent: createAnalyticsEvent, emptyStateHandler: emptyStateHandler, selectedCategory: selectedCategory, selectedCategoryIndex: selectedCategoryIndex, searchTerm: searchTerm, setFocusedCategoryIndex: showCategories ? setFocusedCategoryIndex : undefined, cache: cache, hasTabListContext: showCategories }))); } var MemoizedElementBrowser = /*#__PURE__*/(0, _react.memo)((0, _withAnalyticsContext.default)({ source: 'ElementBrowser' })((0, _withAnalyticsEvents.default)()(StatelessElementBrowser))); var _default = exports.default = MemoizedElementBrowser;