Skip to content

Commit d4cfbbb

Browse files
ramonjdandrewserong
authored andcommitted
Media editor: Remove initial state seeding from the session (WordPress#83893)
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
1 parent 446b460 commit d4cfbbb

8 files changed

Lines changed: 50 additions & 85 deletions

File tree

‎packages/media-editor/src/components/media-editor-crop-panel/test/index.jsdom.test.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ import { fireEvent, render, screen } from '@testing-library/react';
33
import MediaEditorCropPanel from '..';
44
import type { MediaEditorCropPanelProps } from '..';
55
import { MediaEditorStateProvider } from '../../../state';
6-
import type { CropperState } from '../../../image-editor';
76

87
globalThis.wpVitest.mockMatchMedia();
98

109
function setupCropPanel(
11-
overrides: Partial< MediaEditorCropPanelProps > = {},
12-
initialCropperState?: Partial< CropperState >
10+
overrides: Partial< MediaEditorCropPanelProps > = {}
1311
) {
1412
const props: MediaEditorCropPanelProps = {
1513
aspectRatioValue: '1',
@@ -23,7 +21,7 @@ function setupCropPanel(
2321
};
2422

2523
render(
26-
<MediaEditorStateProvider initialCropperState={ initialCropperState }>
24+
<MediaEditorStateProvider>
2725
<MediaEditorCropPanel { ...props } />
2826
</MediaEditorStateProvider>
2927
);

‎packages/media-editor/src/components/media-editor-image-controls/test/index.jsdom.test.tsx‎

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,32 @@
11
import { describe, expect, it } from 'vitest';
22
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
3-
import { useState } from '@wordpress/element';
3+
import { useEffect, useState } from '@wordpress/element';
44
import MediaEditorImageControls from '..';
55
import type { MediaEditorImageControlsProps } from '..';
66
import { MediaEditorStateProvider, useMediaEditor } from '../../../state';
7-
import type { CropperState } from '../../../image-editor';
87
import { MAX_ZOOM } from '../../../image-editor/core/constants';
98

10-
function setup(
11-
props: MediaEditorImageControlsProps = {},
12-
initialCropperState?: Partial< CropperState >
13-
) {
9+
function setup( props: MediaEditorImageControlsProps = {}, zoom?: number ) {
1410
render(
15-
<MediaEditorStateProvider initialCropperState={ initialCropperState }>
11+
<MediaEditorStateProvider>
1612
<MediaEditorImageControls { ...props } />
17-
<CurrentState />
13+
<CurrentState zoom={ zoom } />
1814
</MediaEditorStateProvider>
1915
);
2016
}
2117

22-
function CurrentState() {
18+
function CurrentState( { zoom }: { zoom?: number } ) {
2319
const {
24-
cropper: { state },
20+
cropper: { state, setZoom },
2521
cropOptions,
2622
} = useMediaEditor();
23+
// Start the cases that need it zoomed in. `setZoom` is a session edit,
24+
// so these cases begin with one undo entry; none of them checks history.
25+
useEffect( () => {
26+
if ( zoom !== undefined ) {
27+
setZoom( zoom );
28+
}
29+
}, [ setZoom, zoom ] );
2730

2831
return (
2932
<>
@@ -75,7 +78,7 @@ describe( 'MediaEditorImageControls', () => {
7578
} );
7679

7780
it( 'zoom in multiplies the zoom and zoom out divides it', () => {
78-
setup( {}, { zoom: 2 } );
81+
setup( {}, 2 );
7982

8083
fireEvent.click( screen.getByRole( 'button', { name: 'Zoom in' } ) );
8184
const zoomedIn = Number(
@@ -90,7 +93,7 @@ describe( 'MediaEditorImageControls', () => {
9093
} );
9194

9295
it( 'honors a custom zoomFactor', () => {
93-
setup( { zoomFactor: 2 }, { zoom: 2 } );
96+
setup( { zoomFactor: 2 }, 2 );
9497

9598
fireEvent.click( screen.getByRole( 'button', { name: 'Zoom in' } ) );
9699

@@ -101,7 +104,7 @@ describe( 'MediaEditorImageControls', () => {
101104
} );
102105

103106
it( 'disables Zoom in at the maximum zoom', () => {
104-
setup( {}, { zoom: MAX_ZOOM } );
107+
setup( {}, MAX_ZOOM );
105108
// Buttons use `accessibleWhenDisabled`, so the disabled state is
106109
// expressed via aria-disabled, not the `disabled` attribute.
107110
expect(

‎packages/media-editor/src/components/media-editor/test/use-crop-options.jsdom.test.tsx‎

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import { describe, expect, it } from 'vitest';
22
import { fireEvent, render, screen } from '@testing-library/react';
3+
import { useEffect } from '@wordpress/element';
34
import { useCropOptions } from '../use-crop-options';
45
import { ORIGINAL_ASPECT_RATIO } from '../../../image-editor/core/constants';
5-
import { MediaEditorStateProvider } from '../../../state';
6+
import { MediaEditorStateProvider, useMediaEditor } from '../../../state';
7+
8+
const IMAGE = {
9+
src: 'test.jpg',
10+
naturalWidth: 1200,
11+
naturalHeight: 600,
12+
};
613

714
function CropOptionsHarness() {
15+
// Load the image through the session, as the canvas does.
16+
const { setSourceImage } = useMediaEditor();
17+
useEffect( () => setSourceImage( IMAGE ), [ setSourceImage ] );
818
const cropOptions = useCropOptions( {
919
aspectRatioPresets: [
1020
{ label: 'Square', value: 1 },
@@ -47,15 +57,7 @@ function CropOptionsHarness() {
4757

4858
function renderHarness() {
4959
render(
50-
<MediaEditorStateProvider
51-
initialCropperState={ {
52-
image: {
53-
src: 'test.jpg',
54-
naturalWidth: 1200,
55-
naturalHeight: 600,
56-
},
57-
} }
58-
>
60+
<MediaEditorStateProvider>
5961
<CropOptionsHarness />
6062
</MediaEditorStateProvider>
6163
);

‎packages/media-editor/src/state/composite-reducer.ts‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,18 +117,17 @@ export function areMediaEditorStatesEqual(
117117
}
118118

119119
/**
120-
* Build the initial composite state from optional partial overrides.
120+
* Build the composite state a session starts from: the given cropper
121+
* slice and default crop options.
121122
*
122-
* @param initialCropper Initial cropper-slice fields to merge.
123-
* @param initialOptions Initial cropOptions-slice fields to merge.
123+
* @param cropper The cropper slice.
124124
* @return Composite initial state.
125125
*/
126126
export function buildInitialMediaEditorState(
127-
initialCropper: CropperState,
128-
initialOptions?: Partial< CropOptionsSlice >
127+
cropper: CropperState
129128
): MediaEditorState {
130129
return {
131-
cropper: initialCropper,
132-
cropOptions: { ...DEFAULT_CROP_OPTIONS, ...initialOptions },
130+
cropper,
131+
cropOptions: { ...DEFAULT_CROP_OPTIONS },
133132
};
134133
}

‎packages/media-editor/src/state/media-editor-state-provider.tsx‎

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import { createContext, useContext } from '@wordpress/element';
2-
import type { CropperState } from '../image-editor';
32
import {
43
useMediaEditorState,
54
type MediaEditorSession,
65
} from './use-media-editor-state';
7-
import type { CropOptionsSlice } from './types';
86

97
const MediaEditorStateContext = createContext< MediaEditorSession | null >(
108
null
119
);
1210

1311
interface MediaEditorStateProviderProps {
14-
/** Optional cropper-slice initial state. */
15-
initialCropperState?: Partial< CropperState >;
16-
/** Optional cropOptions-slice initial state. */
17-
initialCropOptions?: Partial< CropOptionsSlice >;
1812
/** Child components. */
1913
children: React.ReactNode;
2014
}
@@ -25,19 +19,12 @@ interface MediaEditorStateProviderProps {
2519
* sidebar) reads from the same store.
2620
*
2721
* @param props
28-
* @param props.initialCropperState
29-
* @param props.initialCropOptions
3022
* @param props.children
3123
*/
3224
export function MediaEditorStateProvider( {
33-
initialCropperState,
34-
initialCropOptions,
3525
children,
3626
}: MediaEditorStateProviderProps ) {
37-
const controller = useMediaEditorState( {
38-
cropper: initialCropperState,
39-
cropOptions: initialCropOptions,
40-
} );
27+
const controller = useMediaEditorState();
4128

4229
return (
4330
<MediaEditorStateContext.Provider value={ controller }>

‎packages/media-editor/src/state/test/use-media-editor-state.browser.test.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ function CropperWithHistory( {
2525
}: {
2626
onController: ( controller: MediaEditorSession ) => void;
2727
} ) {
28-
const controller = useMediaEditorState( { cropper: { image: IMAGE } } );
28+
const controller = useMediaEditorState();
29+
const { setSourceImage } = controller;
30+
useEffect( () => setSourceImage( IMAGE ), [ setSourceImage ] );
2931
useEffect( () => onController( controller ), [ controller, onController ] );
3032
return (
3133
<div style={ { width: 648, height: 448 } }>

‎packages/media-editor/src/state/test/use-media-editor-state.jsdom.test.ts‎

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ const IMAGE = {
88
naturalHeight: 600,
99
};
1010

11+
// Loading the image through the session, as the canvas does, so the
12+
// baseline and history start from the loaded image.
1113
function setupHook( visualSize = { width: 600, height: 400 } ) {
12-
const view = renderHook( () =>
13-
useMediaEditorState( { cropper: { image: IMAGE } } )
14-
);
14+
const view = renderHook( () => useMediaEditorState() );
1515
act( () => {
16+
view.result.current.setSourceImage( IMAGE );
1617
view.result.current.cropper.setVisualSize( visualSize );
1718
} );
1819
return view;
@@ -26,20 +27,6 @@ describe( 'useMediaEditorState', () => {
2627
expect( result.current.cropOptions.aspectRatioValue ).toBe( '0' );
2728
} );
2829

29-
it( 'merges initial cropper and cropOptions overrides', () => {
30-
const { result } = renderHook( () =>
31-
useMediaEditorState( {
32-
cropper: { image: IMAGE },
33-
cropOptions: { aspectRatioValue: '1' },
34-
} )
35-
);
36-
37-
expect( result.current.cropper.state.image ).toEqual( IMAGE );
38-
expect( result.current.cropOptions ).toEqual( {
39-
aspectRatioValue: '1',
40-
} );
41-
} );
42-
4330
it( 'starts with isDirty=false and no undo / redo', () => {
4431
const { result } = setupHook();
4532

@@ -54,9 +41,8 @@ describe( 'useMediaEditorState', () => {
5441
it( 'counts an aspect-ratio preset change as a session edit only', () => {
5542
// No visual size is reported, so picking a ratio changes the
5643
// preset without reshaping the crop.
57-
const { result } = renderHook( () =>
58-
useMediaEditorState( { cropper: { image: IMAGE } } )
59-
);
44+
const { result } = renderHook( () => useMediaEditorState() );
45+
act( () => result.current.setSourceImage( IMAGE ) );
6046

6147
act( () => result.current.setAspectRatioValue( '1' ) );
6248

‎packages/media-editor/src/state/use-media-editor-state.ts‎

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,6 @@ export interface MediaEditorSession {
139139
endGesture: () => void;
140140
}
141141

142-
interface InitialMediaEditorState {
143-
cropper?: Partial< CropperState >;
144-
cropOptions?: Partial< CropOptionsSlice >;
145-
}
146-
147142
/**
148143
* The media editor session.
149144
*
@@ -166,20 +161,13 @@ interface InitialMediaEditorState {
166161
* state. Use `hasOutputEdits` when deciding whether the image output
167162
* needs saving.
168163
*
169-
* @param initialState Optional seed for the cropper and cropOptions slices.
164+
* The session starts empty. Call `setSourceImage` to load an image.
165+
*
170166
* @return The media editor session.
171167
*/
172-
export function useMediaEditorState(
173-
initialState?: InitialMediaEditorState
174-
): MediaEditorSession {
168+
export function useMediaEditorState(): MediaEditorSession {
175169
const [ state, dispatch ] = useReducer( mediaEditorReducer, null, () =>
176-
buildInitialMediaEditorState(
177-
enforceContainment( {
178-
...DEFAULT_STATE,
179-
...initialState?.cropper,
180-
} ),
181-
initialState?.cropOptions
182-
)
170+
buildInitialMediaEditorState( { ...DEFAULT_STATE } )
183171
);
184172

185173
// The "clean" snapshot the current state is compared against for

0 commit comments

Comments
 (0)