From 54eb2ebc1d9130f86a7868aa7d1e3a4843b9aaa1 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Sat, 3 Sep 2022 05:48:01 +0900 Subject: [PATCH 01/17] Rename files --- .../src/focal-point-picker/{controls.js => controls.tsx} | 0 .../src/focal-point-picker/{focal-point.js => focal-point.tsx} | 0 .../components/src/focal-point-picker/{grid.js => grid.tsx} | 0 .../components/src/focal-point-picker/{index.js => index.tsx} | 0 .../components/src/focal-point-picker/{media.js => media.tsx} | 0 .../src/focal-point-picker/stories/{index.js => index.tsx} | 2 +- ...{focal-point-picker-style.js => focal-point-picker-style.ts} | 0 .../styles/{focal-point-style.js => focal-point-style.ts} | 0 .../components/src/focal-point-picker/{utils.js => utils.ts} | 0 9 files changed, 1 insertion(+), 1 deletion(-) rename packages/components/src/focal-point-picker/{controls.js => controls.tsx} (100%) rename packages/components/src/focal-point-picker/{focal-point.js => focal-point.tsx} (100%) rename packages/components/src/focal-point-picker/{grid.js => grid.tsx} (100%) rename packages/components/src/focal-point-picker/{index.js => index.tsx} (100%) rename packages/components/src/focal-point-picker/{media.js => media.tsx} (100%) rename packages/components/src/focal-point-picker/stories/{index.js => index.tsx} (97%) rename packages/components/src/focal-point-picker/styles/{focal-point-picker-style.js => focal-point-picker-style.ts} (100%) rename packages/components/src/focal-point-picker/styles/{focal-point-style.js => focal-point-style.ts} (100%) rename packages/components/src/focal-point-picker/{utils.js => utils.ts} (100%) diff --git a/packages/components/src/focal-point-picker/controls.js b/packages/components/src/focal-point-picker/controls.tsx similarity index 100% rename from packages/components/src/focal-point-picker/controls.js rename to packages/components/src/focal-point-picker/controls.tsx diff --git a/packages/components/src/focal-point-picker/focal-point.js b/packages/components/src/focal-point-picker/focal-point.tsx similarity index 100% rename from packages/components/src/focal-point-picker/focal-point.js rename to packages/components/src/focal-point-picker/focal-point.tsx diff --git a/packages/components/src/focal-point-picker/grid.js b/packages/components/src/focal-point-picker/grid.tsx similarity index 100% rename from packages/components/src/focal-point-picker/grid.js rename to packages/components/src/focal-point-picker/grid.tsx diff --git a/packages/components/src/focal-point-picker/index.js b/packages/components/src/focal-point-picker/index.tsx similarity index 100% rename from packages/components/src/focal-point-picker/index.js rename to packages/components/src/focal-point-picker/index.tsx diff --git a/packages/components/src/focal-point-picker/media.js b/packages/components/src/focal-point-picker/media.tsx similarity index 100% rename from packages/components/src/focal-point-picker/media.js rename to packages/components/src/focal-point-picker/media.tsx diff --git a/packages/components/src/focal-point-picker/stories/index.js b/packages/components/src/focal-point-picker/stories/index.tsx similarity index 97% rename from packages/components/src/focal-point-picker/stories/index.js rename to packages/components/src/focal-point-picker/stories/index.tsx index 475029611a285f..f3b0c9401be8a7 100644 --- a/packages/components/src/focal-point-picker/stories/index.js +++ b/packages/components/src/focal-point-picker/stories/index.tsx @@ -5,7 +5,7 @@ import { useState } from '@wordpress/element'; /** * Internal dependencies */ -import FocalPointPicker from '../'; +import FocalPointPicker from '..'; export default { title: 'Components/FocalPointPicker', diff --git a/packages/components/src/focal-point-picker/styles/focal-point-picker-style.js b/packages/components/src/focal-point-picker/styles/focal-point-picker-style.ts similarity index 100% rename from packages/components/src/focal-point-picker/styles/focal-point-picker-style.js rename to packages/components/src/focal-point-picker/styles/focal-point-picker-style.ts diff --git a/packages/components/src/focal-point-picker/styles/focal-point-style.js b/packages/components/src/focal-point-picker/styles/focal-point-style.ts similarity index 100% rename from packages/components/src/focal-point-picker/styles/focal-point-style.js rename to packages/components/src/focal-point-picker/styles/focal-point-style.ts diff --git a/packages/components/src/focal-point-picker/utils.js b/packages/components/src/focal-point-picker/utils.ts similarity index 100% rename from packages/components/src/focal-point-picker/utils.js rename to packages/components/src/focal-point-picker/utils.ts From 282c9a20482fcd6e4ccdaa2155d8b342c66182ea Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Thu, 8 Sep 2022 20:22:50 +0900 Subject: [PATCH 02/17] FocalPickerControl: Convert to TypeScript --- .../src/focal-point-picker/controls.tsx | 32 +++++-- .../src/focal-point-picker/focal-point.tsx | 8 +- .../src/focal-point-picker/grid.tsx | 7 +- .../src/focal-point-picker/index.tsx | 52 +++++++++--- .../src/focal-point-picker/media.tsx | 3 +- .../src/focal-point-picker/stories/index.tsx | 56 +++++++------ .../styles/focal-point-picker-style.ts | 3 +- .../styles/focal-point-style.ts | 3 +- .../src/focal-point-picker/types.ts | 84 +++++++++++++++++++ .../src/focal-point-picker/utils.ts | 18 ++-- packages/components/tsconfig.json | 1 - .../compose/src/hooks/use-dragging/index.js | 30 ++++--- 12 files changed, 227 insertions(+), 70 deletions(-) create mode 100644 packages/components/src/focal-point-picker/types.ts diff --git a/packages/components/src/focal-point-picker/controls.tsx b/packages/components/src/focal-point-picker/controls.tsx index dc8ea6404029e0..31669a077d795b 100644 --- a/packages/components/src/focal-point-picker/controls.tsx +++ b/packages/components/src/focal-point-picker/controls.tsx @@ -11,6 +11,11 @@ import { ControlWrapper, } from './styles/focal-point-picker-style'; import { fractionToPercentage } from './utils'; +import type { + UnitControlProps, + UnitControlOnChangeCallback, +} from '../unit-control/types'; +import type { FocalPointAxis, FocalPointPickerControlsProps } from './types'; const TEXTCONTROL_MIN = 0; const TEXTCONTROL_MAX = 100; @@ -22,11 +27,16 @@ export default function FocalPointPickerControls( { x: 0.5, y: 0.5, }, -} ) { +}: FocalPointPickerControlsProps ) { const valueX = fractionToPercentage( point.x ); const valueY = fractionToPercentage( point.y ); - const handleChange = ( value, axis ) => { + const handleChange = ( + value: Parameters< UnitControlOnChangeCallback >[ 0 ], + axis: FocalPointAxis + ) => { + if ( value === undefined ) return; + const num = parseInt( value, 10 ); if ( ! isNaN( num ) ) { @@ -39,20 +49,32 @@ export default function FocalPointPickerControls( { handleChange( next, 'x' ) } + onChange={ + ( ( next ) => + handleChange( + next, + 'x' + ) ) as UnitControlOnChangeCallback + } dragDirection="e" /> handleChange( next, 'y' ) } + onChange={ + ( ( next ) => + handleChange( + next, + 'y' + ) ) as UnitControlOnChangeCallback + } dragDirection="s" /> ); } -function UnitControl( props ) { +function UnitControl( props: UnitControlProps ) { return ( ) { const classes = classnames( 'components-focal-point-picker__icon_container' ); diff --git a/packages/components/src/focal-point-picker/grid.tsx b/packages/components/src/focal-point-picker/grid.tsx index ed6d8ae51d0316..9b7ef9cff25f50 100644 --- a/packages/components/src/focal-point-picker/grid.tsx +++ b/packages/components/src/focal-point-picker/grid.tsx @@ -6,8 +6,13 @@ import { GridLineX, GridLineY, } from './styles/focal-point-picker-style'; +import type { FocalPointPickerGridProps } from './types'; +import type { WordPressComponentProps } from '../ui/context/wordpress-component'; -export default function FocalPointPickerGrid( { bounds, ...props } ) { +export default function FocalPointPickerGrid( { + bounds, + ...props +}: WordPressComponentProps< FocalPointPickerGridProps, 'div' > ) { return ( ) { const [ point, setPoint ] = useState( valueProp ); const [ showGridOverlay, setShowGridOverlay ] = useState( false ); const { startDrag, endDrag, isDragging } = useDragging( { onDragStart: ( event ) => { - dragAreaRef.current.focus(); + dragAreaRef.current?.focus(); const value = getValueWithinDragArea( event ); + if ( ! value ) return; onDragStart?.( value, event ); setPoint( value ); }, @@ -61,6 +69,7 @@ export default function FocalPointPicker( { // Prevents text-selection when dragging. event.preventDefault(); const value = getValueWithinDragArea( event ); + if ( ! value ) return; onDrag?.( value, event ); setPoint( value ); }, @@ -73,9 +82,11 @@ export default function FocalPointPicker( { // Uses the internal point while dragging or else the value from props. const { x, y } = isDragging ? point : valueProp; - const dragAreaRef = useRef(); + const dragAreaRef = useRef< HTMLDivElement >( null ); const [ bounds, setBounds ] = useState( INITIAL_BOUNDS ); const refUpdateBounds = useRef( () => { + if ( ! dragAreaRef.current ) return; + const { clientWidth: width, clientHeight: height } = dragAreaRef.current; // Falls back to initial bounds if the ref has no size. Since styles @@ -88,15 +99,27 @@ export default function FocalPointPicker( { useEffect( () => { const updateBounds = refUpdateBounds.current; + if ( ! dragAreaRef.current ) return; + const { defaultView } = dragAreaRef.current.ownerDocument; - defaultView.addEventListener( 'resize', updateBounds ); - return () => defaultView.removeEventListener( 'resize', updateBounds ); + defaultView?.addEventListener( 'resize', updateBounds ); + return () => defaultView?.removeEventListener( 'resize', updateBounds ); }, [] ); // Updates the bounds to cover cases of unspecified media or load failures. useIsomorphicLayoutEffect( () => void refUpdateBounds.current(), [] ); - const getValueWithinDragArea = ( { clientX, clientY, shiftKey } ) => { + const getValueWithinDragArea = ( { + clientX, + clientY, + shiftKey, + }: { + clientX: number; + clientY: number; + shiftKey: boolean; + } ) => { + if ( ! dragAreaRef.current ) return; + const { top, left } = dragAreaRef.current.getBoundingClientRect(); let nextX = ( clientX - left ) / bounds.width; let nextY = ( clientY - top ) / bounds.height; @@ -108,17 +131,22 @@ export default function FocalPointPicker( { return getFinalValue( { x: nextX, y: nextY } ); }; - const getFinalValue = ( value ) => { + const getFinalValue = ( value: FocalPointType ): FocalPointType => { const resolvedValue = resolvePoint?.( value ) ?? value; resolvedValue.x = Math.max( 0, Math.min( resolvedValue.x, 1 ) ); resolvedValue.y = Math.max( 0, Math.min( resolvedValue.y, 1 ) ); + const roundToTwoDecimalPlaces = ( n: number ) => + Math.round( n * 1e2 ) / 1e2; + return { - x: parseFloat( resolvedValue.x ).toFixed( 2 ), - y: parseFloat( resolvedValue.y ).toFixed( 2 ), + // @ts-expect-error: TODO: Is this parseFloat necessary? + x: roundToTwoDecimalPlaces( parseFloat( resolvedValue.x ) ), + // @ts-expect-error: TODO: Is this parseFloat necessary? + y: roundToTwoDecimalPlaces( parseFloat( resolvedValue.y ) ), }; }; - const arrowKeyStep = ( event ) => { + const arrowKeyStep: KeyboardEventHandler< HTMLDivElement > = ( event ) => { const { code, shiftKey } = event; if ( ! [ 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight' ].includes( @@ -133,6 +161,7 @@ export default function FocalPointPicker( { const delta = code === 'ArrowUp' || code === 'ArrowLeft' ? -1 * step : step; const axis = code === 'ArrowUp' || code === 'ArrowDown' ? 'y' : 'x'; + // @ts-expect-error: TODO: Is this parseFloat necessary? value[ axis ] = parseFloat( value[ axis ] ) + delta; onChange?.( getFinalValue( value ) ); }; @@ -161,6 +190,7 @@ export default function FocalPointPicker( { return ( = { title: 'Components/FocalPointPicker', component: FocalPointPicker, }; +export default meta; -const Example = ( props ) => { +const Template: ComponentStory< typeof FocalPointPicker > = ( props ) => { const [ focalPoint, setFocalPoint ] = useState( { x: 0.5, y: 0.5, @@ -20,41 +26,41 @@ const Example = ( props ) => { return ( ); }; -export const _default = () => { - return ; -}; - -export const image = () => { - const url = - 'https://i0.wp.com/themes.svn.wordpress.org/twentytwenty/1.3/screenshot.png?w=572&strip=al'; +export const Default = Template.bind( {} ); - return ; +export const Image = Template.bind( {} ); +Image.args = { + ...Default.args, + url: 'https://i0.wp.com/themes.svn.wordpress.org/twentytwenty/1.3/screenshot.png?w=572&strip=al', }; -export const video = () => { - const url = - 'https://interactive-examples.mdn.mozilla.net/media/examples/flower.webm'; - - return ; +export const Video = Template.bind( {} ); +Video.args = { + ...Default.args, + url: 'https://interactive-examples.mdn.mozilla.net/media/examples/flower.webm', }; -export const snapping = () => { - const snapValues = { - x: [ 0, 0.33, 0.66, 1 ], - y: [ 0, 0.33, 0.66, 1 ], - }; +export const Snapping = Template.bind( {} ); +Snapping.args = { + ...Default.args, + resolvePoint: ( value ) => { + const snapValues = { + x: [ 0, 0.33, 0.66, 1 ], + y: [ 0, 0.33, 0.66, 1 ], + }; - const threshold = 0.05; + const threshold = 0.05; - const maybeSnapFocalPoint = ( value ) => { + // @ts-expect-error: TODO: Is this parseFloat necessary? let x = parseFloat( value.x ); + // @ts-expect-error: TODO: Is this parseFloat necessary? let y = parseFloat( value.y ); snapValues.x.forEach( ( snapValue ) => { @@ -70,7 +76,5 @@ export const snapping = () => { } ); return { x, y }; - }; - - return ; + }, }; diff --git a/packages/components/src/focal-point-picker/styles/focal-point-picker-style.ts b/packages/components/src/focal-point-picker/styles/focal-point-picker-style.ts index 58fa3eb5de893b..1b50a75b13c59f 100644 --- a/packages/components/src/focal-point-picker/styles/focal-point-picker-style.ts +++ b/packages/components/src/focal-point-picker/styles/focal-point-picker-style.ts @@ -69,7 +69,8 @@ export const GridView = styled.div` transition: opacity 120ms linear; z-index: 1; - opacity: ${ ( { showOverlay } ) => ( showOverlay ? 1 : 0 ) }; + opacity: ${ ( { showOverlay }: { showOverlay?: boolean } ) => + showOverlay ? 1 : 0 }; `; export const GridLine = styled.div` diff --git a/packages/components/src/focal-point-picker/styles/focal-point-style.ts b/packages/components/src/focal-point-picker/styles/focal-point-style.ts index 89e248c986962c..0f46d7c5738574 100644 --- a/packages/components/src/focal-point-picker/styles/focal-point-style.ts +++ b/packages/components/src/focal-point-picker/styles/focal-point-style.ts @@ -25,7 +25,8 @@ export const FocalPointWrapper = styled.div` will-change: transform; z-index: 10000; - ${ ( { isDragging } ) => isDragging && 'cursor: grabbing;' } + ${ ( { isDragging }: { isDragging: boolean } ) => + isDragging && 'cursor: grabbing;' } `; export const PointerIconSVG = styled( SVG )` diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts new file mode 100644 index 00000000000000..9921f53eabdc16 --- /dev/null +++ b/packages/components/src/focal-point-picker/types.ts @@ -0,0 +1,84 @@ +/** + * External dependencies + */ +import type { + CSSProperties, + ReactEventHandler, + Ref, + VideoHTMLAttributes, +} from 'react'; + +/** + * Internal dependencies + */ +import type { BaseControlProps } from '../base-control/types'; + +export type FocalPoint = Record< FocalPointAxis, number >; +export type FocalPointAxis = 'x' | 'y'; + +export type FocalPointPickerProps = Pick< + BaseControlProps, + 'help' | 'hideLabelFromVision' | 'label' +> & { + /** + * Autoplays HTML5 video. This only applies to video sources (`url`). + * + * @default true + */ + autoPlay?: boolean; + /** + * Callback which is called when the focal point changes. + */ + onChange: ( value: FocalPoint ) => void; + onDrag?: ( value: FocalPoint, event: MouseEvent ) => void; + /** + * Callback which is called at the end of drag operations. + */ + onDragEnd?: ( event: MouseEvent ) => void; + /** + * Callback which is called at the start of drag operations. + */ + onDragStart?: ( + value: FocalPoint, + event: React.MouseEvent< Element, MouseEvent > + ) => void; + /** + * Function which is called before internal updates to the value state. + * It receives the upcoming value and may return a modified one. + */ + resolvePoint?: ( point: FocalPoint ) => FocalPoint | undefined; + /** + * URL of the image or video to be displayed. + */ + url: string; + /** + * The focal point. Should be an object containing `x` and `y` params. + */ + value: FocalPoint; +}; + +export type FocalPointPickerControlsProps = { + onChange?: ( value: FocalPoint ) => void; + point?: FocalPoint; +}; + +export type FocalPointPickerGridProps = { + bounds: { width: number; height: number }; + showOverlay?: boolean; +}; + +export type FocalPointPickerMediaProps = Pick< + VideoHTMLAttributes< HTMLVideoElement >, + 'autoPlay' | 'muted' +> & { + alt: string; + mediaRef?: Ref< any >; + onLoad?: ReactEventHandler< any >; + src: string; +}; + +export type FocalPointProps = { + isDragging: boolean; + left: CSSProperties[ 'left' ]; + top: CSSProperties[ 'left' ]; +}; diff --git a/packages/components/src/focal-point-picker/utils.ts b/packages/components/src/focal-point-picker/utils.ts index 2205ae4ad66c99..66776f038cf8fb 100644 --- a/packages/components/src/focal-point-picker/utils.ts +++ b/packages/components/src/focal-point-picker/utils.ts @@ -19,10 +19,10 @@ const VIDEO_EXTENSIONS = [ /** * Gets the extension of a file name. * - * @param {string} filename The file name. - * @return {string} The extension of the file name. + * @param filename The file name. + * @return The extension of the file name. */ -export function getExtension( filename = '' ) { +export function getExtension( filename = '' ): string { const parts = filename.split( '.' ); return parts[ parts.length - 1 ]; } @@ -30,10 +30,10 @@ export function getExtension( filename = '' ) { /** * Checks if a file is a video. * - * @param {string} filename The file name. - * @return {boolean} Whether the file is a video. + * @param filename The file name. + * @return Whether the file is a video. */ -export function isVideoType( filename = '' ) { +export function isVideoType( filename: string = '' ): boolean { if ( ! filename ) return false; return VIDEO_EXTENSIONS.includes( getExtension( filename ) ); } @@ -41,9 +41,9 @@ export function isVideoType( filename = '' ) { /** * Transforms a fraction value to a percentage value. * - * @param {number} fraction The fraction value. - * @return {number} A percentage value. + * @param fraction The fraction value. + * @return A percentage value. */ -export function fractionToPercentage( fraction ) { +export function fractionToPercentage( fraction: number ): number { return Math.round( fraction * 100 ); } diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index a896453cb3a56f..f60d4e1de236cd 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -50,7 +50,6 @@ "src/dimension-control", "src/drop-zone", "src/duotone-picker", - "src/focal-point-picker", "src/font-size-picker", "src/form-file-upload", "src/gradient-picker", diff --git a/packages/compose/src/hooks/use-dragging/index.js b/packages/compose/src/hooks/use-dragging/index.js index 357419a8c77e51..f1464df25d84b5 100644 --- a/packages/compose/src/hooks/use-dragging/index.js +++ b/packages/compose/src/hooks/use-dragging/index.js @@ -9,10 +9,10 @@ import { useCallback, useEffect, useRef, useState } from '@wordpress/element'; import useIsomorphicLayoutEffect from '../use-isomorphic-layout-effect'; /** - * @param {Object} props - * @param {(e: MouseEvent) => void} props.onDragStart - * @param {(e: MouseEvent) => void} props.onDragMove - * @param {(e: MouseEvent) => void} props.onDragEnd + * @param {Object} props + * @param {import('react').MouseEventHandler} props.onDragStart + * @param {(e: MouseEvent) => void} props.onDragMove + * @param {(e: MouseEvent) => void} props.onDragEnd */ export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { const [ isDragging, setIsDragging ] = useState( false ); @@ -34,15 +34,19 @@ export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { eventsRef.current.onDragMove( event ), [] ); - const endDrag = useCallback( ( /** @type {MouseEvent} */ event ) => { - if ( eventsRef.current.onDragEnd ) { - eventsRef.current.onDragEnd( event ); - } - document.removeEventListener( 'mousemove', onMouseMove ); - document.removeEventListener( 'mouseup', endDrag ); - setIsDragging( false ); - }, [] ); - const startDrag = useCallback( ( /** @type {MouseEvent} */ event ) => { + const endDrag = useCallback( + ( /** @type {MouseEvent=} */ event = undefined ) => { + if ( eventsRef.current.onDragEnd && event ) { + eventsRef.current.onDragEnd( event ); + } + document.removeEventListener( 'mousemove', onMouseMove ); + document.removeEventListener( 'mouseup', endDrag ); + setIsDragging( false ); + }, + [] + ); + /** @type {import('react').MouseEventHandler} */ + const startDrag = useCallback( ( event ) => { if ( eventsRef.current.onDragStart ) { eventsRef.current.onDragStart( event ); } From 7181b31bf590bb7c508e0faafa97e6b3b9b7e0a4 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Sun, 4 Sep 2022 18:48:24 +0900 Subject: [PATCH 03/17] Improve Storybook --- .../src/focal-point-picker/README.md | 4 +- .../src/focal-point-picker/index.tsx | 49 ++++++++++++++++++- .../src/focal-point-picker/stories/index.tsx | 17 ++++++- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/packages/components/src/focal-point-picker/README.md b/packages/components/src/focal-point-picker/README.md index c2483f01e6a4b1..4d8c1324328766 100644 --- a/packages/components/src/focal-point-picker/README.md +++ b/packages/components/src/focal-point-picker/README.md @@ -2,8 +2,8 @@ Focal Point Picker is a component which creates a UI for identifying the most important visual point of an image. This component addresses a specific problem: with large background images it is common to see undesirable crops, especially when viewing on smaller viewports such as mobile phones. This component allows the selection of the point with the most important visual information and returns it as a pair of numbers between 0 and 1. This value can be easily converted into the CSS `background-position` attribute, and will ensure that the focal point is never cropped out, regardless of viewport. -Example focal point picker value: `{ x: 0.5, y: 0.1 }` -Corresponding CSS: `background-position: 50% 10%;` +- Example focal point picker value: `{ x: 0.5, y: 0.1 }` +- Corresponding CSS: `background-position: 50% 10%;` ## Usage diff --git a/packages/components/src/focal-point-picker/index.tsx b/packages/components/src/focal-point-picker/index.tsx index 030400da2d3fe2..5d61ca8122c218 100644 --- a/packages/components/src/focal-point-picker/index.tsx +++ b/packages/components/src/focal-point-picker/index.tsx @@ -37,7 +37,52 @@ import type { KeyboardEventHandler } from 'react'; const GRID_OVERLAY_TIMEOUT = 600; -export default function FocalPointPicker( { +/** + * Focal Point Picker is a component which creates a UI for identifying the most important visual point of an image. + * + * This component addresses a specific problem: with large background images it is common to see undesirable crops, + * especially when viewing on smaller viewports such as mobile phones. This component allows the selection of + * the point with the most important visual information and returns it as a pair of numbers between 0 and 1. + * This value can be easily converted into the CSS `background-position` attribute, and will ensure that the + * focal point is never cropped out, regardless of viewport. + * + * - Example focal point picker value: `{ x: 0.5, y: 0.1 }` + * - Corresponding CSS: `background-position: 50% 10%;` + * + * ```jsx + * import { FocalPointPicker } from '@wordpress/components'; + * import { useState } from '@wordpress/element'; + * + * const Example = () => { + * const [ focalPoint, setFocalPoint ] = useState( { + * x: 0.5, + * y: 0.5, + * } ); + * + * const url = '/path/to/image'; + * + * // Example function to render the CSS styles based on Focal Point Picker value + * const style = { + * backgroundImage: `url(${ url })`, + * backgroundPosition: `${ focalPoint.x * 100 }% ${ focalPoint.y * 100 }%`, + * }; + * + * return ( + * <> + * + *
+ * + * ); + * }; + * ``` + */ +export function FocalPointPicker( { autoPlay = true, className, help, @@ -230,3 +275,5 @@ export default function FocalPointPicker( { ); } + +export default FocalPointPicker; diff --git a/packages/components/src/focal-point-picker/stories/index.tsx b/packages/components/src/focal-point-picker/stories/index.tsx index e97b4ce3bfaf60..27e271e786b653 100644 --- a/packages/components/src/focal-point-picker/stories/index.tsx +++ b/packages/components/src/focal-point-picker/stories/index.tsx @@ -15,10 +15,20 @@ import FocalPointPicker from '..'; const meta: ComponentMeta< typeof FocalPointPicker > = { title: 'Components/FocalPointPicker', component: FocalPointPicker, + argTypes: { + onChange: { action: 'onChange' }, + }, + parameters: { + controls: { expanded: true }, + docs: { source: { state: 'open' } }, + }, }; export default meta; -const Template: ComponentStory< typeof FocalPointPicker > = ( props ) => { +const Template: ComponentStory< typeof FocalPointPicker > = ( { + onChange, + ...props +} ) => { const [ focalPoint, setFocalPoint ] = useState( { x: 0.5, y: 0.5, @@ -28,7 +38,10 @@ const Template: ComponentStory< typeof FocalPointPicker > = ( props ) => { { + onChange( ...changeArgs ); + setFocalPoint( ...changeArgs ); + } } /> ); }; From 8c6606d9c3b8368e66314633ed23ff8ce3c08283 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 6 Sep 2022 04:53:01 +0900 Subject: [PATCH 04/17] Add changelog --- packages/components/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index d8a8147da0e9e0..b1055350e998a9 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -37,6 +37,7 @@ - Refactor `FocalPointPicker` to function component ([#39168](https://github.com/WordPress/gutenberg/pull/39168)). - `Guide`: use `code` instead of `keyCode` for keyboard events ([#43604](https://github.com/WordPress/gutenberg/pull/43604/)). - `ToggleControl`: Convert to TypeScript and streamline CSS ([#43717](https://github.com/WordPress/gutenberg/pull/43717)). +- `FocalPointPicker`: Convert to TypeScript ([#43872](https://github.com/WordPress/gutenberg/pull/43872)). - `Navigation`: use `code` instead of `keyCode` for keyboard events ([#43644](https://github.com/WordPress/gutenberg/pull/43644/)). - `ComboboxControl`: Add unit tests ([#42403](https://github.com/WordPress/gutenberg/pull/42403)). - `NavigableContainer`: use `code` instead of `keyCode` for keyboard events, rewrite tests using RTL and `user-event` ([#43606](https://github.com/WordPress/gutenberg/pull/43606/)). From ad368db92110f8ba681b8bcc61d69672885909ac Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 6 Sep 2022 04:25:19 +0900 Subject: [PATCH 05/17] Fix test import --- packages/components/src/focal-point-picker/test/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/focal-point-picker/test/index.js b/packages/components/src/focal-point-picker/test/index.js index 02ae72e3910133..3fb16db1ac3270 100644 --- a/packages/components/src/focal-point-picker/test/index.js +++ b/packages/components/src/focal-point-picker/test/index.js @@ -7,7 +7,7 @@ import userEvent from '@testing-library/user-event'; /** * Internal dependencies */ -import Picker from '../index.js'; +import Picker from '..'; describe( 'FocalPointPicker', () => { describe( 'focus and blur', () => { From 729e4807450f7f2ebc122096115034929b1ead2d Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 6 Sep 2022 04:40:26 +0900 Subject: [PATCH 06/17] Fix onDragEnd() types --- packages/components/src/focal-point-picker/index.tsx | 4 ++-- packages/components/src/focal-point-picker/types.ts | 2 +- packages/compose/src/hooks/use-dragging/index.js | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/components/src/focal-point-picker/index.tsx b/packages/components/src/focal-point-picker/index.tsx index 5d61ca8122c218..d69e6d6166e879 100644 --- a/packages/components/src/focal-point-picker/index.tsx +++ b/packages/components/src/focal-point-picker/index.tsx @@ -118,8 +118,8 @@ export function FocalPointPicker( { onDrag?.( value, event ); setPoint( value ); }, - onDragEnd: ( event ) => { - onDragEnd?.( event ); + onDragEnd: () => { + onDragEnd?.(); onChange?.( point ); }, } ); diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index 9921f53eabdc16..ac2143905f682f 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -34,7 +34,7 @@ export type FocalPointPickerProps = Pick< /** * Callback which is called at the end of drag operations. */ - onDragEnd?: ( event: MouseEvent ) => void; + onDragEnd?: () => void; /** * Callback which is called at the start of drag operations. */ diff --git a/packages/compose/src/hooks/use-dragging/index.js b/packages/compose/src/hooks/use-dragging/index.js index f1464df25d84b5..20cbf38cf77f8d 100644 --- a/packages/compose/src/hooks/use-dragging/index.js +++ b/packages/compose/src/hooks/use-dragging/index.js @@ -9,10 +9,10 @@ import { useCallback, useEffect, useRef, useState } from '@wordpress/element'; import useIsomorphicLayoutEffect from '../use-isomorphic-layout-effect'; /** - * @param {Object} props - * @param {import('react').MouseEventHandler} props.onDragStart - * @param {(e: MouseEvent) => void} props.onDragMove - * @param {(e: MouseEvent) => void} props.onDragEnd + * @param {Object} props + * @param {import('react').MouseEventHandler} props.onDragStart + * @param {(e: MouseEvent) => void} props.onDragMove + * @param {(e: MouseEvent | undefined) => void} props.onDragEnd */ export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { const [ isDragging, setIsDragging ] = useState( false ); @@ -36,7 +36,7 @@ export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { ); const endDrag = useCallback( ( /** @type {MouseEvent=} */ event = undefined ) => { - if ( eventsRef.current.onDragEnd && event ) { + if ( eventsRef.current.onDragEnd ) { eventsRef.current.onDragEnd( event ); } document.removeEventListener( 'mousemove', onMouseMove ); From 4404e590324d3ba532b5b6bb514cca1065bdfc79 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 02:19:51 +0900 Subject: [PATCH 07/17] Rename misleading `UnitControl` subcomponent --- .../components/src/focal-point-picker/controls.tsx | 10 +++++----- .../styles/focal-point-picker-style.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/components/src/focal-point-picker/controls.tsx b/packages/components/src/focal-point-picker/controls.tsx index 31669a077d795b..80cd6ad6a41511 100644 --- a/packages/components/src/focal-point-picker/controls.tsx +++ b/packages/components/src/focal-point-picker/controls.tsx @@ -7,7 +7,7 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { - UnitControl as BaseUnitControl, + StyledUnitControl, ControlWrapper, } from './styles/focal-point-picker-style'; import { fractionToPercentage } from './utils'; @@ -46,7 +46,7 @@ export default function FocalPointPickerControls( { return ( - - Date: Wed, 7 Sep 2022 02:28:25 +0900 Subject: [PATCH 08/17] Listen to all `on*` callbacks in Storybook --- packages/components/src/focal-point-picker/stories/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/components/src/focal-point-picker/stories/index.tsx b/packages/components/src/focal-point-picker/stories/index.tsx index 27e271e786b653..55663c6d07282b 100644 --- a/packages/components/src/focal-point-picker/stories/index.tsx +++ b/packages/components/src/focal-point-picker/stories/index.tsx @@ -15,10 +15,8 @@ import FocalPointPicker from '..'; const meta: ComponentMeta< typeof FocalPointPicker > = { title: 'Components/FocalPointPicker', component: FocalPointPicker, - argTypes: { - onChange: { action: 'onChange' }, - }, parameters: { + actions: { argTypesRegex: '^on.*' }, controls: { expanded: true }, docs: { source: { state: 'open' } }, }, From bfedb27b9224e377f0cf84fef4f5918896b492eb Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 02:42:48 +0900 Subject: [PATCH 09/17] Use prop types from FocalPointPickerMediaProps --- packages/components/src/focal-point-picker/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index ac2143905f682f..644e06d43a7bb3 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -25,7 +25,7 @@ export type FocalPointPickerProps = Pick< * * @default true */ - autoPlay?: boolean; + autoPlay?: FocalPointPickerMediaProps[ 'autoPlay' ]; /** * Callback which is called when the focal point changes. */ @@ -50,7 +50,7 @@ export type FocalPointPickerProps = Pick< /** * URL of the image or video to be displayed. */ - url: string; + url: FocalPointPickerMediaProps[ 'src' ]; /** * The focal point. Should be an object containing `x` and `y` params. */ From 5b9cd4de90091e80342b2dd681357b826697245d Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 02:45:31 +0900 Subject: [PATCH 10/17] Disallow undefined return from resolvePoint() --- packages/components/src/focal-point-picker/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index 644e06d43a7bb3..6cc9a5bf1c2e94 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -46,7 +46,7 @@ export type FocalPointPickerProps = Pick< * Function which is called before internal updates to the value state. * It receives the upcoming value and may return a modified one. */ - resolvePoint?: ( point: FocalPoint ) => FocalPoint | undefined; + resolvePoint?: ( point: FocalPoint ) => FocalPoint; /** * URL of the image or video to be displayed. */ From 4090caa8dda699b39cd0f2dc59b475f2e9391527 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 02:54:11 +0900 Subject: [PATCH 11/17] Better type `onLoad` --- packages/components/src/focal-point-picker/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index 6cc9a5bf1c2e94..9e72221c60cb43 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -73,7 +73,7 @@ export type FocalPointPickerMediaProps = Pick< > & { alt: string; mediaRef?: Ref< any >; - onLoad?: ReactEventHandler< any >; + onLoad?: ReactEventHandler< HTMLVideoElement | HTMLImageElement >; src: string; }; From 4a5f79c001b5a421c24a4da1aa8aa70d3ed003b4 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 02:54:54 +0900 Subject: [PATCH 12/17] Fix typo --- packages/components/src/focal-point-picker/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index 9e72221c60cb43..3092c07c51210f 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -80,5 +80,5 @@ export type FocalPointPickerMediaProps = Pick< export type FocalPointProps = { isDragging: boolean; left: CSSProperties[ 'left' ]; - top: CSSProperties[ 'left' ]; + top: CSSProperties[ 'top' ]; }; From 4736d157e15c32b2f9761825b21e4fbe9862e630 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 03:36:12 +0900 Subject: [PATCH 13/17] Fix useDragging types --- .../src/focal-point-picker/types.ts | 5 +-- .../compose/src/hooks/use-dragging/index.js | 35 ++++++++++--------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index 3092c07c51210f..9619f9a61c6e53 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -38,10 +38,7 @@ export type FocalPointPickerProps = Pick< /** * Callback which is called at the start of drag operations. */ - onDragStart?: ( - value: FocalPoint, - event: React.MouseEvent< Element, MouseEvent > - ) => void; + onDragStart?: ( value: FocalPoint, event: React.MouseEvent ) => void; /** * Function which is called before internal updates to the value state. * It receives the upcoming value and may return a modified one. diff --git a/packages/compose/src/hooks/use-dragging/index.js b/packages/compose/src/hooks/use-dragging/index.js index 20cbf38cf77f8d..1ef0b6fee1adc7 100644 --- a/packages/compose/src/hooks/use-dragging/index.js +++ b/packages/compose/src/hooks/use-dragging/index.js @@ -8,11 +8,13 @@ import { useCallback, useEffect, useRef, useState } from '@wordpress/element'; */ import useIsomorphicLayoutEffect from '../use-isomorphic-layout-effect'; +// Event handlers that are triggered from `document` listeners accept a MouseEvent, +// while those triggered from React listeners accept a React.MouseEvent. /** - * @param {Object} props - * @param {import('react').MouseEventHandler} props.onDragStart - * @param {(e: MouseEvent) => void} props.onDragMove - * @param {(e: MouseEvent | undefined) => void} props.onDragEnd + * @param {Object} props + * @param {(e: import('react').MouseEvent) => void} props.onDragStart + * @param {(e: MouseEvent) => void} props.onDragMove + * @param {(e?: MouseEvent) => void} props.onDragEnd */ export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { const [ isDragging, setIsDragging ] = useState( false ); @@ -28,24 +30,23 @@ export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { eventsRef.current.onDragEnd = onDragEnd; }, [ onDragStart, onDragMove, onDragEnd ] ); + /** @type {(e: MouseEvent) => void} */ const onMouseMove = useCallback( - ( /** @type {MouseEvent} */ event ) => + ( event ) => eventsRef.current.onDragMove && eventsRef.current.onDragMove( event ), [] ); - const endDrag = useCallback( - ( /** @type {MouseEvent=} */ event = undefined ) => { - if ( eventsRef.current.onDragEnd ) { - eventsRef.current.onDragEnd( event ); - } - document.removeEventListener( 'mousemove', onMouseMove ); - document.removeEventListener( 'mouseup', endDrag ); - setIsDragging( false ); - }, - [] - ); - /** @type {import('react').MouseEventHandler} */ + /** @type {(e?: MouseEvent) => void} */ + const endDrag = useCallback( ( event ) => { + if ( eventsRef.current.onDragEnd ) { + eventsRef.current.onDragEnd( event ); + } + document.removeEventListener( 'mousemove', onMouseMove ); + document.removeEventListener( 'mouseup', endDrag ); + setIsDragging( false ); + }, [] ); + /** @type {(e: import('react').MouseEvent) => void} */ const startDrag = useCallback( ( event ) => { if ( eventsRef.current.onDragStart ) { eventsRef.current.onDragStart( event ); From 6a226c82ed86217f956ae81fb1d1858ddde50628 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 03:47:11 +0900 Subject: [PATCH 14/17] Annotate `getValueWithinDragArea` complication --- packages/components/src/focal-point-picker/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/components/src/focal-point-picker/index.tsx b/packages/components/src/focal-point-picker/index.tsx index d69e6d6166e879..281cafcbbd4b4c 100644 --- a/packages/components/src/focal-point-picker/index.tsx +++ b/packages/components/src/focal-point-picker/index.tsx @@ -106,7 +106,11 @@ export function FocalPointPicker( { onDragStart: ( event ) => { dragAreaRef.current?.focus(); const value = getValueWithinDragArea( event ); + + // `value` can technically be undefined if getValueWithinDragArea() is + // called before dragAreaRef is set, but this shouldn't happen in reality. if ( ! value ) return; + onDragStart?.( value, event ); setPoint( value ); }, @@ -154,6 +158,8 @@ export function FocalPointPicker( { // Updates the bounds to cover cases of unspecified media or load failures. useIsomorphicLayoutEffect( () => void refUpdateBounds.current(), [] ); + // TODO: Consider refactoring getValueWithinDragArea() into a pure function. + // https://github.com/WordPress/gutenberg/pull/43872#discussion_r963455173 const getValueWithinDragArea = ( { clientX, clientY, From e23efc1d7f3530c60daae8cfa54437bd74d8aa8b Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 7 Sep 2022 04:37:09 +0900 Subject: [PATCH 15/17] Remove parseFloat calls --- .../src/focal-point-picker/index.tsx | 9 ++---- .../src/focal-point-picker/stories/index.tsx | 6 ++-- .../src/focal-point-picker/test/index.js | 32 +++++++++++++++---- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/components/src/focal-point-picker/index.tsx b/packages/components/src/focal-point-picker/index.tsx index 281cafcbbd4b4c..bf4107d51af50c 100644 --- a/packages/components/src/focal-point-picker/index.tsx +++ b/packages/components/src/focal-point-picker/index.tsx @@ -190,10 +190,8 @@ export function FocalPointPicker( { Math.round( n * 1e2 ) / 1e2; return { - // @ts-expect-error: TODO: Is this parseFloat necessary? - x: roundToTwoDecimalPlaces( parseFloat( resolvedValue.x ) ), - // @ts-expect-error: TODO: Is this parseFloat necessary? - y: roundToTwoDecimalPlaces( parseFloat( resolvedValue.y ) ), + x: roundToTwoDecimalPlaces( resolvedValue.x ), + y: roundToTwoDecimalPlaces( resolvedValue.y ), }; }; @@ -212,8 +210,7 @@ export function FocalPointPicker( { const delta = code === 'ArrowUp' || code === 'ArrowLeft' ? -1 * step : step; const axis = code === 'ArrowUp' || code === 'ArrowDown' ? 'y' : 'x'; - // @ts-expect-error: TODO: Is this parseFloat necessary? - value[ axis ] = parseFloat( value[ axis ] ) + delta; + value[ axis ] = value[ axis ] + delta; onChange?.( getFinalValue( value ) ); }; diff --git a/packages/components/src/focal-point-picker/stories/index.tsx b/packages/components/src/focal-point-picker/stories/index.tsx index 55663c6d07282b..7ef82c101b72cc 100644 --- a/packages/components/src/focal-point-picker/stories/index.tsx +++ b/packages/components/src/focal-point-picker/stories/index.tsx @@ -69,10 +69,8 @@ Snapping.args = { const threshold = 0.05; - // @ts-expect-error: TODO: Is this parseFloat necessary? - let x = parseFloat( value.x ); - // @ts-expect-error: TODO: Is this parseFloat necessary? - let y = parseFloat( value.y ); + let x = value.x; + let y = value.y; snapValues.x.forEach( ( snapValue ) => { if ( snapValue - threshold < x && x < snapValue + threshold ) { diff --git a/packages/components/src/focal-point-picker/test/index.js b/packages/components/src/focal-point-picker/test/index.js index 3fb16db1ac3270..b49985931050d1 100644 --- a/packages/components/src/focal-point-picker/test/index.js +++ b/packages/components/src/focal-point-picker/test/index.js @@ -112,9 +112,9 @@ describe( 'FocalPointPicker', () => { await user.keyboard( '[ArrowUp]' ); expect( spy ).toHaveBeenCalled(); - expect( spyChange ).toHaveBeenCalledWith( { - x: '0.91', - y: '0.42', + expect( spyChange ).toHaveBeenLastCalledWith( { + x: 0.91, + y: 0.42, } ); } ); } ); @@ -143,10 +143,30 @@ describe( 'FocalPointPicker', () => { await user.click( dragArea ); await user.keyboard( '[ArrowDown]' ); - expect( spyChange ).toHaveBeenCalledWith( { - x: '0.14', - y: '0.63', + expect( spyChange ).toHaveBeenLastCalledWith( { + x: 0.14, + y: 0.63, } ); } ); } ); + + describe( 'value handling', () => { + it( 'should handle legacy string values', () => { + const onChangeSpy = jest.fn(); + render( + + ); + + expect( + screen.getByRole( 'spinbutton', { name: 'Left' } ).value + ).toBe( '10' ); + expect( + screen.getByRole( 'spinbutton', { name: 'Top' } ).value + ).toBe( '20' ); + expect( onChangeSpy ).not.toHaveBeenCalled(); + } ); + } ); } ); From d354a6a48caa174298854e5bca5c1780ec992e8a Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Thu, 8 Sep 2022 21:21:21 +0900 Subject: [PATCH 16/17] Fixup control types --- packages/components/src/focal-point-picker/stories/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/src/focal-point-picker/stories/index.tsx b/packages/components/src/focal-point-picker/stories/index.tsx index 7ef82c101b72cc..a42185f3c1ffb5 100644 --- a/packages/components/src/focal-point-picker/stories/index.tsx +++ b/packages/components/src/focal-point-picker/stories/index.tsx @@ -15,6 +15,10 @@ import FocalPointPicker from '..'; const meta: ComponentMeta< typeof FocalPointPicker > = { title: 'Components/FocalPointPicker', component: FocalPointPicker, + argTypes: { + help: { control: 'text' }, + label: { control: 'text' }, + }, parameters: { actions: { argTypesRegex: '^on.*' }, controls: { expanded: true }, From f709d34152cf3381960ef7b2a1f2b65435ec03ea Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Thu, 8 Sep 2022 22:21:48 +0900 Subject: [PATCH 17/17] Cast mediaRef types --- packages/components/src/focal-point-picker/media.tsx | 11 ++++++++--- packages/components/src/focal-point-picker/types.ts | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/components/src/focal-point-picker/media.tsx b/packages/components/src/focal-point-picker/media.tsx index 113878167248e5..55ec6b510f6a70 100644 --- a/packages/components/src/focal-point-picker/media.tsx +++ b/packages/components/src/focal-point-picker/media.tsx @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import type { Ref } from 'react'; + /** * Internal dependencies */ @@ -20,7 +25,7 @@ export default function Media( { return ( } { ...props } /> ); @@ -36,7 +41,7 @@ export default function Media( { loop muted={ muted } onLoadedData={ onLoad } - ref={ mediaRef } + ref={ mediaRef as Ref< HTMLVideoElement > } src={ src } /> ) : ( @@ -45,7 +50,7 @@ export default function Media( { alt={ alt } className="components-focal-point-picker__media components-focal-point-picker__media--image" onLoad={ onLoad } - ref={ mediaRef } + ref={ mediaRef as Ref< HTMLImageElement > } src={ src } /> ); diff --git a/packages/components/src/focal-point-picker/types.ts b/packages/components/src/focal-point-picker/types.ts index 9619f9a61c6e53..89e632f9e0925b 100644 --- a/packages/components/src/focal-point-picker/types.ts +++ b/packages/components/src/focal-point-picker/types.ts @@ -69,7 +69,7 @@ export type FocalPointPickerMediaProps = Pick< 'autoPlay' | 'muted' > & { alt: string; - mediaRef?: Ref< any >; + mediaRef?: Ref< HTMLDivElement | HTMLVideoElement | HTMLImageElement >; onLoad?: ReactEventHandler< HTMLVideoElement | HTMLImageElement >; src: string; };