@wordpress/block-editor
Version:
164 lines (163 loc) • 4.84 kB
JavaScript
// 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