UNPKG

@gechiui/block-editor

Version:
188 lines (175 loc) 6.01 kB
import { createElement, Fragment } from "@gechiui/element"; /** * External dependencies */ import { AccessibilityInfo, TouchableHighlight, Platform } from 'react-native'; /** * GeChiUI dependencies */ import { useEffect, useState, useCallback } from '@gechiui/element'; import { useSelect, useDispatch } from '@gechiui/data'; import { createBlock } from '@gechiui/blocks'; import { BottomSheet, BottomSheetConsumer, SearchControl } from '@gechiui/components'; /** * Internal dependencies */ import InserterSearchResults from './search-results'; import { store as blockEditorStore } from '../../store'; import InserterTabs from './tabs'; import styles from './style.scss'; import { filterInserterItems } from './utils'; const MIN_ITEMS_FOR_SEARCH = 2; function InserterMenu(_ref) { let { onSelect, onDismiss, rootClientId, clientId, isAppender, shouldReplaceBlock, insertionIndex } = _ref; const [filterValue, setFilterValue] = useState(''); const [showTabs, setShowTabs] = useState(true); const [tabIndex, setTabIndex] = useState(0); const isIOS = Platform.OS === 'ios'; const { showInsertionPoint, hideInsertionPoint, clearSelectedBlock, insertBlock, removeBlock, resetBlocks, insertDefaultBlock } = useDispatch(blockEditorStore); const { items, destinationRootClientId, showReusableBlocks } = useSelect(select => { const { getInserterItems, getBlockRootClientId, getBlockSelectionEnd } = select(blockEditorStore); let targetRootClientId = rootClientId; if (!targetRootClientId && !clientId && !isAppender) { const end = getBlockSelectionEnd(); if (end) { targetRootClientId = getBlockRootClientId(end) || undefined; } } const allItems = getInserterItems(targetRootClientId); const reusableBlockItems = filterInserterItems(allItems, { onlyReusable: true }); return { items: allItems, destinationRootClientId: targetRootClientId, showReusableBlocks: !!reusableBlockItems.length }; }); const { getBlockOrder, getBlockCount } = useSelect(blockEditorStore); useEffect(() => { // Show/Hide insertion point on Mount/Dismount if (shouldReplaceBlock) { const count = getBlockCount(); // Check if there is a rootClientId because that means it is a nested replaceable block // and we don't want to clear/reset all blocks. if (count === 1 && !rootClientId) { // Removing the last block is not possilble with `removeBlock` action. // It always inserts a default block if the last of the blocks have been removed. clearSelectedBlock(); resetBlocks([]); } else { const blockToReplace = getBlockOrder(destinationRootClientId)[insertionIndex]; removeBlock(blockToReplace, false); } } showInsertionPoint(destinationRootClientId, insertionIndex); return hideInsertionPoint; }, []); const onClose = useCallback(() => { // if should replace but didn't insert any block // re-insert default block if (shouldReplaceBlock) { insertDefaultBlock({}, destinationRootClientId, insertionIndex); } onDismiss(); }, [shouldReplaceBlock, destinationRootClientId, insertionIndex]); const onInsert = useCallback(item => { const { name, initialAttributes, innerBlocks } = item; const newBlock = createBlock(name, initialAttributes, innerBlocks); insertBlock(newBlock, insertionIndex, destinationRootClientId, true, { source: 'inserter_menu' }); }, [insertBlock, destinationRootClientId, insertionIndex]); const onSelectItem = useCallback(item => { // Avoid a focus loop, see https://github.com/GeChiUI/gutenberg/issues/30562 if (Platform.OS === 'ios') { AccessibilityInfo.isScreenReaderEnabled().then(enabled => { // In testing, the bug focus loop needed a longer timeout when VoiceOver was enabled const timeout = enabled ? 200 : 100; // eslint-disable-next-line @gechiui/react-no-unsafe-timeout setTimeout(() => { onInsert(item); }, timeout); }); } else { onInsert(item); } onSelect(item); }, [onInsert, onSelect]); const onChangeSearch = useCallback(value => { setFilterValue(value); }, [setFilterValue]); const onKeyboardShow = useCallback(() => setShowTabs(false), [setShowTabs]); const onKeyboardHide = useCallback(() => setShowTabs(true), [setShowTabs]); const showSearchForm = items.length > MIN_ITEMS_FOR_SEARCH; const isFullScreen = !isIOS && showSearchForm; return createElement(BottomSheet, { isVisible: true, onClose: onClose, onKeyboardShow: onKeyboardShow, onKeyboardHide: onKeyboardHide, header: createElement(Fragment, null, showSearchForm && createElement(SearchControl, { onChange: onChangeSearch, value: filterValue }), showTabs && !filterValue && createElement(InserterTabs.Control, { onChangeTab: setTabIndex, showReusableBlocks: showReusableBlocks })), hasNavigation: true, setMinHeightToMaxHeight: true, contentStyle: styles['inserter-menu__list'], isFullScreen: isFullScreen, allowDragIndicator: true }, createElement(BottomSheetConsumer, null, _ref2 => { let { listProps } = _ref2; return createElement(TouchableHighlight, { accessible: false, style: styles['inserter-menu__list-wrapper'] }, !showTabs || filterValue ? createElement(InserterSearchResults, { rootClientId: rootClientId, filterValue: filterValue, onSelect: onSelectItem, listProps: listProps, isFullScreen: isFullScreen }) : createElement(InserterTabs, { rootClientId: rootClientId, listProps: listProps, tabIndex: tabIndex, onSelect: onSelectItem, showReusableBlocks: showReusableBlocks })); })); } export default InserterMenu; //# sourceMappingURL=menu.native.js.map