UNPKG

@wordpress/block-editor

Version:
343 lines (341 loc) 12.1 kB
/** * External dependencies */ import { View, Platform, Pressable } from 'react-native'; /** * WordPress dependencies */ import { useRef, useState, useCallback } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; import { KeyboardAwareFlatList, WIDE_ALIGNMENTS, alignmentHelpers } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import styles from './style.scss'; import BlockListAppender from '../block-list-appender'; import BlockListItem from './block-list-item'; import BlockListItemCell from './block-list-item-cell'; import { BlockListProvider, DEFAULT_BLOCK_LIST_CONTEXT } from './block-list-context'; import { BlockDraggableWrapper } from '../block-draggable'; import { useEditorWrapperStyles } from '../../hooks/use-editor-wrapper-styles'; import { store as blockEditorStore } from '../../store'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; const identity = x => x; const stylesMemo = {}; const getStyles = (isStackedHorizontally, horizontalAlignment) => { const styleName = `${isStackedHorizontally}-${horizontalAlignment}`; if (stylesMemo[styleName]) { return stylesMemo[styleName]; } const computedStyles = [isStackedHorizontally && styles.horizontal, horizontalAlignment && styles[`is-aligned-${horizontalAlignment}`], styles.overflowVisible]; stylesMemo[styleName] = computedStyles; return computedStyles; }; export default function BlockList({ blockWidth: initialBlockWidth, contentResizeMode, contentStyle, filterInnerBlocks, gridProperties, header, horizontal, horizontalAlignment, marginHorizontal = styles.defaultBlock.marginLeft, marginVertical = styles.defaultBlock.marginTop, onAddBlock, onDeleteBlock, orientation, parentWidth, renderAppender, renderFooterAppender, rootClientId, withFooter = true }) { const { blockClientIds, blockCount, blockInsertionPointIsVisible, isReadOnly, isRootList, isFloatingToolbarVisible, isStackedHorizontally, maxWidth, isRTL } = useSelect(select => { const { getBlockCount, getBlockHierarchyRootClientId, getBlockOrder, getSelectedBlockClientId, isBlockInsertionPointVisible, getSettings } = select(blockEditorStore); const selectedBlockClientId = getSelectedBlockClientId(); const rootBlockId = getBlockHierarchyRootClientId(selectedBlockClientId); let blockOrder = getBlockOrder(rootClientId); // Display only block which fulfill the condition in passed `filterInnerBlocks` function. if (filterInnerBlocks) { blockOrder = filterInnerBlocks(blockOrder); } const { isRTL: isRTLSetting, maxWidth: maxWidthSetting, readOnly } = getSettings(); return { blockClientIds: blockOrder, blockCount: getBlockCount(), blockInsertionPointIsVisible: Platform.OS === 'ios' && isBlockInsertionPointVisible(), isReadOnly: readOnly, isRootList: rootClientId === undefined, isFloatingToolbarVisible: !!selectedBlockClientId && !!getBlockCount(rootBlockId), isStackedHorizontally: orientation === 'horizontal', maxWidth: maxWidthSetting, isRTL: isRTLSetting }; }, [filterInnerBlocks, orientation, rootClientId]); const { insertBlock, clearSelectedBlock } = useDispatch(blockEditorStore); const extraData = useRef({ parentWidth, renderFooterAppender, renderAppender, onDeleteBlock, contentStyle }); const [blockWidth, setBlockWidth] = useState(initialBlockWidth || 0); const addBlockToEndOfPost = newBlock => { insertBlock(newBlock, blockCount); }; const scrollRef = useRef(null); const shouldFlatListPreventAutomaticScroll = () => blockInsertionPointIsVisible; const shouldShowInnerBlockAppender = () => renderAppender && blockClientIds.length > 0; const getExtraData = () => { if (extraData.current.parentWidth !== parentWidth || extraData.current.renderFooterAppender !== renderFooterAppender || extraData.current.onDeleteBlock !== onDeleteBlock || extraData.current.contentStyle !== contentStyle || extraData.current.renderAppender !== renderAppender || extraData.current.blockWidth !== blockWidth || extraData.current.gridProperties !== gridProperties) { extraData.current = { parentWidth, renderFooterAppender, onDeleteBlock, contentStyle, renderAppender, blockWidth, gridProperties }; } return extraData.current; }; const onLayout = ({ nativeEvent }) => { const { layout } = nativeEvent; const layoutWidth = Math.floor(layout.width); if (isRootList && blockWidth !== layoutWidth) { setBlockWidth(Math.min(layoutWidth, maxWidth)); } else if (!isRootList && !blockWidth) { setBlockWidth(Math.min(layoutWidth, maxWidth)); } }; const renderItem = ({ item: clientId, index }) => { // Extracting the grid item properties here to avoid // re-renders in the blockListItem component. const isGridItem = !!gridProperties; const gridItemProps = gridProperties && { numOfColumns: gridProperties.numColumns, tileCount: blockClientIds.length, tileIndex: blockClientIds.indexOf(clientId) }; return /*#__PURE__*/_jsx(BlockListItem, { index: index, isStackedHorizontally: isStackedHorizontally, rootClientId: rootClientId, clientId: clientId, parentWidth: parentWidth, contentResizeMode: contentResizeMode, contentStyle: contentStyle, onAddBlock: onAddBlock, marginVertical: marginVertical, marginHorizontal: marginHorizontal, onDeleteBlock: onDeleteBlock, shouldShowInnerBlockAppender: shouldShowInnerBlockAppender, blockWidth: blockWidth, isGridItem: isGridItem, ...gridItemProps }); }; const { blockToolbar, floatingToolbar } = styles; const containerStyle = { flex: isRootList ? 1 : 0, // We set negative margin in the parent to remove the edge spacing between parent block and child block in ineer blocks. marginVertical: isRootList ? 0 : -marginVertical, marginHorizontal: isRootList ? 0 : -marginHorizontal }; const isContentStretch = contentResizeMode === 'stretch'; const isMultiBlocks = blockClientIds.length > 1; const { isWider } = alignmentHelpers; const extraScrollHeight = blockToolbar.height + (isFloatingToolbarVisible ? floatingToolbar.height : 0); return /*#__PURE__*/_jsxs(View, { style: containerStyle, onAccessibilityEscape: clearSelectedBlock, onLayout: onLayout, testID: "block-list-wrapper", children: [isRootList ? /*#__PURE__*/_jsx(BlockListProvider, { value: { ...DEFAULT_BLOCK_LIST_CONTEXT, scrollRef: scrollRef.current }, children: /*#__PURE__*/_jsx(BlockDraggableWrapper, { isRTL: isRTL, children: ({ onScroll }) => /*#__PURE__*/_jsx(KeyboardAwareFlatList, { accessibilityLabel: "block-list", ref: scrollRef, extraScrollHeight: extraScrollHeight, keyboardShouldPersistTaps: "always", extraData: getExtraData(), scrollEnabled: isRootList, contentContainerStyle: [horizontal && styles.horizontalContentContainer, isWider(blockWidth, 'medium') && (isContentStretch && isMultiBlocks ? styles.horizontalContentContainerStretch : styles.horizontalContentContainerCenter)], data: blockClientIds, keyExtractor: identity, renderItem: renderItem, CellRendererComponent: BlockListItemCell, shouldPreventAutomaticScroll: shouldFlatListPreventAutomaticScroll, ListHeaderComponent: header, ListEmptyComponent: !isReadOnly && /*#__PURE__*/_jsx(EmptyList, { orientation: orientation, rootClientId: rootClientId, renderAppender: renderAppender, renderFooterAppender: renderFooterAppender }), ListFooterComponent: /*#__PURE__*/_jsx(Footer, { addBlockToEndOfPost: addBlockToEndOfPost, isReadOnly: isReadOnly, renderFooterAppender: renderFooterAppender, withFooter: withFooter }), onScroll: onScroll }) }) }) : /*#__PURE__*/_jsx(_Fragment, { children: blockClientIds.length > 0 ? /*#__PURE__*/_jsx(View, { style: [{ flex: 0 }, styles.overflowVisible], children: /*#__PURE__*/_jsxs(View, { style: [...getStyles(isStackedHorizontally, horizontalAlignment), horizontal && styles.horizontalContentContainer], children: [blockClientIds.map((currentClientId, index) => { return /*#__PURE__*/_jsx(View, { children: renderItem({ item: currentClientId, index }) }, currentClientId); }), /*#__PURE__*/_jsx(Footer, { addBlockToEndOfPost: addBlockToEndOfPost, isReadOnly: isReadOnly, renderFooterAppender: renderFooterAppender, withFooter: withFooter })] }) }) : /*#__PURE__*/_jsx(EmptyList, { orientation: orientation, rootClientId: rootClientId, renderAppender: renderAppender, renderFooterAppender: renderFooterAppender }) }), shouldShowInnerBlockAppender() && /*#__PURE__*/_jsx(View, { style: { marginHorizontal: marginHorizontal - styles.innerAppender.marginLeft }, children: /*#__PURE__*/_jsx(BlockListAppender, { rootClientId: rootClientId, renderAppender: renderAppender, showSeparator: true }) })] }); } function Footer({ addBlockToEndOfPost, isReadOnly, renderFooterAppender, withFooter }) { const onAddParagraphBlock = useCallback(() => { const paragraphBlock = createBlock('core/paragraph'); addBlockToEndOfPost(paragraphBlock); }, [addBlockToEndOfPost]); if (!isReadOnly && withFooter) { return /*#__PURE__*/_jsx(Pressable, { accessibilityLabel: __('Add paragraph block'), testID: __('Add paragraph block'), onPress: onAddParagraphBlock, children: /*#__PURE__*/_jsx(View, { style: styles.blockListFooter }) }); } else if (renderFooterAppender) { return /*#__PURE__*/_jsx(View, { children: renderFooterAppender() }); } return null; } function EmptyList({ orientation, renderAppender, renderFooterAppender, rootClientId }) { const { shouldShowInsertionPoint } = useSelect(select => { const { getBlockOrder, getBlockInsertionPoint, isBlockInsertionPointVisible } = select(blockEditorStore); const isStackedHorizontally = orientation === 'horizontal'; const blockClientIds = getBlockOrder(rootClientId); const insertionPoint = getBlockInsertionPoint(); const blockInsertionPointIsVisible = isBlockInsertionPointVisible(); return { shouldShowInsertionPoint: !isStackedHorizontally && blockInsertionPointIsVisible && insertionPoint.rootClientId === rootClientId && ( // If list is empty, show the insertion point (via the default appender) blockClientIds.length === 0 || // Or if the insertion point is right before the denoted block. !blockClientIds[insertionPoint.index]) }; }); const align = renderAppender ? WIDE_ALIGNMENTS.alignments.full : undefined; const [wrapperStyles] = useEditorWrapperStyles({ align }); if (renderFooterAppender || renderAppender === false) { return null; } const containerStyles = [styles.defaultAppender, wrapperStyles]; return /*#__PURE__*/_jsx(View, { style: containerStyles, children: /*#__PURE__*/_jsx(BlockListAppender, { rootClientId: rootClientId, renderAppender: renderAppender, showSeparator: shouldShowInsertionPoint }) }); } //# sourceMappingURL=index.native.js.map