From 9cbbdf233d6a295f0d09fa82dc9eb6596ee91d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Ka=CC=88gy?= Date: Wed, 31 May 2023 11:06:30 +0200 Subject: [PATCH 01/15] start refactor of image component to create more composable API --- components/image/index.js | 178 ++++++++++++++++++++++++++++++-------- 1 file changed, 140 insertions(+), 38 deletions(-) diff --git a/components/image/index.js b/components/image/index.js index 1979ac87..432aed22 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -1,11 +1,14 @@ import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor'; +import { useContext, useMemo, Children, createContext } from '@wordpress/element'; import { Spinner, FocalPointPicker, PanelBody, Placeholder } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import PropTypes from 'prop-types'; import { useMedia } from '../../hooks/use-media'; -const Image = (props) => { +export const ImageContext = createContext(); + +const ImageWrapper = (props) => { const { id, size = 'full', @@ -14,29 +17,137 @@ const Image = (props) => { onChangeFocalPoint, labels = {}, canEditImage = true, + children, ...rest } = props; const hasImage = !!id; const { media, isResolvingMedia } = useMedia(id); + const hasRenderCallback = typeof children === 'function'; + const hasChildComponents = !hasRenderCallback && Children.count(children); + const shouldDisplayFocalPointPicker = typeof onChangeFocalPoint === 'function'; - if (!hasImage && !canEditImage) { - return ; + const imageUrl = media?.media_details?.sizes[size]?.source_url ?? media?.source_url; + const altText = media?.alt_text; + + const imageContext = useMemo(() => { + return { + id, + size, + focalPoint, + onChangeFocalPoint, + imageUrl, + altText, + labels, + canEditImage, + onSelect, + isResolvingMedia, + shouldDisplayFocalPointPicker, + hasImage, + }; + }, [ + id, + size, + focalPoint, + onChangeFocalPoint, + imageUrl, + altText, + labels, + canEditImage, + onSelect, + isResolvingMedia, + shouldDisplayFocalPointPicker, + hasImage, + ]); + + if (hasRenderCallback) { + return children({ + hasImage, + imageUrl, + altText, + focalPoint, + labels, + canEditImage, + onSelect, + }); + } + + if (hasChildComponents) { + return {children}; } if (!hasImage && canEditImage) { return ( - + ); } - if (isResolvingMedia) { - return ; - } + return ( + +
+ +
+
+ ); +}; - const imageUrl = media?.media_details?.sizes[size]?.source_url ?? media?.source_url; - const altText = media?.alt_text; +export { ImageWrapper as Image }; + +ImageWrapper.defaultProps = { + size: 'large', + focalPoint: { x: 0.5, y: 0.5 }, + onChangeFocalPoint: undefined, + labels: {}, + canEditImage: true, +}; + +ImageWrapper.propTypes = { + id: PropTypes.number.isRequired, + size: PropTypes.string, + onSelect: PropTypes.func.isRequired, + onChangeFocalPoint: PropTypes.func, + focalPoint: PropTypes.shape({ + x: PropTypes.string, + y: PropTypes.string, + }), + labels: PropTypes.shape({ + title: PropTypes.string, + instructions: PropTypes.string, + }), + canEditImage: PropTypes.bool, +}; + +const Figure = (props) => { + const { children, style, ...rest } = props; + + return ( +
+ {children} +
+ ); +}; + +const Image = (props) => { + const { style } = props; + const { + imageUrl, + altText, + labels, + onSelect, + isResolvingMedia, + shouldDisplayFocalPointPicker, + focalPoint, + onChangeFocalPoint, + canEditImage, + hasImage, + } = useContext(ImageContext); if (shouldDisplayFocalPointPicker) { const focalPointStyle = { @@ -44,12 +155,20 @@ const Image = (props) => { objectPosition: `${focalPoint.x * 100}% ${focalPoint.y * 100}%`, }; - rest.style = { - ...rest.style, + props.style = { + ...style, ...focalPointStyle, }; } + if (isResolvingMedia) { + return ; + } + + if (!hasImage && !canEditImage) { + return ; + } + return ( <> {shouldDisplayFocalPointPicker && ( @@ -64,33 +183,16 @@ const Image = (props) => { )} - {altText} + {hasImage && {altText}} + {canEditImage && ( + + )} ); }; - -export { Image }; - -Image.defaultProps = { - size: 'large', - focalPoint: { x: 0.5, y: 0.5 }, - onChangeFocalPoint: undefined, - labels: {}, - canEditImage: true, -}; - -Image.propTypes = { - id: PropTypes.number.isRequired, - size: PropTypes.string, - onSelect: PropTypes.func.isRequired, - onChangeFocalPoint: PropTypes.func, - focalPoint: PropTypes.shape({ - x: PropTypes.string, - y: PropTypes.string, - }), - labels: PropTypes.shape({ - title: PropTypes.string, - instructions: PropTypes.string, - }), - canEditImage: PropTypes.bool, -}; From 905324e85c3e4725a8e36bb3a8b402bdd6b7f62e Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 15:43:35 +0200 Subject: [PATCH 02/15] Added inline image controls options --- components/image/index.js | 72 ++++++++++++++-- components/image/styles.js | 84 +++++++++++++++++++ .../blocks/multiple-image-example/block.json | 44 ++++++++++ .../src/blocks/multiple-image-example/edit.js | 50 +++++++++++ .../blocks/multiple-image-example/index.js | 10 +++ example/src/index.js | 1 + 6 files changed, 254 insertions(+), 7 deletions(-) create mode 100644 components/image/styles.js create mode 100644 example/src/blocks/multiple-image-example/block.json create mode 100644 example/src/blocks/multiple-image-example/edit.js create mode 100644 example/src/blocks/multiple-image-example/index.js diff --git a/components/image/index.js b/components/image/index.js index 432aed22..b5bcd357 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -1,9 +1,20 @@ -import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor'; +import { MediaPlaceholder, InspectorControls, MediaReplaceFlow } from '@wordpress/block-editor'; import { useContext, useMemo, Children, createContext } from '@wordpress/element'; -import { Spinner, FocalPointPicker, PanelBody, Placeholder } from '@wordpress/components'; +import { + Spinner, + FocalPointPicker, + PanelBody, + Placeholder, + ToolbarButton, +} from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import PropTypes from 'prop-types'; +/** + * Internal Dependencies + */ +import { StyledComponentContext } from '../styled-components-context'; +import { InlineControlsStyleWrapper } from './styles'; import { useMedia } from '../../hooks/use-media'; export const ImageContext = createContext(); @@ -18,6 +29,9 @@ const ImageWrapper = (props) => { labels = {}, canEditImage = true, children, + hasInlineControls = false, + isOptional = true, + onRemove, ...rest } = props; const hasImage = !!id; @@ -93,6 +107,22 @@ const ImageWrapper = (props) => {
+ {hasImage && !!hasInlineControls && ( +
+
+ + {!!isOptional && ( + + {__('Remove')} + + )} +
+
+ )}
); @@ -106,6 +136,10 @@ ImageWrapper.defaultProps = { onChangeFocalPoint: undefined, labels: {}, canEditImage: true, + hasInlineControls: false, + isOptional: true, + onRemove: undefined, + children: [], }; ImageWrapper.propTypes = { @@ -122,18 +156,34 @@ ImageWrapper.propTypes = { instructions: PropTypes.string, }), canEditImage: PropTypes.bool, + hasInlineControls: PropTypes.bool, + isOptional: PropTypes.bool, + onRemove: PropTypes.func, + children: PropTypes.array, }; const Figure = (props) => { - const { children, style, ...rest } = props; + const { style, children, ...rest } = props; return ( -
- {children} -
+ + + {children} + + ); }; +Figure.defaultProps = { + style: {}, + children: [], +}; + +Figure.propTypes = { + style: PropTypes.object, + children: PropTypes.array, +}; + const Image = (props) => { const { style } = props; const { @@ -155,7 +205,7 @@ const Image = (props) => { objectPosition: `${focalPoint.x * 100}% ${focalPoint.y * 100}%`, }; - props.style = { + props.styles = { ...style, ...focalPointStyle, }; @@ -196,3 +246,11 @@ const Image = (props) => { ); }; + +Image.defaultProps = { + style: {}, +}; + +Image.propTypes = { + style: PropTypes.object, +}; diff --git a/components/image/styles.js b/components/image/styles.js new file mode 100644 index 00000000..83320663 --- /dev/null +++ b/components/image/styles.js @@ -0,0 +1,84 @@ +import styled from '@emotion/styled'; + +export const InlineControlsStyleWrapper = styled('figure')` + line-height: 0; + position: relative; + margin-bottom: 0; + + & img { + max-width: 100%; + } + + & *, + *::before, + *::after { + box-sizing: border-box; + } + + &:hover, + &:focus, + &:focus-visible, + &:focus-within { + outline: 1px solid #1e1e1e; + outline-offset: -1px; + + & .inline-controls { + opacity: 1; + pointer-events: all; + } + } + + & .inline-controls-sticky-wrapper { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + + & .inline-controls { + border: 1px solid #1e1e1e; + border-radius: 2px; + display: grid; + gap: 1px; + grid-auto-flow: column; + grid-template-columns: repeat(auto-fit, minmax(36px, 1fr)); + margin: 10px 10px 10px auto; + opacity: 0; + overflow: hidden; + pointer-events: none; + position: sticky; + top: 10px; + transition: opacity 250ms ease-out; + width: max-content; + + & > div:not(:last-child) { + border-right: 1px solid #1e1e1e; + display: block; + min-width: max-content; + position: relative; + } + + & .components-button { + --button-text: inherit; + --button-background: var(--wp--preset--color--white); + background: var(--button-background); + border-radius: 0; + color: var(--button-text); + height: 46px; + outline: 1px solid transparent; + padding: 6px 12px; + text-decoration: none; + white-space: nowrap; + + &:focus:not(.disabled) { + outline: var(--wp-admin-theme-color); + } + + &:hover:not(.disabled), + &:active:not(.disabled) { + --button-text: var(--wp-admin-theme-color); + } + } + } +`; diff --git a/example/src/blocks/multiple-image-example/block.json b/example/src/blocks/multiple-image-example/block.json new file mode 100644 index 00000000..aa25e9d2 --- /dev/null +++ b/example/src/blocks/multiple-image-example/block.json @@ -0,0 +1,44 @@ +{ + "name": "example/multiple-image-example", + "apiVersion": 2, + "title": "Multiple Image Example", + "description": "Multiple images block to show the Image with inline controls in usage", + "icon": "smiley", + "category": "common", + "example": {}, + "supports": { + "html": false + }, + "attributes": { + "image1": { + "type": "number" + }, + "image2": { + "type": "number" + }, + "image3": { + "type": "number" + }, + "focalPoint1": { + "type": "object", + "default": { + "x": "0.5", + "y": "0.5" + } + }, + "focalPoint2": { + "type": "object", + "default": { + "x": "0.5", + "y": "0.5" + } + }, + "focalPoint3": { + "type": "object", + "default": { + "x": "0.5", + "y": "0.5" + } + } + } +} \ No newline at end of file diff --git a/example/src/blocks/multiple-image-example/edit.js b/example/src/blocks/multiple-image-example/edit.js new file mode 100644 index 00000000..38add3dc --- /dev/null +++ b/example/src/blocks/multiple-image-example/edit.js @@ -0,0 +1,50 @@ +import { __ } from '@wordpress/i18n'; +import { useBlockProps } from '@wordpress/block-editor'; + +import { Image } from '@10up/block-components'; + +export function BlockEdit(props) { + const { + attributes, + setAttributes + } = props; + + const { image1, image2, image3, focalPoint1, focalPoint2, focalPoint3 } = attributes; + const blockProps = useBlockProps(); + + return ( +
+ + setAttributes({image1: image.id })} + className="example-image" + focalPoint={focalPoint1} + onChangeFocalPoint={(value) => setAttributes({focalPoint1: value})} + hasInlineControls={true} onRemove={() => setAttributes({image1: null})} + isOptional={false} + /> + + setAttributes({image2: image.id })} + className="example-image" + focalPoint={focalPoint2} + onChangeFocalPoint={(value) => setAttributes({focalPoint2: value})} + hasInlineControls={true} onRemove={() => setAttributes({image2: null})} + /> + + setAttributes({image3: image.id })} + className="example-image" + focalPoint={focalPoint3} + onChangeFocalPoint={(value) => setAttributes({focalPoint3: value})} + hasInlineControls={true} onRemove={() => setAttributes({image3: null})} + /> +
+ ) +} \ No newline at end of file diff --git a/example/src/blocks/multiple-image-example/index.js b/example/src/blocks/multiple-image-example/index.js new file mode 100644 index 00000000..cd17beb4 --- /dev/null +++ b/example/src/blocks/multiple-image-example/index.js @@ -0,0 +1,10 @@ +import { registerBlockType } from '@wordpress/blocks'; +import { __ } from '@wordpress/i18n'; + +import { BlockEdit } from './edit'; +import metadata from './block.json'; + +registerBlockType( metadata, { + edit: BlockEdit, + save: () => null +} ); diff --git a/example/src/index.js b/example/src/index.js index 14f017e4..29351724 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -1 +1,2 @@ import './extensions/background-pattern'; +import './blocks/multiple-image-example'; From e92b5cef1092568f6f571848650988c1294b85a9 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 16:39:06 +0200 Subject: [PATCH 03/15] Refactored the inline controls as a separate component --- components/image/inline-controls.js | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 components/image/inline-controls.js diff --git a/components/image/inline-controls.js b/components/image/inline-controls.js new file mode 100644 index 00000000..c580fb86 --- /dev/null +++ b/components/image/inline-controls.js @@ -0,0 +1,39 @@ +import { __ } from '@wordpress/i18n'; +import { MediaReplaceFlow } from '@wordpress/block-editor'; +import { ToolbarButton } from '@wordpress/components'; +import PropTypes from 'prop-types'; + +/** + * Internal Dependencies + */ + +export const InlineControls = (props) => { + const { imageUrl, onSelect, isOptional, onRemove } = props; + + return ( +
+
+ + {!!isOptional && ( + + {__('Remove')} + + )} +
+
+ ); +}; + +InlineControls.defaultProps = { + imageUrl: '', + onSelect: undefined, + isOptional: false, + onRemove: undefined, +}; + +InlineControls.propTypes = { + imageUrl: PropTypes.string, + onSelect: PropTypes.func, + isOptional: PropTypes.bool, + onRemove: PropTypes.func, +}; From a7225b10c1485b4d6b033bed8a1dce2ce1668d78 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 16:39:53 +0200 Subject: [PATCH 04/15] Changes Image.Image component to Media and split into separate component file --- components/image/media.js | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 components/image/media.js diff --git a/components/image/media.js b/components/image/media.js new file mode 100644 index 00000000..42f391f9 --- /dev/null +++ b/components/image/media.js @@ -0,0 +1,78 @@ +import PropTypes from 'prop-types'; +import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor'; +import { useContext, createContext } from '@wordpress/element'; +import { Spinner, FocalPointPicker, PanelBody, Placeholder } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export const ImageContext = createContext(); + +export const Media = (props) => { + const { style } = props; + const { + imageUrl, + altText, + labels, + onSelect, + isResolvingMedia, + shouldDisplayFocalPointPicker, + focalPoint, + onChangeFocalPoint, + canEditImage, + hasImage, + } = useContext(ImageContext); + + if (shouldDisplayFocalPointPicker) { + const focalPointStyle = { + objectFit: 'cover', + objectPosition: `${focalPoint.x * 100}% ${focalPoint.y * 100}%`, + }; + + props.styles = { + ...style, + ...focalPointStyle, + }; + } + + if (isResolvingMedia) { + return ; + } + + if (!hasImage && !canEditImage) { + return ; + } + + return ( + <> + {shouldDisplayFocalPointPicker && ( + + + + + + )} + {hasImage && {altText}} + {canEditImage && ( + + )} + + ); +}; + +Media.defaultProps = { + style: {}, +}; + +Media.propTypes = { + style: PropTypes.object, +}; From 4491c431a57997a443e1d85797e20a5d41c13443 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 16:40:17 +0200 Subject: [PATCH 05/15] Refactored the index to pull in external components --- components/image/index.js | 118 +++++++------------------------------- 1 file changed, 20 insertions(+), 98 deletions(-) diff --git a/components/image/index.js b/components/image/index.js index b5bcd357..d86574e6 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -1,24 +1,16 @@ -import { MediaPlaceholder, InspectorControls, MediaReplaceFlow } from '@wordpress/block-editor'; -import { useContext, useMemo, Children, createContext } from '@wordpress/element'; -import { - Spinner, - FocalPointPicker, - PanelBody, - Placeholder, - ToolbarButton, -} from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; +import { MediaPlaceholder } from '@wordpress/block-editor'; +import { useMemo, Children } from '@wordpress/element'; import PropTypes from 'prop-types'; /** * Internal Dependencies */ import { StyledComponentContext } from '../styled-components-context'; +import { Media, ImageContext } from './media'; +import { InlineControls } from './inline-controls'; import { InlineControlsStyleWrapper } from './styles'; import { useMedia } from '../../hooks/use-media'; -export const ImageContext = createContext(); - const ImageWrapper = (props) => { const { id, @@ -59,6 +51,9 @@ const ImageWrapper = (props) => { isResolvingMedia, shouldDisplayFocalPointPicker, hasImage, + hasInlineControls, + isOptional, + onRemove, }; }, [ id, @@ -73,6 +68,9 @@ const ImageWrapper = (props) => { isResolvingMedia, shouldDisplayFocalPointPicker, hasImage, + hasInlineControls, + isOptional, + onRemove, ]); if (hasRenderCallback) { @@ -84,6 +82,9 @@ const ImageWrapper = (props) => { labels, canEditImage, onSelect, + hasInlineControls, + isOptional, + onRemove, }); } @@ -106,22 +107,14 @@ const ImageWrapper = (props) => { return (
- + {hasImage && !!hasInlineControls && ( -
-
- - {!!isOptional && ( - - {__('Remove')} - - )} -
-
+ )}
@@ -183,74 +176,3 @@ Figure.propTypes = { style: PropTypes.object, children: PropTypes.array, }; - -const Image = (props) => { - const { style } = props; - const { - imageUrl, - altText, - labels, - onSelect, - isResolvingMedia, - shouldDisplayFocalPointPicker, - focalPoint, - onChangeFocalPoint, - canEditImage, - hasImage, - } = useContext(ImageContext); - - if (shouldDisplayFocalPointPicker) { - const focalPointStyle = { - objectFit: 'cover', - objectPosition: `${focalPoint.x * 100}% ${focalPoint.y * 100}%`, - }; - - props.styles = { - ...style, - ...focalPointStyle, - }; - } - - if (isResolvingMedia) { - return ; - } - - if (!hasImage && !canEditImage) { - return ; - } - - return ( - <> - {shouldDisplayFocalPointPicker && ( - - - - - - )} - {hasImage && {altText}} - {canEditImage && ( - - )} - - ); -}; - -Image.defaultProps = { - style: {}, -}; - -Image.propTypes = { - style: PropTypes.object, -}; From 4cb8b51429024ba01c146c0749d42ace2aa88601 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 16:42:47 +0200 Subject: [PATCH 06/15] Split the figure component out into its own file --- components/image/figure.js | 25 ++++++++++++++++++ components/image/index.js | 26 ++----------------- .../src/blocks/multiple-image-example/edit.js | 9 ++++--- 3 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 components/image/figure.js diff --git a/components/image/figure.js b/components/image/figure.js new file mode 100644 index 00000000..e60c68a7 --- /dev/null +++ b/components/image/figure.js @@ -0,0 +1,25 @@ +import PropTypes from 'prop-types'; +import { StyledComponentContext } from '../styled-components-context'; +import { InlineControlsStyleWrapper } from './styles'; + +export const Figure = (props) => { + const { style, children, ...rest } = props; + + return ( + + + {children} + + + ); +}; + +Figure.defaultProps = { + style: {}, + children: [], +}; + +Figure.propTypes = { + style: PropTypes.object, + children: PropTypes.array, +}; diff --git a/components/image/index.js b/components/image/index.js index d86574e6..4f72c280 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -5,10 +5,10 @@ import PropTypes from 'prop-types'; /** * Internal Dependencies */ -import { StyledComponentContext } from '../styled-components-context'; + import { Media, ImageContext } from './media'; +import { Figure } from './figure'; import { InlineControls } from './inline-controls'; -import { InlineControlsStyleWrapper } from './styles'; import { useMedia } from '../../hooks/use-media'; const ImageWrapper = (props) => { @@ -154,25 +154,3 @@ ImageWrapper.propTypes = { onRemove: PropTypes.func, children: PropTypes.array, }; - -const Figure = (props) => { - const { style, children, ...rest } = props; - - return ( - - - {children} - - - ); -}; - -Figure.defaultProps = { - style: {}, - children: [], -}; - -Figure.propTypes = { - style: PropTypes.object, - children: PropTypes.array, -}; diff --git a/example/src/blocks/multiple-image-example/edit.js b/example/src/blocks/multiple-image-example/edit.js index 38add3dc..36bd382b 100644 --- a/example/src/blocks/multiple-image-example/edit.js +++ b/example/src/blocks/multiple-image-example/edit.js @@ -22,7 +22,8 @@ export function BlockEdit(props) { className="example-image" focalPoint={focalPoint1} onChangeFocalPoint={(value) => setAttributes({focalPoint1: value})} - hasInlineControls={true} onRemove={() => setAttributes({image1: null})} + hasInlineControls={true} + onRemove={() => setAttributes({image1: null})} isOptional={false} /> @@ -33,7 +34,8 @@ export function BlockEdit(props) { className="example-image" focalPoint={focalPoint2} onChangeFocalPoint={(value) => setAttributes({focalPoint2: value})} - hasInlineControls={true} onRemove={() => setAttributes({image2: null})} + hasInlineControls={true} + onRemove={() => setAttributes({image2: null})} /> setAttributes({focalPoint3: value})} - hasInlineControls={true} onRemove={() => setAttributes({image3: null})} + hasInlineControls={true} + onRemove={() => setAttributes({image3: null})} /> ) From 9126341164d17bb378ebb6f4488a470877ca622e Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 16:49:36 +0200 Subject: [PATCH 07/15] Refactored child components into their own sub directory for easier import --- components/image/{ => child-components}/figure.js | 4 ++-- components/image/child-components/index.js | 5 +++++ components/image/{ => child-components}/inline-controls.js | 0 components/image/{ => child-components}/media.js | 0 components/image/index.js | 5 +---- 5 files changed, 8 insertions(+), 6 deletions(-) rename components/image/{ => child-components}/figure.js (77%) create mode 100644 components/image/child-components/index.js rename components/image/{ => child-components}/inline-controls.js (100%) rename components/image/{ => child-components}/media.js (100%) diff --git a/components/image/figure.js b/components/image/child-components/figure.js similarity index 77% rename from components/image/figure.js rename to components/image/child-components/figure.js index e60c68a7..f965738e 100644 --- a/components/image/figure.js +++ b/components/image/child-components/figure.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; -import { StyledComponentContext } from '../styled-components-context'; -import { InlineControlsStyleWrapper } from './styles'; +import { StyledComponentContext } from '../../styled-components-context'; +import { InlineControlsStyleWrapper } from '../styles'; export const Figure = (props) => { const { style, children, ...rest } = props; diff --git a/components/image/child-components/index.js b/components/image/child-components/index.js new file mode 100644 index 00000000..3e05dd96 --- /dev/null +++ b/components/image/child-components/index.js @@ -0,0 +1,5 @@ +import { Media, ImageContext } from './media'; +import { Figure } from './figure'; +import { InlineControls } from './inline-controls'; + +export { Media, ImageContext, Figure, InlineControls }; diff --git a/components/image/inline-controls.js b/components/image/child-components/inline-controls.js similarity index 100% rename from components/image/inline-controls.js rename to components/image/child-components/inline-controls.js diff --git a/components/image/media.js b/components/image/child-components/media.js similarity index 100% rename from components/image/media.js rename to components/image/child-components/media.js diff --git a/components/image/index.js b/components/image/index.js index 4f72c280..78b78cb2 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -5,10 +5,7 @@ import PropTypes from 'prop-types'; /** * Internal Dependencies */ - -import { Media, ImageContext } from './media'; -import { Figure } from './figure'; -import { InlineControls } from './inline-controls'; +import { Media, ImageContext, Figure, InlineControls } from './child-components'; import { useMedia } from '../../hooks/use-media'; const ImageWrapper = (props) => { From e670cea2e55f8f04d2351f6206ac2886c68d0d78 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 17:04:29 +0200 Subject: [PATCH 08/15] Updated readme --- components/image/readme.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/image/readme.md b/components/image/readme.md index 531f85a7..9eec72bf 100644 --- a/components/image/readme.md +++ b/components/image/readme.md @@ -45,11 +45,13 @@ function BlockEdit(props) { | Name | Type | Default | Description | | ---------- | ----------------- | -------- | -------------------------------------------------------------- | -| `id` | `number` | `null` | Image ID | +| `id` | `number` | `null` | Image ID | | `onSelect` | `Function` | `null` | Callback that gets called with the new image when one is selected | | `size` | `string` | `large` | Name of the image size to be displayed | | `focalPoint` | `object` | `{x:0.5,y:0.5}` | Optional focal point object. | `onChangeFocalPoint` | `function` | `undefined` | Callback that gets called with the new focal point when it changes. (Is required for the FocalPointPicker to appear) | | `labels` | `object` | `{}` | Pass in an object of labels to be used by the `MediaPlaceholder` component under the hook. Allows the sub properties `title` and `instructions` | -| `canEditImage` | `boolean` | `true` | whether or not the image can be edited by in the context its getting viewed. Controls whether a placeholder or upload controls should be shown when no image is present | -| `...rest` | `*` | `null` | any additional attributes you want to pass to the underlying `img` tag | +| `canEditImage` | `boolean` | `true` | Whether or not the image can be edited by in the context its getting viewed. Controls whether a placeholder or upload controls should be shown when no image is present | +| `hasInlineControls` | `boolean` | `false` | When `true`, it will display inline media flow controls | +| `isOptional` | `boolean` | `false` | Wether or not the inline controls' Remove Image button should be shown. ***NOTE:*** it has no effect if `hasInlineControls` is `false` | +| `...rest` | `*` | `null` | Any additional attributes you want to pass to the underlying `img` tag | From 4dba3d1080835d80d383617e0eb2e631dc8e9b2e Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 17:34:50 +0200 Subject: [PATCH 09/15] Fixes media styles block error --- components/image/child-components/media.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/components/image/child-components/media.js b/components/image/child-components/media.js index 42f391f9..fa66d86c 100644 --- a/components/image/child-components/media.js +++ b/components/image/child-components/media.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; -import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor'; import { useContext, createContext } from '@wordpress/element'; +import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor'; import { Spinner, FocalPointPicker, PanelBody, Placeholder } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -21,16 +21,13 @@ export const Media = (props) => { hasImage, } = useContext(ImageContext); + let focalPointStyle = {}; + if (shouldDisplayFocalPointPicker) { - const focalPointStyle = { + focalPointStyle = { objectFit: 'cover', objectPosition: `${focalPoint.x * 100}% ${focalPoint.y * 100}%`, }; - - props.styles = { - ...style, - ...focalPointStyle, - }; } if (isResolvingMedia) { @@ -55,7 +52,14 @@ export const Media = (props) => { )} - {hasImage && {altText}} + {hasImage && ( + {altText} + )} {canEditImage && ( Date: Fri, 6 Oct 2023 20:31:18 +0200 Subject: [PATCH 10/15] Reworked the style prop for rendering conditional --- components/image/index.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/components/image/index.js b/components/image/index.js index 78b78cb2..b8e363cf 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -21,6 +21,7 @@ const ImageWrapper = (props) => { hasInlineControls = false, isOptional = true, onRemove, + style, ...rest } = props; const hasImage = !!id; @@ -103,17 +104,19 @@ const ImageWrapper = (props) => { return ( -
- - {hasImage && !!hasInlineControls && ( + {hasImage && !!hasInlineControls ? ( +
+ - )} -
+
+ ) : ( + + )}
); }; @@ -129,7 +132,8 @@ ImageWrapper.defaultProps = { hasInlineControls: false, isOptional: true, onRemove: undefined, - children: [], + children: undefined, + style: {}, }; ImageWrapper.propTypes = { @@ -149,5 +153,6 @@ ImageWrapper.propTypes = { hasInlineControls: PropTypes.bool, isOptional: PropTypes.bool, onRemove: PropTypes.func, - children: PropTypes.array, + children: PropTypes.node, + style: PropTypes.object, }; From 5a64b4522f188984f8b37614448524089d15460b Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 20:31:31 +0200 Subject: [PATCH 11/15] Updated figure styles --- components/image/styles.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/image/styles.js b/components/image/styles.js index 83320663..a4c00219 100644 --- a/components/image/styles.js +++ b/components/image/styles.js @@ -1,18 +1,20 @@ import styled from '@emotion/styled'; export const InlineControlsStyleWrapper = styled('figure')` - line-height: 0; position: relative; - margin-bottom: 0; + margin: 0; + line-height: 0; & img { - max-width: 100%; + min-width: 100%; + min-height: 100%; } & *, *::before, *::after { box-sizing: border-box; + line-height: initial; } &:hover, From f006e22ddafca48158bfe6afa16b98c93ed54885 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 20:31:55 +0200 Subject: [PATCH 12/15] Updated figire component style prop --- components/image/child-components/figure.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/image/child-components/figure.js b/components/image/child-components/figure.js index f965738e..932afd7b 100644 --- a/components/image/child-components/figure.js +++ b/components/image/child-components/figure.js @@ -7,7 +7,7 @@ export const Figure = (props) => { return ( - + {children} @@ -16,10 +16,10 @@ export const Figure = (props) => { Figure.defaultProps = { style: {}, - children: [], + children: undefined, }; Figure.propTypes = { style: PropTypes.object, - children: PropTypes.array, + children: PropTypes.node, }; From 4db07f2e4b41ba23e4616493a74676e4ef073f18 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 20:37:49 +0200 Subject: [PATCH 13/15] Updated media component props --- components/image/child-components/media.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/image/child-components/media.js b/components/image/child-components/media.js index fa66d86c..00cb9071 100644 --- a/components/image/child-components/media.js +++ b/components/image/child-components/media.js @@ -7,7 +7,7 @@ import { __ } from '@wordpress/i18n'; export const ImageContext = createContext(); export const Media = (props) => { - const { style } = props; + const { style, ...rest } = props; const { imageUrl, altText, @@ -56,8 +56,8 @@ export const Media = (props) => { {altText} )} {canEditImage && ( From 786c680e195b84240a984879ebdd0c0443e3c942 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 20:38:49 +0200 Subject: [PATCH 14/15] Created `Figure` compound component for the main Image component --- components/image/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/image/index.js b/components/image/index.js index b8e363cf..78962d85 100644 --- a/components/image/index.js +++ b/components/image/index.js @@ -121,6 +121,8 @@ const ImageWrapper = (props) => { ); }; +ImageWrapper.Figure = Figure; + export { ImageWrapper as Image }; ImageWrapper.defaultProps = { From df92c3389c871f61ba1fbeab442dc71050391d52 Mon Sep 17 00:00:00 2001 From: Neil Coetzer Date: Fri, 6 Oct 2023 20:51:18 +0200 Subject: [PATCH 15/15] Added styling fix for the figure lement for block API 3 --- components/image/styles.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/image/styles.js b/components/image/styles.js index a4c00219..b211ca7f 100644 --- a/components/image/styles.js +++ b/components/image/styles.js @@ -1,11 +1,12 @@ import styled from '@emotion/styled'; export const InlineControlsStyleWrapper = styled('figure')` + line-height: 0; position: relative; margin: 0; - line-height: 0; & img { + max-width: 100%; min-width: 100%; min-height: 100%; } @@ -31,11 +32,11 @@ export const InlineControlsStyleWrapper = styled('figure')` } & .inline-controls-sticky-wrapper { + height: 100%; + left: 0; position: absolute; top: 0; - left: 0; width: 100%; - height: 100%; } & .inline-controls {