@wordpress/block-library
Version:
Block library for the WordPress editor.
456 lines (450 loc) • 15.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = _interopRequireDefault(require("clsx"));
var _i18n = require("@wordpress/i18n");
var _data = require("@wordpress/data");
var _element = require("@wordpress/element");
var _blockEditor = require("@wordpress/block-editor");
var _components = require("@wordpress/components");
var _blob = require("@wordpress/blob");
var _icons = require("@wordpress/icons");
var _coreData = require("@wordpress/core-data");
var _mediaContainer = _interopRequireDefault(require("./media-container"));
var _constants = require("./constants");
var _lockUnlock = require("../lock-unlock");
var _hooks = require("../utils/hooks");
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
const {
ResolutionTool
} = (0, _lockUnlock.unlock)(_blockEditor.privateApis);
// this limits the resize to a safe zone to avoid making broken layouts
const applyWidthConstraints = width => Math.max(_constants.WIDTH_CONSTRAINT_PERCENTAGE, Math.min(width, 100 - _constants.WIDTH_CONSTRAINT_PERCENTAGE));
function getImageSourceUrlBySizeSlug(image, slug) {
// eslint-disable-next-line camelcase
return image?.media_details?.sizes?.[slug]?.source_url;
}
function attributesFromMedia({
attributes: {
linkDestination,
href
},
setAttributes
}) {
return media => {
if (!media || !media.url) {
setAttributes({
mediaAlt: undefined,
mediaId: undefined,
mediaType: undefined,
mediaUrl: undefined,
mediaLink: undefined,
href: undefined,
focalPoint: undefined,
useFeaturedImage: false
});
return;
}
if ((0, _blob.isBlobURL)(media.url)) {
media.type = (0, _blob.getBlobTypeByURL)(media.url);
}
let mediaType;
let src;
// For media selections originated from a file upload.
if (media.media_type) {
if (media.media_type === 'image') {
mediaType = 'image';
} else {
// only images and videos are accepted so if the media_type is not an image we can assume it is a video.
// video contain the media type of 'file' in the object returned from the rest api.
mediaType = 'video';
}
} else {
// For media selections originated from existing files in the media library.
mediaType = media.type;
}
if (mediaType === 'image') {
// Try the "large" size URL, falling back to the "full" size URL below.
src = media.sizes?.large?.url ||
// eslint-disable-next-line camelcase
media.media_details?.sizes?.large?.source_url;
}
let newHref = href;
if (linkDestination === _constants.LINK_DESTINATION_MEDIA) {
// Update the media link.
newHref = media.url;
}
// Check if the image is linked to the attachment page.
if (linkDestination === _constants.LINK_DESTINATION_ATTACHMENT) {
// Update the media link.
newHref = media.link;
}
setAttributes({
mediaAlt: media.alt,
mediaId: media.id,
mediaType,
mediaUrl: src || media.url,
mediaLink: media.link || undefined,
href: newHref,
focalPoint: undefined,
useFeaturedImage: false
});
};
}
function MediaTextResolutionTool({
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
}) => getImageSourceUrlBySizeSlug(image, slug)).map(({
name,
slug
}) => ({
value: slug,
label: name
}));
return /*#__PURE__*/(0, _jsxRuntime.jsx)(ResolutionTool, {
value: value,
defaultValue: _constants.DEFAULT_MEDIA_SIZE_SLUG,
options: imageSizeOptions,
onChange: onChange
});
}
function MediaTextEdit({
attributes,
isSelected,
setAttributes,
context: {
postId,
postType
}
}) {
const {
focalPoint,
href,
imageFill,
isStackedOnMobile,
linkClass,
linkDestination,
linkTarget,
mediaAlt,
mediaId,
mediaPosition,
mediaType,
mediaUrl,
mediaWidth,
mediaSizeSlug,
rel,
verticalAlignment,
allowedBlocks,
useFeaturedImage
} = attributes;
const [featuredImage] = (0, _coreData.useEntityProp)('postType', postType, 'featured_media', postId);
const {
featuredImageMedia
} = (0, _data.useSelect)(select => {
return {
featuredImageMedia: featuredImage && useFeaturedImage ? select(_coreData.store).getMedia(featuredImage, {
context: 'view'
}) : undefined
};
}, [featuredImage, useFeaturedImage]);
const {
image
} = (0, _data.useSelect)(select => {
return {
image: mediaId && isSelected ? select(_coreData.store).getMedia(mediaId, {
context: 'view'
}) : null
};
}, [isSelected, mediaId]);
const featuredImageURL = useFeaturedImage ? featuredImageMedia?.source_url : '';
const featuredImageAlt = useFeaturedImage ? featuredImageMedia?.alt_text : '';
const toggleUseFeaturedImage = () => {
setAttributes({
imageFill: false,
mediaType: 'image',
mediaId: undefined,
mediaUrl: undefined,
mediaAlt: undefined,
mediaLink: undefined,
linkDestination: undefined,
linkTarget: undefined,
linkClass: undefined,
rel: undefined,
href: undefined,
useFeaturedImage: !useFeaturedImage
});
};
const refMedia = (0, _element.useRef)();
const imperativeFocalPointPreview = value => {
const {
style
} = refMedia.current;
const {
x,
y
} = value;
style.objectPosition = `${x * 100}% ${y * 100}%`;
};
const [temporaryMediaWidth, setTemporaryMediaWidth] = (0, _element.useState)(null);
const onSelectMedia = attributesFromMedia({
attributes,
setAttributes
});
const onSetHref = props => {
setAttributes(props);
};
const onWidthChange = width => {
setTemporaryMediaWidth(applyWidthConstraints(width));
};
const commitWidthChange = width => {
setAttributes({
mediaWidth: applyWidthConstraints(width)
});
setTemporaryMediaWidth(null);
};
const classNames = (0, _clsx.default)({
'has-media-on-the-right': 'right' === mediaPosition,
'is-selected': isSelected,
'is-stacked-on-mobile': isStackedOnMobile,
[`is-vertically-aligned-${verticalAlignment}`]: verticalAlignment,
'is-image-fill-element': imageFill
});
const widthString = `${temporaryMediaWidth || mediaWidth}%`;
const gridTemplateColumns = 'right' === mediaPosition ? `1fr ${widthString}` : `${widthString} 1fr`;
const style = {
gridTemplateColumns,
msGridColumns: gridTemplateColumns
};
const onMediaAltChange = newMediaAlt => {
setAttributes({
mediaAlt: newMediaAlt
});
};
const onVerticalAlignmentChange = alignment => {
setAttributes({
verticalAlignment: alignment
});
};
const updateImage = newMediaSizeSlug => {
const newUrl = getImageSourceUrlBySizeSlug(image, newMediaSizeSlug);
if (!newUrl) {
return null;
}
setAttributes({
mediaUrl: newUrl,
mediaSizeSlug: newMediaSizeSlug
});
};
const dropdownMenuProps = (0, _hooks.useToolsPanelDropdownMenuProps)();
const mediaTextGeneralSettings = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
label: (0, _i18n.__)('Settings'),
resetAll: () => {
setAttributes({
isStackedOnMobile: true,
imageFill: false,
mediaAlt: '',
focalPoint: undefined,
mediaWidth: 50,
mediaSizeSlug: undefined
});
},
dropdownMenuProps: dropdownMenuProps,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
label: (0, _i18n.__)('Media width'),
isShownByDefault: true,
hasValue: () => mediaWidth !== 50,
onDeselect: () => setAttributes({
mediaWidth: 50
}),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.RangeControl, {
__nextHasNoMarginBottom: true,
__next40pxDefaultSize: true,
label: (0, _i18n.__)('Media width'),
value: temporaryMediaWidth || mediaWidth,
onChange: commitWidthChange,
min: _constants.WIDTH_CONSTRAINT_PERCENTAGE,
max: 100 - _constants.WIDTH_CONSTRAINT_PERCENTAGE
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
label: (0, _i18n.__)('Stack on mobile'),
isShownByDefault: true,
hasValue: () => !isStackedOnMobile,
onDeselect: () => setAttributes({
isStackedOnMobile: true
}),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Stack on mobile'),
checked: isStackedOnMobile,
onChange: () => setAttributes({
isStackedOnMobile: !isStackedOnMobile
})
})
}), mediaType === 'image' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
label: (0, _i18n.__)('Crop image to fill'),
isShownByDefault: true,
hasValue: () => !!imageFill,
onDeselect: () => setAttributes({
imageFill: false
}),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Crop image to fill'),
checked: !!imageFill,
onChange: () => setAttributes({
imageFill: !imageFill
})
})
}), imageFill && (mediaUrl || featuredImageURL) && mediaType === 'image' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
label: (0, _i18n.__)('Focal point'),
isShownByDefault: true,
hasValue: () => !!focalPoint,
onDeselect: () => setAttributes({
focalPoint: undefined
}),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.FocalPointPicker, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Focal point'),
url: useFeaturedImage && featuredImageURL ? featuredImageURL : mediaUrl,
value: focalPoint,
onChange: value => setAttributes({
focalPoint: value
}),
onDragStart: imperativeFocalPointPreview,
onDrag: imperativeFocalPointPreview
})
}), mediaType === 'image' && mediaUrl && !useFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
label: (0, _i18n.__)('Alternative text'),
isShownByDefault: true,
hasValue: () => !!mediaAlt,
onDeselect: () => setAttributes({
mediaAlt: ''
}),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextareaControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Alternative text'),
value: mediaAlt,
onChange: onMediaAltChange,
help: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ExternalLink, {
href:
// translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations.
(0, _i18n.__)('https://www.w3.org/WAI/tutorials/images/decision-tree/'),
children: (0, _i18n.__)('Describe the purpose of the image.')
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), (0, _i18n.__)('Leave empty if decorative.')]
})
})
}), mediaType === 'image' && !useFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(MediaTextResolutionTool, {
image: image,
value: mediaSizeSlug,
onChange: updateImage
})]
});
const blockProps = (0, _blockEditor.useBlockProps)({
className: classNames,
style
});
const innerBlocksProps = (0, _blockEditor.useInnerBlocksProps)({
className: 'wp-block-media-text__content'
}, {
template: _constants.TEMPLATE,
allowedBlocks
});
const blockEditingMode = (0, _blockEditor.useBlockEditingMode)();
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
children: mediaTextGeneralSettings
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_blockEditor.BlockControls, {
group: "block",
children: [blockEditingMode === 'default' && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockVerticalAlignmentControl, {
onChange: onVerticalAlignmentChange,
value: verticalAlignment
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
icon: _icons.pullLeft,
title: (0, _i18n.__)('Show media on left'),
isActive: mediaPosition === 'left',
onClick: () => setAttributes({
mediaPosition: 'left'
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
icon: _icons.pullRight,
title: (0, _i18n.__)('Show media on right'),
isActive: mediaPosition === 'right',
onClick: () => setAttributes({
mediaPosition: 'right'
})
})]
}), mediaType === 'image' && !useFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.__experimentalImageURLInputUI, {
url: href || '',
onChangeUrl: onSetHref,
linkDestination: linkDestination,
mediaType: mediaType,
mediaUrl: image && image.source_url,
mediaLink: image && image.link,
linkTarget: linkTarget,
linkClass: linkClass,
rel: rel
})]
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
...blockProps,
children: [mediaPosition === 'right' && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
...innerBlocksProps
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_mediaContainer.default, {
className: "wp-block-media-text__media",
onSelectMedia: onSelectMedia,
onWidthChange: onWidthChange,
commitWidthChange: commitWidthChange,
refMedia: refMedia,
enableResize: blockEditingMode === 'default',
toggleUseFeaturedImage: toggleUseFeaturedImage,
focalPoint,
imageFill,
isSelected,
isStackedOnMobile,
mediaAlt,
mediaId,
mediaPosition,
mediaType,
mediaUrl,
mediaWidth,
useFeaturedImage,
featuredImageURL,
featuredImageAlt
}), mediaPosition !== 'right' && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
...innerBlocksProps
})]
})]
});
}
var _default = exports.default = MediaTextEdit;
//# sourceMappingURL=edit.js.map