UNPKG

@wordpress/block-editor

Version:
338 lines (320 loc) 11.7 kB
import { createElement, Fragment } from "@wordpress/element"; /** * External dependencies */ import { Platform, findNodeHandle } from 'react-native'; import { partial, first, castArray, last, compact } from 'lodash'; /** * WordPress dependencies */ import { getClipboard, setClipboard, ToolbarButton, Picker } from '@wordpress/components'; import { getBlockType, getDefaultBlockName, serialize, rawHandler, createBlock, isUnmodifiedDefaultBlock, isReusableBlock } from '@wordpress/blocks'; import { __, sprintf } from '@wordpress/i18n'; import { withDispatch, withSelect } from '@wordpress/data'; import { withInstanceId, compose } from '@wordpress/compose'; import { moreHorizontalMobile } from '@wordpress/icons'; import { useRef, useState } from '@wordpress/element'; import { store as noticesStore } from '@wordpress/notices'; import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ import { getMoversSetup } from '../block-mover/mover-description'; import { store as blockEditorStore } from '../../store'; import BlockTransformationsMenu from '../block-switcher/block-transformations-menu'; const BlockActionsMenu = ({ // Select blockTitle, canInsertBlockType, getBlocksByClientId, isEmptyDefaultBlock, isFirst, isLast, isReusableBlockType, reusableBlock, rootClientId, selectedBlockClientId, selectedBlockPossibleTransformations, // Dispatch createSuccessNotice, convertToRegularBlocks, duplicateBlock, onMoveDown, onMoveUp, openGeneralSidebar, pasteBlock, removeBlocks, // Passed in anchorNodeRef, isStackedHorizontally, onDelete, wrapBlockMover, wrapBlockSettings }) => { const [clipboard, setCurrentClipboard] = useState(getClipboard()); const blockActionsMenuPickerRef = useRef(); const blockTransformationMenuPickerRef = useRef(); const moversOptions = { keys: ['icon', 'actionTitle'] }; const clipboardBlock = clipboard && rawHandler({ HTML: clipboard })[0]; const isPasteEnabled = clipboardBlock && canInsertBlockType(clipboardBlock.name, rootClientId); const { actionTitle: { backward: backwardButtonTitle, forward: forwardButtonTitle } } = getMoversSetup(isStackedHorizontally, moversOptions); const allOptions = { settings: { id: 'settingsOption', label: __('Block settings'), value: 'settingsOption', onSelect: openGeneralSidebar }, backwardButton: { id: 'backwardButtonOption', label: backwardButtonTitle, value: 'backwardButtonOption', disabled: isFirst, onSelect: onMoveUp }, forwardButton: { id: 'forwardButtonOption', label: forwardButtonTitle, value: 'forwardButtonOption', disabled: isLast, onSelect: onMoveDown }, delete: { id: 'deleteOption', label: __('Remove block'), value: 'deleteOption', separated: true, disabled: isEmptyDefaultBlock, onSelect: () => { onDelete(); createSuccessNotice( // translators: displayed right after the block is removed. __('Block removed')); } }, transformButton: { id: 'transformButtonOption', label: __('Transform block…'), value: 'transformButtonOption', onSelect: () => { if (blockTransformationMenuPickerRef.current) { blockTransformationMenuPickerRef.current.presentPicker(); } } }, copyButton: { id: 'copyButtonOption', label: __('Copy block'), value: 'copyButtonOption', onSelect: () => { const serializedBlock = serialize(getBlocksByClientId(selectedBlockClientId)); setCurrentClipboard(serializedBlock); setClipboard(serializedBlock); createSuccessNotice( // translators: displayed right after the block is copied. __('Block copied')); } }, cutButton: { id: 'cutButtonOption', label: __('Cut block'), value: 'cutButtonOption', onSelect: () => { setClipboard(serialize(getBlocksByClientId(selectedBlockClientId))); removeBlocks(selectedBlockClientId); createSuccessNotice( // translators: displayed right after the block is cut. __('Block cut')); } }, pasteButton: { id: 'pasteButtonOption', label: __('Paste block after'), value: 'pasteButtonOption', onSelect: () => { onPasteBlock(); createSuccessNotice( // translators: displayed right after the block is pasted. __('Block pasted')); } }, duplicateButton: { id: 'duplicateButtonOption', label: __('Duplicate block'), value: 'duplicateButtonOption', onSelect: () => { duplicateBlock(); createSuccessNotice( // translators: displayed right after the block is duplicated. __('Block duplicated')); } }, convertToRegularBlocks: { id: 'convertToRegularBlocksOption', label: __('Convert to regular blocks'), value: 'convertToRegularBlocksOption', onSelect: () => { var _reusableBlock$title; createSuccessNotice(sprintf( /* translators: %s: name of the reusable block */ __('%s converted to regular blocks'), (reusableBlock === null || reusableBlock === void 0 ? void 0 : (_reusableBlock$title = reusableBlock.title) === null || _reusableBlock$title === void 0 ? void 0 : _reusableBlock$title.raw) || blockTitle)); convertToRegularBlocks(); } } }; const options = compact([wrapBlockMover && allOptions.backwardButton, wrapBlockMover && allOptions.forwardButton, wrapBlockSettings && allOptions.settings, selectedBlockPossibleTransformations.length && allOptions.transformButton, allOptions.copyButton, allOptions.cutButton, isPasteEnabled && allOptions.pasteButton, allOptions.duplicateButton, isReusableBlockType && allOptions.convertToRegularBlocks, allOptions.delete]); function onPasteBlock() { if (!clipboard) { return; } pasteBlock(rawHandler({ HTML: clipboard })[0]); } function onPickerSelect(value) { const selectedItem = options.find(item => item.value === value); selectedItem.onSelect(); } function onPickerPresent() { if (blockActionsMenuPickerRef.current) { blockActionsMenuPickerRef.current.presentPicker(); } } const disabledButtonIndices = options.map((option, index) => option.disabled && index + 1).filter(Boolean); const accessibilityHint = Platform.OS === 'ios' ? __('Double tap to open Action Sheet with available options') : __('Double tap to open Bottom Sheet with available options'); const getAnchor = () => anchorNodeRef ? findNodeHandle(anchorNodeRef) : undefined; return createElement(Fragment, null, createElement(ToolbarButton, { title: __('Open Block Actions Menu'), onClick: onPickerPresent, icon: moreHorizontalMobile, extraProps: { hint: accessibilityHint } }), createElement(Picker, { ref: blockActionsMenuPickerRef, options: options, onChange: onPickerSelect, destructiveButtonIndex: options.length, disabledButtonIndices: disabledButtonIndices, hideCancelButton: Platform.OS !== 'ios', leftAlign: true, getAnchor: getAnchor // translators: %s: block title e.g: "Paragraph". , title: sprintf(__('%s block options'), blockTitle) }), createElement(BlockTransformationsMenu, { anchorNodeRef: anchorNodeRef, blockTitle: blockTitle, pickerRef: blockTransformationMenuPickerRef, possibleTransformations: selectedBlockPossibleTransformations, selectedBlock: getBlocksByClientId(selectedBlockClientId), selectedBlockClientId: selectedBlockClientId })); }; export default compose(withSelect((select, { clientIds }) => { const { getBlockIndex, getBlockRootClientId, getBlockOrder, getBlockName, getBlockTransformItems, getBlock, getBlocksByClientId, getSelectedBlockClientIds, canInsertBlockType } = select(blockEditorStore); const normalizedClientIds = castArray(clientIds); const block = getBlock(normalizedClientIds); const blockName = getBlockName(normalizedClientIds); const blockType = getBlockType(blockName); const blockTitle = blockType === null || blockType === void 0 ? void 0 : blockType.title; const firstClientId = first(normalizedClientIds); const rootClientId = getBlockRootClientId(firstClientId); const blockOrder = getBlockOrder(rootClientId); const firstIndex = getBlockIndex(firstClientId, rootClientId); const lastIndex = getBlockIndex(last(normalizedClientIds), rootClientId); const isDefaultBlock = blockName === getDefaultBlockName(); const isEmptyContent = (block === null || block === void 0 ? void 0 : block.attributes.content) === ''; const isExactlyOneBlock = blockOrder.length === 1; const isEmptyDefaultBlock = isExactlyOneBlock && isDefaultBlock && isEmptyContent; const selectedBlockClientId = first(getSelectedBlockClientIds()); const selectedBlock = selectedBlockClientId ? first(getBlocksByClientId(selectedBlockClientId)) : undefined; const selectedBlockPossibleTransformations = selectedBlock ? getBlockTransformItems([selectedBlock], rootClientId) : []; const isReusableBlockType = block ? isReusableBlock(block) : false; const reusableBlock = isReusableBlockType ? select(coreStore).getEntityRecord('postType', 'wp_block', block === null || block === void 0 ? void 0 : block.attributes.ref) : undefined; return { blockTitle, canInsertBlockType, currentIndex: firstIndex, getBlocksByClientId, isEmptyDefaultBlock, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, isReusableBlockType, reusableBlock, rootClientId, selectedBlockClientId, selectedBlockPossibleTransformations }; }), withDispatch((dispatch, { clientIds, rootClientId, currentIndex, selectedBlockClientId }, { select }) => { const { moveBlocksDown, moveBlocksUp, duplicateBlocks, removeBlocks, insertBlock, replaceBlocks, clearSelectedBlock } = dispatch(blockEditorStore); const { openGeneralSidebar } = dispatch('core/edit-post'); const { getBlockSelectionEnd, getBlock } = select(blockEditorStore); const { createSuccessNotice } = dispatch(noticesStore); const { __experimentalConvertBlockToStatic: convertBlockToStatic } = dispatch(reusableBlocksStore); return { createSuccessNotice, convertToRegularBlocks() { clearSelectedBlock(); // Convert action is executed at the end of the current JavaScript execution block // to prevent issues related to undo/redo actions. setImmediate(() => convertBlockToStatic(selectedBlockClientId)); }, duplicateBlock() { return duplicateBlocks(clientIds); }, onMoveDown: partial(moveBlocksDown, clientIds, rootClientId), onMoveUp: partial(moveBlocksUp, clientIds, rootClientId), openGeneralSidebar: () => openGeneralSidebar('edit-post/block'), pasteBlock: clipboardBlock => { const canReplaceBlock = isUnmodifiedDefaultBlock(getBlock(getBlockSelectionEnd())); if (!canReplaceBlock) { const insertedBlock = createBlock(clipboardBlock.name, clipboardBlock.attributes, clipboardBlock.innerBlocks); insertBlock(insertedBlock, currentIndex + 1, rootClientId); } else { replaceBlocks(clientIds, clipboardBlock); } }, removeBlocks }; }), withInstanceId)(BlockActionsMenu); //# sourceMappingURL=block-actions-menu.native.js.map