@wordpress/block-library
Version:
Block library for the WordPress editor.
179 lines (178 loc) • 6.25 kB
JavaScript
// packages/block-library/src/embed/util.js
import clsx from "clsx";
import memoize from "memize";
import { privateApis as componentsPrivateApis } from "@wordpress/components";
import { renderToString } from "@wordpress/element";
import {
createBlock,
getBlockType,
getBlockVariations
} from "@wordpress/blocks";
import metadata from "./block.json";
import { ASPECT_RATIOS, WP_EMBED_TYPE } from "./constants";
import { unlock } from "../lock-unlock";
import { jsx } from "react/jsx-runtime";
var { name: DEFAULT_EMBED_BLOCK } = metadata;
var { kebabCase } = unlock(componentsPrivateApis);
var getEmbedInfoByProvider = (provider) => getBlockVariations(DEFAULT_EMBED_BLOCK)?.find(
({ name }) => name === provider
);
var matchesPatterns = (url, patterns = []) => patterns.some((pattern) => url.match(pattern));
var findMoreSuitableBlock = (url) => getBlockVariations(DEFAULT_EMBED_BLOCK)?.find(
({ patterns }) => matchesPatterns(url, patterns)
);
var isFromWordPress = (html) => html && html.includes('class="wp-embedded-content"');
var getPhotoHtml = (photo) => {
const imageUrl = photo.url || photo.thumbnail_url;
const photoPreview = /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("img", { src: imageUrl, alt: photo.title, width: "100%" }) });
return renderToString(photoPreview);
};
var createUpgradedEmbedBlock = (props, attributesFromPreview = {}) => {
const { preview, attributes = {} } = props;
const { url, providerNameSlug, type, ...restAttributes } = attributes;
if (!url || !getBlockType(DEFAULT_EMBED_BLOCK)) {
return;
}
const matchedBlock = findMoreSuitableBlock(url);
const isCurrentBlockWP = providerNameSlug === "wordpress" || type === WP_EMBED_TYPE;
const shouldCreateNewBlock = !isCurrentBlockWP && matchedBlock && (matchedBlock.attributes.providerNameSlug !== providerNameSlug || !providerNameSlug);
if (shouldCreateNewBlock) {
return createBlock(DEFAULT_EMBED_BLOCK, {
url,
...restAttributes,
...matchedBlock.attributes
});
}
const wpVariation = getBlockVariations(DEFAULT_EMBED_BLOCK)?.find(
({ name }) => name === "wordpress"
);
if (!wpVariation || !preview || !isFromWordPress(preview.html) || isCurrentBlockWP) {
return;
}
return createBlock(DEFAULT_EMBED_BLOCK, {
url,
...wpVariation.attributes,
// By now we have the preview, but when the new block first renders, it
// won't have had all the attributes set, and so won't get the correct
// type and it won't render correctly. So, we pass through the current attributes
// here so that the initial render works when we switch to the WordPress
// block. This only affects the WordPress block because it can't be
// rendered in the usual Sandbox (it has a sandbox of its own) and it
// relies on the preview to set the correct render type.
...attributesFromPreview
});
};
var hasAspectRatioClass = (existingClassNames) => {
if (!existingClassNames) {
return false;
}
return ASPECT_RATIOS.some(
({ className }) => existingClassNames.includes(className)
);
};
var removeAspectRatioClasses = (existingClassNames) => {
if (!existingClassNames) {
return existingClassNames;
}
const aspectRatioClassNames = ASPECT_RATIOS.reduce(
(accumulator, { className }) => {
accumulator.push(className);
return accumulator;
},
["wp-has-aspect-ratio"]
);
let outputClassNames = existingClassNames;
for (const className of aspectRatioClassNames) {
outputClassNames = outputClassNames.replace(className, "");
}
return outputClassNames.trim();
};
function getClassNames(html, existingClassNames, allowResponsive = true) {
if (!allowResponsive) {
return removeAspectRatioClasses(existingClassNames);
}
const previewDocument = document.implementation.createHTMLDocument("");
previewDocument.body.innerHTML = html;
const iframe = previewDocument.body.querySelector("iframe");
if (iframe && iframe.height && iframe.width) {
const aspectRatio = (iframe.width / iframe.height).toFixed(2);
for (let ratioIndex = 0; ratioIndex < ASPECT_RATIOS.length; ratioIndex++) {
const potentialRatio = ASPECT_RATIOS[ratioIndex];
if (aspectRatio >= potentialRatio.ratio) {
const ratioDiff = aspectRatio - potentialRatio.ratio;
if (ratioDiff > 0.1) {
return removeAspectRatioClasses(existingClassNames);
}
return clsx(
removeAspectRatioClasses(existingClassNames),
potentialRatio.className,
"wp-has-aspect-ratio"
);
}
}
}
return existingClassNames;
}
function fallback(url, onReplace) {
const link = /* @__PURE__ */ jsx("a", { href: url, children: url });
onReplace(
createBlock("core/paragraph", { content: renderToString(link) })
);
}
var getAttributesFromPreview = memoize(
(preview, title, currentClassNames, isResponsive, allowResponsive = true) => {
if (!preview) {
return {};
}
const attributes = {};
let { type = "rich" } = preview;
const { html, provider_name: providerName } = preview;
const providerNameSlug = kebabCase(
(providerName || title).toLowerCase()
);
if (isFromWordPress(html)) {
type = WP_EMBED_TYPE;
}
if (html || "photo" === type) {
attributes.type = type;
attributes.providerNameSlug = providerNameSlug;
}
if (hasAspectRatioClass(currentClassNames)) {
return attributes;
}
attributes.className = getClassNames(
html,
currentClassNames,
isResponsive && allowResponsive
);
return attributes;
}
);
var getMergedAttributesWithPreview = (currentAttributes, preview, title, isResponsive) => {
const { allowResponsive, className } = currentAttributes;
return {
...currentAttributes,
...getAttributesFromPreview(
preview,
title,
className,
isResponsive,
allowResponsive
)
};
};
export {
createUpgradedEmbedBlock,
fallback,
findMoreSuitableBlock,
getAttributesFromPreview,
getClassNames,
getEmbedInfoByProvider,
getMergedAttributesWithPreview,
getPhotoHtml,
hasAspectRatioClass,
isFromWordPress,
matchesPatterns,
removeAspectRatioClasses
};
//# sourceMappingURL=util.js.map