UNPKG

@wordpress/block-library

Version:
394 lines (384 loc) 13.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = PostFeaturedImageEdit; var _clsx = _interopRequireDefault(require("clsx")); var _blob = require("@wordpress/blob"); var _coreData = require("@wordpress/core-data"); var _data = require("@wordpress/data"); var _components = require("@wordpress/components"); var _blockEditor = require("@wordpress/block-editor"); var _element = require("@wordpress/element"); var _i18n = require("@wordpress/i18n"); var _icons = require("@wordpress/icons"); var _notices = require("@wordpress/notices"); var _dimensionControls = _interopRequireDefault(require("./dimension-controls")); var _overlayControls = _interopRequireDefault(require("./overlay-controls")); var _overlay = _interopRequireDefault(require("./overlay")); var _hooks = require("../utils/hooks"); var _lockUnlock = require("../lock-unlock"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const ALLOWED_MEDIA_TYPES = ['image']; const { ResolutionTool } = (0, _lockUnlock.unlock)(_blockEditor.privateApis); const DEFAULT_MEDIA_SIZE_SLUG = 'full'; function FeaturedImageResolutionTool({ image, value, onChange }) { const { imageSizes } = (0, _data.useSelect)(select => { const { getSettings } = select(_blockEditor.store); return { imageSizes: getSettings().imageSizes }; }, []); if (!imageSizes?.length) { return null; } const imageSizeOptions = imageSizes.filter(({ slug }) => image?.media_details?.sizes?.[slug]?.source_url).map(({ name, slug }) => ({ value: slug, label: name })); return /*#__PURE__*/(0, _jsxRuntime.jsx)(ResolutionTool, { value: value, defaultValue: DEFAULT_MEDIA_SIZE_SLUG, options: imageSizeOptions, onChange: onChange }); } function PostFeaturedImageEdit({ clientId, attributes, setAttributes, context: { postId, postType: postTypeSlug, queryId } }) { const isDescendentOfQueryLoop = Number.isFinite(queryId); const { isLink, aspectRatio, height, width, scale, sizeSlug, rel, linkTarget, useFirstImageFromPost } = attributes; const [temporaryURL, setTemporaryURL] = (0, _element.useState)(); const [storedFeaturedImage, setFeaturedImage] = (0, _coreData.useEntityProp)('postType', postTypeSlug, 'featured_media', postId); // Fallback to post content if no featured image is set. // This is needed for the "Use first image from post" option. const [postContent] = (0, _coreData.useEntityProp)('postType', postTypeSlug, 'content', postId); const featuredImage = (0, _element.useMemo)(() => { if (storedFeaturedImage) { return storedFeaturedImage; } if (!useFirstImageFromPost) { return; } const imageOpener = /<!--\s+wp:(?:core\/)?image\s+(?<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*)?}\s+)?-->/.exec(postContent); const imageId = imageOpener?.groups?.attrs && JSON.parse(imageOpener.groups.attrs)?.id; return imageId; }, [storedFeaturedImage, useFirstImageFromPost, postContent]); const { media, postType, postPermalink } = (0, _data.useSelect)(select => { const { getMedia, getPostType, getEditedEntityRecord } = select(_coreData.store); return { media: featuredImage && getMedia(featuredImage, { context: 'view' }), postType: postTypeSlug && getPostType(postTypeSlug), postPermalink: getEditedEntityRecord('postType', postTypeSlug, postId)?.link }; }, [featuredImage, postTypeSlug, postId]); const mediaUrl = media?.media_details?.sizes?.[sizeSlug]?.source_url || media?.source_url; const blockProps = (0, _blockEditor.useBlockProps)({ style: { width, height, aspectRatio }, className: (0, _clsx.default)({ 'is-transient': temporaryURL }) }); const borderProps = (0, _blockEditor.__experimentalUseBorderProps)(attributes); const shadowProps = (0, _blockEditor.__experimentalGetShadowClassesAndStyles)(attributes); const blockEditingMode = (0, _blockEditor.useBlockEditingMode)(); const placeholder = content => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Placeholder, { className: (0, _clsx.default)('block-editor-media-placeholder', borderProps.className), withIllustration: true, style: { height: !!aspectRatio && '100%', width: !!aspectRatio && '100%', ...borderProps.style, ...shadowProps.style }, children: content }); }; const onSelectImage = value => { if (value?.id) { setFeaturedImage(value.id); } if (value?.url && (0, _blob.isBlobURL)(value.url)) { setTemporaryURL(value.url); } }; // On reset image const onResetImage = () => { setAttributes({ isLink: false, linkTarget: '_self', rel: '', sizeSlug: undefined }); setFeaturedImage(0); }; // Reset temporary url when media is available. (0, _element.useEffect)(() => { if (mediaUrl && temporaryURL) { setTemporaryURL(); } }, [mediaUrl, temporaryURL]); const { createErrorNotice } = (0, _data.useDispatch)(_notices.store); const onUploadError = message => { createErrorNotice(message, { type: 'snackbar' }); setTemporaryURL(); }; const dropdownMenuProps = (0, _hooks.useToolsPanelDropdownMenuProps)(); const controls = blockEditingMode === 'default' && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, { group: "color", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_overlayControls.default, { attributes: attributes, setAttributes: setAttributes, clientId: clientId }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, { group: "dimensions", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dimensionControls.default, { clientId: clientId, attributes: attributes, setAttributes: setAttributes, media: media }) }), (featuredImage || isDescendentOfQueryLoop || !postId) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, { children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Settings'), resetAll: () => { setAttributes({ isLink: false, linkTarget: '_self', rel: '' }); }, dropdownMenuProps: dropdownMenuProps, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { label: postType?.labels.singular_name ? (0, _i18n.sprintf)( // translators: %s: Name of the post type e.g: "post". (0, _i18n.__)('Link to %s'), postType.labels.singular_name) : (0, _i18n.__)('Link to post'), isShownByDefault: true, hasValue: () => !!isLink, onDeselect: () => setAttributes({ isLink: false }), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: postType?.labels.singular_name ? (0, _i18n.sprintf)( // translators: %s: Name of the post type e.g: "post". (0, _i18n.__)('Link to %s'), postType.labels.singular_name) : (0, _i18n.__)('Link to post'), onChange: () => setAttributes({ isLink: !isLink }), checked: isLink }) }), isLink && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { label: (0, _i18n.__)('Open in new tab'), isShownByDefault: true, hasValue: () => '_self' !== linkTarget, onDeselect: () => setAttributes({ linkTarget: '_self' }), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Open in new tab'), onChange: value => setAttributes({ linkTarget: value ? '_blank' : '_self' }), checked: linkTarget === '_blank' }) }), isLink && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { label: (0, _i18n.__)('Link rel'), isShownByDefault: true, hasValue: () => !!rel, onDeselect: () => setAttributes({ rel: '' }), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextControl, { __next40pxDefaultSize: true, __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Link rel'), value: rel, onChange: newRel => setAttributes({ rel: newRel }) }) }), !!media && /*#__PURE__*/(0, _jsxRuntime.jsx)(FeaturedImageResolutionTool, { image: media, value: sizeSlug, onChange: nextSizeSlug => setAttributes({ sizeSlug: nextSizeSlug }) })] }) })] }); let image; /** * A Post Featured Image block should not have image replacement * or upload options in the following cases: * - Is placed in a Query Loop. This is a conscious decision to * prevent content editing of different posts in Query Loop, and * this could change in the future. * - Is in a context where it does not have a postId (for example * in a template or template part). */ if (!featuredImage && (isDescendentOfQueryLoop || !postId)) { return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [controls, /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { ...blockProps, children: [!!isLink ? /*#__PURE__*/(0, _jsxRuntime.jsx)("a", { href: postPermalink, target: linkTarget, children: placeholder() }) : placeholder(), /*#__PURE__*/(0, _jsxRuntime.jsx)(_overlay.default, { attributes: attributes, setAttributes: setAttributes, clientId: clientId })] })] }); } const label = (0, _i18n.__)('Add a featured image'); const imageStyles = { ...borderProps.style, ...shadowProps.style, height: aspectRatio ? '100%' : height, width: !!aspectRatio && '100%', objectFit: !!(height || aspectRatio) && scale }; /** * When the post featured image block is placed in a context where: * - It has a postId (for example in a single post) * - It is not inside a query loop * - It has no image assigned yet * Then display the placeholder with the image upload option. */ if (!featuredImage && !temporaryURL) { image = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaPlaceholder, { onSelect: onSelectImage, accept: "image/*", allowedTypes: ALLOWED_MEDIA_TYPES, onError: onUploadError, placeholder: placeholder, mediaLibraryButton: ({ open }) => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, icon: _icons.upload, variant: "primary", label: label, showTooltip: true, tooltipPosition: "top center", onClick: () => { open(); } }); } }); } else { // We have a Featured image so show a Placeholder if is loading. image = !media && !temporaryURL ? placeholder() : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("img", { className: borderProps.className, src: temporaryURL || mediaUrl, alt: media && media?.alt_text ? (0, _i18n.sprintf)( // translators: %s: The image's alt text. (0, _i18n.__)('Featured image: %s'), media.alt_text) : (0, _i18n.__)('Featured image'), style: imageStyles }), temporaryURL && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {})] }); } /** * When the post featured image block: * - Has an image assigned * - Is not inside a query loop * Then display the image and the image replacement option. */ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [!temporaryURL && controls, !!media && !isDescendentOfQueryLoop && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, { group: "other", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaReplaceFlow, { mediaId: featuredImage, mediaURL: mediaUrl, allowedTypes: ALLOWED_MEDIA_TYPES, accept: "image/*", onSelect: onSelectImage, onError: onUploadError, onReset: onResetImage }) }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("figure", { ...blockProps, children: [!!isLink ? /*#__PURE__*/(0, _jsxRuntime.jsx)("a", { href: postPermalink, target: linkTarget, children: image }) : image, /*#__PURE__*/(0, _jsxRuntime.jsx)(_overlay.default, { attributes: attributes, setAttributes: setAttributes, clientId: clientId })] })] }); } //# sourceMappingURL=edit.js.map