UNPKG

@wordpress/block-editor

Version:
164 lines (163 loc) 4.84 kB
// packages/block-editor/src/components/use-paste-styles/index.js import { useCallback } from "@wordpress/element"; import { getBlockType, parse } from "@wordpress/blocks"; import { useDispatch, useRegistry } from "@wordpress/data"; import { store as noticesStore } from "@wordpress/notices"; import { __, sprintf } from "@wordpress/i18n"; import { store as blockEditorStore } from "../../store"; import { hasAlignSupport, hasBorderSupport, hasBackgroundColorSupport, hasTextAlignSupport, hasTextColorSupport, hasGradientSupport, hasCustomClassNameSupport, hasFontFamilySupport, hasFontSizeSupport, hasLayoutSupport, hasStyleSupport } from "../../hooks/supports"; function hasSerializedBlocks(text) { try { const blocks = parse(text, { __unstableSkipMigrationLogs: true, __unstableSkipAutop: true }); if (blocks.length === 1 && blocks[0].name === "core/freeform") { return false; } return true; } catch (err) { return false; } } var STYLE_ATTRIBUTES = { align: hasAlignSupport, borderColor: (nameOrType) => hasBorderSupport(nameOrType, "color"), backgroundColor: hasBackgroundColorSupport, textAlign: hasTextAlignSupport, textColor: hasTextColorSupport, gradient: hasGradientSupport, className: hasCustomClassNameSupport, fontFamily: hasFontFamilySupport, fontSize: hasFontSizeSupport, layout: hasLayoutSupport, style: hasStyleSupport }; function getStyleAttributes(sourceBlock, targetBlock) { return Object.entries(STYLE_ATTRIBUTES).reduce( (attributes, [attributeKey, hasSupport]) => { if (hasSupport(sourceBlock.name) && hasSupport(targetBlock.name)) { attributes[attributeKey] = sourceBlock.attributes[attributeKey]; } return attributes; }, {} ); } function recursivelyUpdateBlockAttributes(targetBlocks, sourceBlocks, updateBlockAttributes) { for (let index = 0; index < Math.min(sourceBlocks.length, targetBlocks.length); index += 1) { updateBlockAttributes( targetBlocks[index].clientId, getStyleAttributes(sourceBlocks[index], targetBlocks[index]) ); recursivelyUpdateBlockAttributes( targetBlocks[index].innerBlocks, sourceBlocks[index].innerBlocks, updateBlockAttributes ); } } function usePasteStyles() { const registry = useRegistry(); const { updateBlockAttributes } = useDispatch(blockEditorStore); const { createSuccessNotice, createWarningNotice, createErrorNotice } = useDispatch(noticesStore); return useCallback( async (targetBlocks) => { let html = ""; try { if (!window.navigator.clipboard) { createErrorNotice( __( "Unable to paste styles. This feature is only available on secure (https) sites in supporting browsers." ), { type: "snackbar" } ); return; } html = await window.navigator.clipboard.readText(); } catch (error) { createErrorNotice( __( "Unable to paste styles. Please allow browser clipboard permissions before continuing." ), { type: "snackbar" } ); return; } if (!html || !hasSerializedBlocks(html)) { createWarningNotice( __( "Unable to paste styles. Block styles couldn't be found within the copied content." ), { type: "snackbar" } ); return; } const copiedBlocks = parse(html); if (copiedBlocks.length === 1) { registry.batch(() => { recursivelyUpdateBlockAttributes( targetBlocks, targetBlocks.map(() => copiedBlocks[0]), updateBlockAttributes ); }); } else { registry.batch(() => { recursivelyUpdateBlockAttributes( targetBlocks, copiedBlocks, updateBlockAttributes ); }); } if (targetBlocks.length === 1) { const title = getBlockType(targetBlocks[0].name)?.title; createSuccessNotice( sprintf( // Translators: %s: Name of the block being pasted, e.g. "Paragraph". __("Pasted styles to %s."), title ), { type: "snackbar" } ); } else { createSuccessNotice( sprintf( // Translators: %d: The number of the blocks. __("Pasted styles to %d blocks."), targetBlocks.length ), { type: "snackbar" } ); } }, [ registry.batch, updateBlockAttributes, createSuccessNotice, createWarningNotice, createErrorNotice ] ); } export { usePasteStyles as default }; //# sourceMappingURL=index.js.map