UNPKG

@wordpress/block-library

Version:
280 lines (251 loc) 7.53 kB
import { createElement, Fragment } from "@wordpress/element"; /** * External dependencies */ import classnames from 'classnames'; import { get } from 'lodash'; /** * WordPress dependencies */ import { Component } from '@wordpress/element'; import { Button, Spinner, ButtonGroup } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { BACKSPACE, DELETE } from '@wordpress/keycodes'; import { withSelect, withDispatch } from '@wordpress/data'; import { RichText, MediaPlaceholder, store as blockEditorStore, __experimentalGetElementClassName } from '@wordpress/block-editor'; import { isBlobURL } from '@wordpress/blob'; import { compose } from '@wordpress/compose'; import { closeSmall, chevronLeft, chevronRight, edit, image as imageIcon } from '@wordpress/icons'; import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ import { pickRelevantMediaFiles } from './shared'; import { LINK_DESTINATION_ATTACHMENT, LINK_DESTINATION_MEDIA } from './constants'; const isTemporaryImage = (id, url) => !id && isBlobURL(url); class GalleryImage extends Component { constructor() { super(...arguments); this.onSelectImage = this.onSelectImage.bind(this); this.onRemoveImage = this.onRemoveImage.bind(this); this.bindContainer = this.bindContainer.bind(this); this.onEdit = this.onEdit.bind(this); this.onSelectImageFromLibrary = this.onSelectImageFromLibrary.bind(this); this.onSelectCustomURL = this.onSelectCustomURL.bind(this); this.state = { isEditing: false }; } bindContainer(ref) { this.container = ref; } onSelectImage() { if (!this.props.isSelected) { this.props.onSelect(); } } onRemoveImage(event) { if (this.container === this.container.ownerDocument.activeElement && this.props.isSelected && [BACKSPACE, DELETE].indexOf(event.keyCode) !== -1) { event.preventDefault(); this.props.onRemove(); } } onEdit() { this.setState({ isEditing: true }); } componentDidUpdate() { const { image, url, __unstableMarkNextChangeAsNotPersistent } = this.props; if (image && !url) { __unstableMarkNextChangeAsNotPersistent(); this.props.setAttributes({ url: image.source_url, alt: image.alt_text }); } } deselectOnBlur() { this.props.onDeselect(); } onSelectImageFromLibrary(media) { const { setAttributes, id, url, alt, caption, sizeSlug } = this.props; if (!media || !media.url) { return; } let mediaAttributes = pickRelevantMediaFiles(media, sizeSlug); // If the current image is temporary but an alt text was meanwhile // written by the user, make sure the text is not overwritten. if (isTemporaryImage(id, url)) { if (alt) { const { alt: omittedAlt, ...restMediaAttributes } = mediaAttributes; mediaAttributes = restMediaAttributes; } } // If a caption text was meanwhile written by the user, // make sure the text is not overwritten by empty captions. if (caption && !get(mediaAttributes, ['caption'])) { const { caption: omittedCaption, ...restMediaAttributes } = mediaAttributes; mediaAttributes = restMediaAttributes; } setAttributes(mediaAttributes); this.setState({ isEditing: false }); } onSelectCustomURL(newURL) { const { setAttributes, url } = this.props; if (newURL !== url) { setAttributes({ url: newURL, id: undefined }); this.setState({ isEditing: false }); } } render() { const { url, alt, id, linkTo, link, isFirstItem, isLastItem, isSelected, caption, onRemove, onMoveForward, onMoveBackward, setAttributes, 'aria-label': ariaLabel } = this.props; const { isEditing } = this.state; let href; switch (linkTo) { case LINK_DESTINATION_MEDIA: href = url; break; case LINK_DESTINATION_ATTACHMENT: href = link; break; } const img = // Disable reason: Image itself is not meant to be interactive, but should // direct image selection and unfocus caption fields. /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ createElement(Fragment, null, createElement("img", { src: url, alt: alt, "data-id": id, onKeyDown: this.onRemoveImage, tabIndex: "0", "aria-label": ariaLabel, ref: this.bindContainer }), isBlobURL(url) && createElement(Spinner, null)) /* eslint-enable jsx-a11y/no-noninteractive-element-interactions */ ; const className = classnames({ 'is-selected': isSelected, 'is-transient': isBlobURL(url) }); return (// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions createElement("figure", { className: className, onClick: this.onSelectImage, onFocus: this.onSelectImage }, !isEditing && (href ? createElement("a", { href: href }, img) : img), isEditing && createElement(MediaPlaceholder, { labels: { title: __('Edit gallery image') }, icon: imageIcon, onSelect: this.onSelectImageFromLibrary, onSelectURL: this.onSelectCustomURL, accept: "image/*", allowedTypes: ['image'], value: { id, src: url } }), createElement(ButtonGroup, { className: "block-library-gallery-item__inline-menu is-left" }, createElement(Button, { icon: chevronLeft, onClick: isFirstItem ? undefined : onMoveBackward, label: __('Move image backward'), "aria-disabled": isFirstItem, disabled: !isSelected }), createElement(Button, { icon: chevronRight, onClick: isLastItem ? undefined : onMoveForward, label: __('Move image forward'), "aria-disabled": isLastItem, disabled: !isSelected })), createElement(ButtonGroup, { className: "block-library-gallery-item__inline-menu is-right" }, createElement(Button, { icon: edit, onClick: this.onEdit, label: __('Replace image'), disabled: !isSelected }), createElement(Button, { icon: closeSmall, onClick: onRemove, label: __('Remove image'), disabled: !isSelected })), !isEditing && (isSelected || caption) && createElement(RichText, { tagName: "figcaption", className: __experimentalGetElementClassName('caption'), "aria-label": __('Image caption text'), placeholder: isSelected ? __('Add caption') : null, value: caption, onChange: newCaption => setAttributes({ caption: newCaption }), inlineToolbar: true })) ); } } export default compose([withSelect((select, ownProps) => { const { getMedia } = select(coreStore); const { id } = ownProps; return { image: id ? getMedia(parseInt(id, 10)) : null }; }), withDispatch(dispatch => { const { __unstableMarkNextChangeAsNotPersistent } = dispatch(blockEditorStore); return { __unstableMarkNextChangeAsNotPersistent }; })])(GalleryImage); //# sourceMappingURL=gallery-image.js.map