UNPKG

@atlaskit/editor-plugin-insert-block

Version:

Insert block plugin for @atlaskit/editor-core

273 lines (272 loc) • 10.9 kB
/* RegisteredInsertMenuList.tsx generated by @compiled/babel-plugin v3.0.2 */ import _extends from "@babel/runtime/helpers/extends"; import "./RegisteredInsertMenuList.compiled.css"; import { ax, ix } from "@compiled/react/runtime"; import React, { useCallback, useLayoutEffect, useMemo, useRef } from 'react'; import { CellMeasurer, CellMeasurerCache } from 'react-virtualized/dist/commonjs/CellMeasurer'; import { List } from 'react-virtualized/dist/commonjs/List'; import { QuickInsertEmptyState } from '@atlaskit/editor-common/quick-insert/empty-state'; import { getQuickInsertMenuRows } from '@atlaskit/editor-common/quick-insert/registered-menu-model'; import { useMenuListHeight } from '@atlaskit/editor-common/quick-insert/use-menu-list-height'; // eslint-disable-next-line @atlaskit/platform/no-barrel-entry-imports import { Box } from '@atlaskit/primitives/compiled/box'; import { RegisteredInsertMenuItem, RegisteredInsertMenuPreviewContext } from './RegisteredInsertMenuItem'; const ESTIMATED_ROW_HEIGHT = 44; // 44px item + 1px separator. const MENU_FOOTER_HEIGHT = 45; const MENU_SEARCH_HEIGHT = 64; const LIST_WIDTH = 350; const listAriaProps = { // @ts-expect-error react-virtualized forwards null to omit its grid-only default; its types exclude null. 'aria-readonly': null }; const styles = { content: "_1e0c1txw _2lx21bp4 _1tkeidpf", scrollable: "_16jlkb7n _1tkeidpf _18m91wug", footer: "_1o9zidpf", footerWithDivider: "_1i531l7x _15a5nqa1 _uwhke4h9 _1o9zidpf", externalControls: "_1i531l7x _15a5nqa1 _uwhke4h9 _1q51u2gc _85i5u2gc" }; const RegisteredInsertMenuItemRow = ({ editorView, id, isOffline, isSelected, itemIndex, menuOpenId, onClose, onItemFocus, onItemBlur, onItemHover, onItemLeave, registration, surfaceContext }) => { useLayoutEffect(() => () => onItemLeave(registration.key), [onItemLeave, registration.key]); const onBlur = useCallback(event => { if (!event.currentTarget.contains(event.relatedTarget)) { onItemBlur(registration.key); } }, [onItemBlur, registration.key]); return /*#__PURE__*/React.createElement("div", { onBlur: onBlur, onFocus: () => onItemFocus(itemIndex, registration.key), onMouseLeave: () => onItemLeave(registration.key), onMouseMove: () => onItemHover(itemIndex, registration.key) }, /*#__PURE__*/React.createElement(RegisteredInsertMenuItem, { editorView: editorView, id: id, isOffline: isOffline, isSelected: isSelected, menuOpenId: menuOpenId, onClose: onClose, registration: registration, surfaceContext: surfaceContext })); }; export const RegisteredInsertMenuList = ({ editorView, emptyStateHandler, isOffline, listId, listLabel, maxHeight, menuOpenId, model, onClose, onItemFocus, onItemBlur, query, onItemHover, onItemLeave, onItemVisibilityChange, onRenderedItemsChange, selectedItemIndex, surfaceContext, activePreviewItemKey }) => { var _model$root$component, _model$root; const Root = (_model$root$component = (_model$root = model.root) === null || _model$root === void 0 ? void 0 : _model$root.component) !== null && _model$root$component !== void 0 ? _model$root$component : React.Fragment; const listRef = useRef(null); const setListRef = useCallback(list => { listRef.current = list; }, []); const rows = useMemo(() => getQuickInsertMenuRows(model), [model]); const cache = useMemo(() => new CellMeasurerCache({ defaultHeight: ESTIMATED_ROW_HEIGHT, fixedWidth: true }), []); const itemIndexByRowIndex = useMemo(() => { const indexes = new Map(); let itemIndex = 0; rows.forEach((registration, rowIndex) => { if (registration.type === 'menu-item') { indexes.set(rowIndex, itemIndex++); } }); return indexes; }, [rows]); const selectedRowIndex = useMemo(() => { for (const [rowIndex, itemIndex] of itemIndexByRowIndex) { if (itemIndex === selectedItemIndex) { return rowIndex; } } return -1; }, [itemIndexByRowIndex, selectedItemIndex]); const rowKeySignature = useMemo(() => rows.map(({ key, type }) => `${type}:${key}`).join('\0'), [rows]); const { height: measuredHeight, updateHeight } = useMenuListHeight(cache, rows.length, rowKeySignature); useLayoutEffect(() => { var _listRef$current, _listRef$current2; cache.clearAll(); (_listRef$current = listRef.current) === null || _listRef$current === void 0 ? void 0 : _listRef$current.recomputeRowHeights(); (_listRef$current2 = listRef.current) === null || _listRef$current2 === void 0 ? void 0 : _listRef$current2.scrollToPosition(0); }, [cache, rowKeySignature]); const onRowsRendered = useCallback(({ overscanStartIndex, overscanStopIndex, startIndex, stopIndex }) => { var _indexes$, _indexes; if (activePreviewItemKey) { const previewRowIndex = rows.findIndex(({ key }) => key === activePreviewItemKey); if (previewRowIndex < startIndex || previewRowIndex > stopIndex) { onItemVisibilityChange(activePreviewItemKey, false); } } updateHeight(); const indexes = [...itemIndexByRowIndex].filter(([rowIndex]) => rowIndex >= overscanStartIndex && rowIndex <= overscanStopIndex).map(([, itemIndex]) => itemIndex); onRenderedItemsChange({ startIndex: (_indexes$ = indexes[0]) !== null && _indexes$ !== void 0 ? _indexes$ : -1, stopIndex: (_indexes = indexes[indexes.length - 1]) !== null && _indexes !== void 0 ? _indexes : -1 }); }, [activePreviewItemKey, itemIndexByRowIndex, onItemVisibilityChange, onRenderedItemsChange, rows, updateHeight]); const onScrollableContentScroll = useCallback(event => { if (event.target === event.currentTarget && activePreviewItemKey) { onItemVisibilityChange(activePreviewItemKey, false); } }, [activePreviewItemKey, onItemVisibilityChange]); const renderRow = useCallback(({ index, key, parent, style }) => { var _registration$compone; const registration = rows[index]; if (!registration) { return null; } const itemIndex = itemIndexByRowIndex.get(index); const rowContent = registration.type === 'menu-section' ? ( /*#__PURE__*/React.createElement((_registration$compone = registration.component) !== null && _registration$compone !== void 0 ? _registration$compone : React.Fragment, null, null)) : /*#__PURE__*/React.createElement(RegisteredInsertMenuItemRow, { editorView: editorView, id: `${listId}-${itemIndex}`, isOffline: isOffline, isSelected: itemIndex === selectedItemIndex, itemIndex: itemIndex !== null && itemIndex !== void 0 ? itemIndex : 0, menuOpenId: menuOpenId, onClose: onClose, onItemFocus: onItemFocus, onItemBlur: onItemBlur, onItemHover: onItemHover, onItemLeave: onItemLeave, registration: registration, surfaceContext: surfaceContext }); return /*#__PURE__*/React.createElement(CellMeasurer, { key: key, cache: cache, parent: parent, columnIndex: 0, rowIndex: index }, ({ registerChild }) => /*#__PURE__*/React.createElement("div", { ref: element => registerChild === null || registerChild === void 0 ? void 0 : registerChild(element !== null && element !== void 0 ? element : undefined) // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop , style: style }, /*#__PURE__*/React.createElement(Box, { paddingBlockEnd: index === rows.length - 1 ? 'space.100' : undefined }, rowContent))); }, [cache, editorView, isOffline, itemIndexByRowIndex, listId, menuOpenId, onClose, onItemFocus, onItemBlur, onItemHover, onItemLeave, rows, selectedItemIndex, surfaceContext]); const footerItemIndex = itemIndexByRowIndex.size; const footerItemId = `${listId}-${footerItemIndex}`; const hasExternalControls = model.fallbackItems !== undefined && emptyStateHandler !== undefined; const hasNoSearchResults = query !== '' && rows.length === 0; const externalControls = hasExternalControls && emptyStateHandler ? emptyStateHandler({ mode: 'inline', searchTerm: query, showNoResultsMessage: false }) : null; const showFooterDivider = !hasNoSearchResults || Boolean(externalControls); const listMaxHeight = Math.max(0, maxHeight - MENU_SEARCH_HEIGHT - (model.footer ? MENU_FOOTER_HEIGHT : 0)); const contentStyle = { maxHeight: Math.max(0, maxHeight - MENU_SEARCH_HEIGHT) }; const onFooterItemHover = useCallback(() => onItemHover(footerItemIndex), [footerItemIndex, onItemHover]); const onFooterItemFocus = useCallback(() => onItemFocus(footerItemIndex), [footerItemIndex, onItemFocus]); const footer = model.footer ? /*#__PURE__*/React.createElement(Box, { testId: "registered-insert-menu-footer", xcss: showFooterDivider ? styles.footerWithDivider : styles.footer, onFocus: onFooterItemFocus, onMouseMove: onFooterItemHover }, /*#__PURE__*/React.createElement(RegisteredInsertMenuItem, { editorView: editorView, id: footerItemId, isOffline: isOffline, isSelected: footerItemIndex === selectedItemIndex, menuOpenId: menuOpenId, onClose: onClose, registration: model.footer, surfaceContext: surfaceContext })) : null; if (!model.root) { return null; } return /*#__PURE__*/React.createElement(Root, null, /*#__PURE__*/React.createElement(RegisteredInsertMenuPreviewContext.Provider, { value: activePreviewItemKey }, /*#__PURE__*/React.createElement(Box, { xcss: styles.content, style: contentStyle }, /*#__PURE__*/React.createElement(Box, { xcss: styles.scrollable, onScroll: onScrollableContentScroll }, /*#__PURE__*/React.createElement(Box, { "aria-label": listLabel, "aria-owns": model.footer ? footerItemId : undefined, id: listId, role: "listbox" }, rows.length > 0 && /*#__PURE__*/React.createElement(List // eslint-disable-next-line react/jsx-props-no-spreading -- Omits the library's grid-only ARIA default without declaring it on the group role. , _extends({}, listAriaProps, { tabIndex: null, containerRole: "presentation", height: Math.min(measuredHeight, listMaxHeight), overscanRowCount: 3, onRowsRendered: onRowsRendered, ref: setListRef, role: "group", rowCount: rows.length, rowHeight: cache.rowHeight, rowRenderer: renderRow, scrollToAlignment: "auto", scrollToIndex: selectedRowIndex, width: LIST_WIDTH }))), hasNoSearchResults && /*#__PURE__*/React.createElement(QuickInsertEmptyState, { mode: "inline", spacing: "compact" }), externalControls && /*#__PURE__*/React.createElement(Box, { testId: "registered-insert-menu-external-controls", xcss: styles.externalControls }, externalControls)), footer))); };