1- import type { PayloadAction , Selector } from '@reduxjs/toolkit' ;
2- import { createSelector , createSlice } from '@reduxjs/toolkit' ;
1+ import type { PayloadAction , Selector , UnknownAction } from '@reduxjs/toolkit' ;
2+ import { createSelector , createSlice , isAnyOf } from '@reduxjs/toolkit' ;
33import type { RootState } from 'app/store/store' ;
44import type { SliceConfig } from 'app/store/types' ;
55import { isPlainObject } from 'es-toolkit' ;
@@ -18,7 +18,7 @@ import {
1818const zAutoSwitchMode = z . enum ( [ 'off' , 'switch_on_start' , 'switch_on_finish' ] ) ;
1919export type AutoSwitchMode = z . infer < typeof zAutoSwitchMode > ;
2020
21- const zCanvasSharedSettingsState = z . object ( {
21+ const zCanvasSharedSettings = z . object ( {
2222 /**
2323 * Whether to show HUD (Heads-Up Display) on the canvas.
2424 */
@@ -89,9 +89,9 @@ const zCanvasSharedSettingsState = z.object({
8989 */
9090 stagingAreaAutoSwitch : zAutoSwitchMode ,
9191} ) ;
92- type CanvasSharedSettingsState = z . infer < typeof zCanvasSharedSettingsState > ;
92+ type CanvasSharedSettings = z . infer < typeof zCanvasSharedSettings > ;
9393
94- const zCanvasInstanceSettingsState = z . object ( {
94+ const zCanvasInstanceSettings = z . object ( {
9595 canvasId : z . string ( ) ,
9696 /**
9797 * The width of the brush tool.
@@ -108,16 +108,16 @@ const zCanvasInstanceSettingsState = z.object({
108108 bgColor : zRgbaColor ,
109109 fgColor : zRgbaColor ,
110110} ) ;
111- type CanvasInstanceSettingsState = z . infer < typeof zCanvasInstanceSettingsState > ;
111+ type CanvasInstanceSettings = z . infer < typeof zCanvasInstanceSettings > ;
112112
113113const zCanvasSettingsState = z . object ( {
114114 _version : z . literal ( 1 ) ,
115- shared : zCanvasSharedSettingsState ,
116- canvases : z . array ( zCanvasInstanceSettingsState ) ,
115+ shared : zCanvasSharedSettings ,
116+ canvases : z . record ( z . string ( ) , zCanvasInstanceSettings ) ,
117117} ) ;
118118type CanvasSettingsState = z . infer < typeof zCanvasSettingsState > ;
119119
120- const getInitialCanvasSharedSettingsState = ( ) : CanvasSharedSettingsState => ( {
120+ const getInitialCanvasSharedSettings = ( ) : CanvasSharedSettings => ( {
121121 showHUD : true ,
122122 clipToBbox : false ,
123123 dynamicGrid : false ,
@@ -135,26 +135,26 @@ const getInitialCanvasSharedSettingsState = (): CanvasSharedSettingsState => ({
135135 saveAllImagesToGallery : false ,
136136 stagingAreaAutoSwitch : 'switch_on_start' ,
137137} ) ;
138- const getInitialCanvasInstanceSettingsState = ( canvasId : string ) : CanvasInstanceSettingsState => ( {
138+ const getInitialCanvasInstanceSettings = ( canvasId : string ) : CanvasInstanceSettings => ( {
139139 canvasId,
140140 brushWidth : 50 ,
141141 eraserWidth : 50 ,
142142 activeColor : 'fgColor' ,
143143 bgColor : RGBA_BLACK ,
144144 fgColor : RGBA_WHITE ,
145145} ) ;
146- const getInitialState = ( ) : CanvasSettingsState => ( {
146+ const getInitialCanvasSettingsState = ( ) : CanvasSettingsState => ( {
147147 _version : 1 ,
148- shared : getInitialCanvasSharedSettingsState ( ) ,
149- canvases : [ ] ,
148+ shared : getInitialCanvasSharedSettings ( ) ,
149+ canvases : { } ,
150150} ) ;
151151
152- type CanvasPayload < T > = { canvasId : string } & T ;
153- type CanvasPayloadAction < T > = PayloadAction < CanvasPayload < T > > ;
152+ type PayloadWithCanvasId < P > = P & { canvasId : string } ;
153+ type CanvasPayloadAction < P > = PayloadAction < PayloadWithCanvasId < P > > ;
154154
155- const slice = createSlice ( {
155+ const canvasSettingsSlice = createSlice ( {
156156 name : 'canvasSettings' ,
157- initialState : getInitialState ( ) ,
157+ initialState : getInitialCanvasSettingsState ( ) ,
158158 reducers : {
159159 settingsClipToBboxChanged : ( state , action : PayloadAction < { clipToBbox : boolean } > ) => {
160160 const { clipToBbox } = action . payload ;
@@ -167,67 +167,6 @@ const slice = createSlice({
167167 settingsShowHUDToggled : ( state ) => {
168168 state . shared . showHUD = ! state . shared . showHUD ;
169169 } ,
170- settingsBrushWidthChanged : ( state , action : CanvasPayloadAction < { brushWidth : number } > ) => {
171- const { canvasId, brushWidth } = action . payload ;
172-
173- const settings = state . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
174- if ( ! settings ) {
175- return ;
176- }
177-
178- settings . brushWidth = Math . round ( brushWidth ) ;
179- } ,
180- settingsEraserWidthChanged : ( state , action : CanvasPayloadAction < { eraserWidth : number } > ) => {
181- const { canvasId, eraserWidth } = action . payload ;
182-
183- const settings = state . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
184- if ( ! settings ) {
185- return ;
186- }
187-
188- settings . eraserWidth = Math . round ( eraserWidth ) ;
189- } ,
190- settingsActiveColorToggled : ( state , action : CanvasPayloadAction < unknown > ) => {
191- const { canvasId } = action . payload ;
192-
193- const settings = state . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
194- if ( ! settings ) {
195- return ;
196- }
197-
198- settings . activeColor = settings . activeColor === 'bgColor' ? 'fgColor' : 'bgColor' ;
199- } ,
200- settingsBgColorChanged : ( state , action : CanvasPayloadAction < { bgColor : Partial < RgbaColor > } > ) => {
201- const { canvasId, bgColor } = action . payload ;
202-
203- const settings = state . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
204- if ( ! settings ) {
205- return ;
206- }
207-
208- settings . bgColor = { ...settings . bgColor , ...bgColor } ;
209- } ,
210- settingsFgColorChanged : ( state , action : CanvasPayloadAction < { fgColor : Partial < RgbaColor > } > ) => {
211- const { canvasId, fgColor } = action . payload ;
212-
213- const settings = state . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
214- if ( ! settings ) {
215- return ;
216- }
217-
218- settings . fgColor = { ...settings . fgColor , ...fgColor } ;
219- } ,
220- settingsColorsSetToDefault : ( state , action : CanvasPayloadAction < unknown > ) => {
221- const { canvasId } = action . payload ;
222-
223- const settings = state . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
224- if ( ! settings ) {
225- return ;
226- }
227-
228- settings . bgColor = RGBA_BLACK ;
229- settings . fgColor = RGBA_WHITE ;
230- } ,
231170 settingsInvertScrollForToolWidthChanged : ( state , action : PayloadAction < { invertScrollForToolWidth : boolean } > ) => {
232171 const { invertScrollForToolWidth } = action . payload ;
233172
@@ -268,7 +207,7 @@ const slice = createSlice({
268207 } ,
269208 settingsStagingAreaAutoSwitchChanged : (
270209 state ,
271- action : PayloadAction < { stagingAreaAutoSwitch : CanvasSharedSettingsState [ 'stagingAreaAutoSwitch' ] } >
210+ action : PayloadAction < { stagingAreaAutoSwitch : CanvasSharedSettings [ 'stagingAreaAutoSwitch' ] } >
272211 ) => {
273212 const { stagingAreaAutoSwitch } = action . payload ;
274213
@@ -277,32 +216,62 @@ const slice = createSlice({
277216 } ,
278217 extraReducers ( builder ) {
279218 builder . addCase ( canvasCreated , ( state , action ) => {
280- const canvasSettings = getInitialCanvasInstanceSettingsState ( action . payload . canvasId ) ;
281- state . canvases . push ( canvasSettings ) ;
219+ const canvasSettings = getInitialCanvasInstanceSettings ( action . payload . canvasId ) ;
220+ state . canvases [ canvasSettings . canvasId ] = canvasSettings ;
282221 } ) ;
283222 builder . addCase ( canvasRemoved , ( state , action ) => {
284- state . canvases = state . canvases . filter ( ( settings ) => settings . canvasId !== action . payload . canvasId ) ;
223+ delete state . canvases [ action . payload . canvasId ] ;
285224 } ) ;
286225 builder . addCase ( canvasMultiCanvasMigrated , ( state , action ) => {
287- const settings = state . canvases . find ( ( settings ) => settings . canvasId === MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER ) ;
226+ const settings = state . canvases [ MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER ] ;
288227 if ( ! settings ) {
289228 return ;
290229 }
291230 settings . canvasId = action . payload . canvasId ;
231+ state . canvases [ settings . canvasId ] = settings ;
232+ delete state . canvases [ MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER ] ;
292233 } ) ;
293234 } ,
294235} ) ;
295236
237+ const canvasInstanceSettingsSlice = createSlice ( {
238+ name : 'canvasSettings' ,
239+ initialState : { } as CanvasInstanceSettings ,
240+ reducers : {
241+ settingsBrushWidthChanged : ( state , action : CanvasPayloadAction < { brushWidth : number } > ) => {
242+ const { brushWidth } = action . payload ;
243+
244+ state . brushWidth = Math . round ( brushWidth ) ;
245+ } ,
246+ settingsEraserWidthChanged : ( state , action : CanvasPayloadAction < { eraserWidth : number } > ) => {
247+ const { eraserWidth } = action . payload ;
248+
249+ state . eraserWidth = Math . round ( eraserWidth ) ;
250+ } ,
251+ settingsActiveColorToggled : ( state , _action : CanvasPayloadAction < unknown > ) => {
252+ state . activeColor = state . activeColor === 'bgColor' ? 'fgColor' : 'bgColor' ;
253+ } ,
254+ settingsBgColorChanged : ( state , action : CanvasPayloadAction < { bgColor : Partial < RgbaColor > } > ) => {
255+ const { bgColor } = action . payload ;
256+
257+ state . bgColor = { ...state . bgColor , ...bgColor } ;
258+ } ,
259+ settingsFgColorChanged : ( state , action : CanvasPayloadAction < { fgColor : Partial < RgbaColor > } > ) => {
260+ const { fgColor } = action . payload ;
261+
262+ state . fgColor = { ...state . fgColor , ...fgColor } ;
263+ } ,
264+ settingsColorsSetToDefault : ( state , _action : CanvasPayloadAction < unknown > ) => {
265+ state . bgColor = RGBA_BLACK ;
266+ state . fgColor = RGBA_WHITE ;
267+ } ,
268+ } ,
269+ } ) ;
270+
296271export const {
297272 settingsClipToBboxChanged,
298273 settingsDynamicGridToggled,
299274 settingsShowHUDToggled,
300- settingsBrushWidthChanged,
301- settingsEraserWidthChanged,
302- settingsActiveColorToggled,
303- settingsBgColorChanged,
304- settingsFgColorChanged,
305- settingsColorsSetToDefault,
306275 settingsInvertScrollForToolWidthChanged,
307276 settingsOutputOnlyMaskedRegionsToggled,
308277 settingsAutoProcessToggled,
@@ -316,28 +285,57 @@ export const {
316285 settingsRuleOfThirdsToggled,
317286 settingsSaveAllImagesToGalleryToggled,
318287 settingsStagingAreaAutoSwitchChanged,
319- } = slice . actions ;
288+ } = canvasSettingsSlice . actions ;
289+
290+ export const {
291+ settingsBrushWidthChanged,
292+ settingsEraserWidthChanged,
293+ settingsActiveColorToggled,
294+ settingsBgColorChanged,
295+ settingsFgColorChanged,
296+ settingsColorsSetToDefault,
297+ } = canvasInstanceSettingsSlice . actions ;
298+
299+ const isCanvasInstanceSettingsAction = isAnyOf ( ...Object . values ( canvasInstanceSettingsSlice . actions ) ) ;
300+
301+ export const canvasSettingsReducer = ( state : CanvasSettingsState , action : UnknownAction ) : CanvasSettingsState => {
302+ state = canvasSettingsSlice . reducer ( state , action ) ;
320303
321- export const canvasSettingsSliceConfig : SliceConfig < typeof slice > = {
322- slice,
304+ if ( ! isCanvasInstanceSettingsAction ( action ) ) {
305+ return state ;
306+ }
307+
308+ const canvasId = action . payload . canvasId ;
309+
310+ return {
311+ ...state ,
312+ canvases : {
313+ ...state . canvases ,
314+ [ canvasId ] : canvasInstanceSettingsSlice . reducer ( state . canvases [ canvasId ] , action ) ,
315+ } ,
316+ } ;
317+ } ;
318+
319+ export const canvasSettingsSliceConfig : SliceConfig < typeof canvasSettingsSlice > = {
320+ slice : canvasSettingsSlice ,
323321 schema : zCanvasSettingsState ,
324- getInitialState,
322+ getInitialState : getInitialCanvasSettingsState ,
325323 persistConfig : {
326324 migrate : ( state ) => {
327325 assert ( isPlainObject ( state ) ) ;
328326 if ( ! ( '_version' in state ) ) {
329327 // Migrate from v1: slice represented a canvas settings instance -> slice represents multiple canvas settings instances
330- const canvas = {
328+ const settings = {
331329 canvasId : MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER ,
332330 ...state ,
333- } as CanvasInstanceSettingsState ;
331+ } as CanvasInstanceSettings ;
334332
335333 state = {
336334 _version : 1 ,
337335 shared : {
338336 ...state ,
339337 } ,
340- canvases : [ canvas ] ,
338+ canvases : { [ settings . canvasId ] : settings } ,
341339 } ;
342340 }
343341
@@ -359,52 +357,42 @@ export const buildSelectCanvasSettingsByCanvasId = (canvasId: string) =>
359357 ) ;
360358const selectCanvasSharedSettings = ( state : RootState ) => state . canvasSettings . shared ;
361359const selectCanvasInstanceSettings = ( state : RootState , canvasId : string ) => {
362- const settings = state . canvasSettings . canvases . find ( ( settings ) => settings . canvasId === canvasId ) ;
360+ const settings = state . canvasSettings . canvases [ canvasId ] ;
363361 assert ( settings , 'Settings must exist for a canvas once the canvas has been created' ) ;
364362 return settings ;
365363} ;
366364
367365const buildCanvasSharedSettingsSelector =
368- < T > ( selector : Selector < CanvasSharedSettingsState , T > ) =>
366+ < T > ( selector : Selector < CanvasSharedSettings , T > ) =>
369367 ( state : RootState ) =>
370368 selector ( selectCanvasSharedSettings ( state ) ) ;
371369const buildCanvasInstanceSettingsSelector =
372- < T > ( selector : Selector < CanvasInstanceSettingsState , T > ) =>
370+ < T > ( selector : Selector < CanvasInstanceSettings , T > ) =>
373371 ( state : RootState , canvasId : string ) =>
374372 selector ( selectCanvasInstanceSettings ( state , canvasId ) ) ;
375373
376- export const selectPreserveMask = buildCanvasSharedSettingsSelector ( ( settings ) => settings . preserveMask ) ;
374+ export const selectPreserveMask = buildCanvasSharedSettingsSelector ( ( state ) => state . preserveMask ) ;
377375export const selectOutputOnlyMaskedRegions = buildCanvasSharedSettingsSelector (
378- ( settings ) => settings . outputOnlyMaskedRegions
376+ ( state ) => state . outputOnlyMaskedRegions
379377) ;
380- export const selectDynamicGrid = buildCanvasSharedSettingsSelector ( ( settings ) => settings . dynamicGrid ) ;
378+ export const selectDynamicGrid = buildCanvasSharedSettingsSelector ( ( state ) => state . dynamicGrid ) ;
381379export const selectInvertScrollForToolWidth = buildCanvasSharedSettingsSelector (
382- ( settings ) => settings . invertScrollForToolWidth
383- ) ;
384- export const selectBboxOverlay = buildCanvasSharedSettingsSelector ( ( settings ) => settings . bboxOverlay ) ;
385- export const selectShowHUD = buildCanvasSharedSettingsSelector ( ( settings ) => settings . showHUD ) ;
386- export const selectClipToBbox = buildCanvasSharedSettingsSelector ( ( settings ) => settings . clipToBbox ) ;
387- export const selectAutoProcess = buildCanvasSharedSettingsSelector ( ( settings ) => settings . autoProcess ) ;
388- export const selectSnapToGrid = buildCanvasSharedSettingsSelector ( ( settings ) => settings . snapToGrid ) ;
389- export const selectShowProgressOnCanvas = buildCanvasSharedSettingsSelector (
390- ( settings ) => settings . showProgressOnCanvas
391- ) ;
392- export const selectIsolatedStagingPreview = buildCanvasSharedSettingsSelector (
393- ( settings ) => settings . isolatedStagingPreview
394- ) ;
395- export const selectIsolatedLayerPreview = buildCanvasSharedSettingsSelector (
396- ( settings ) => settings . isolatedLayerPreview
397- ) ;
398- export const selectPressureSensitivity = buildCanvasSharedSettingsSelector ( ( settings ) => settings . pressureSensitivity ) ;
399- export const selectRuleOfThirds = buildCanvasSharedSettingsSelector ( ( settings ) => settings . ruleOfThirds ) ;
400- export const selectSaveAllImagesToGallery = buildCanvasSharedSettingsSelector (
401- ( settings ) => settings . saveAllImagesToGallery
402- ) ;
403- export const selectStagingAreaAutoSwitch = buildCanvasSharedSettingsSelector (
404- ( settings ) => settings . stagingAreaAutoSwitch
380+ ( state ) => state . invertScrollForToolWidth
405381) ;
406- export const selectActiveColor = buildCanvasInstanceSettingsSelector ( ( settings ) => settings . activeColor ) ;
407- export const selectBgColor = buildCanvasInstanceSettingsSelector ( ( settings ) => settings . bgColor ) ;
408- export const selectFgColor = buildCanvasInstanceSettingsSelector ( ( settings ) => settings . fgColor ) ;
409- export const selectBrushWidth = buildCanvasInstanceSettingsSelector ( ( settings ) => settings . brushWidth ) ;
410- export const selectEraserWidth = buildCanvasInstanceSettingsSelector ( ( settings ) => settings . eraserWidth ) ;
382+ export const selectBboxOverlay = buildCanvasSharedSettingsSelector ( ( state ) => state . bboxOverlay ) ;
383+ export const selectShowHUD = buildCanvasSharedSettingsSelector ( ( state ) => state . showHUD ) ;
384+ export const selectClipToBbox = buildCanvasSharedSettingsSelector ( ( state ) => state . clipToBbox ) ;
385+ export const selectAutoProcess = buildCanvasSharedSettingsSelector ( ( state ) => state . autoProcess ) ;
386+ export const selectSnapToGrid = buildCanvasSharedSettingsSelector ( ( state ) => state . snapToGrid ) ;
387+ export const selectShowProgressOnCanvas = buildCanvasSharedSettingsSelector ( ( state ) => state . showProgressOnCanvas ) ;
388+ export const selectIsolatedStagingPreview = buildCanvasSharedSettingsSelector ( ( state ) => state . isolatedStagingPreview ) ;
389+ export const selectIsolatedLayerPreview = buildCanvasSharedSettingsSelector ( ( state ) => state . isolatedLayerPreview ) ;
390+ export const selectPressureSensitivity = buildCanvasSharedSettingsSelector ( ( state ) => state . pressureSensitivity ) ;
391+ export const selectRuleOfThirds = buildCanvasSharedSettingsSelector ( ( state ) => state . ruleOfThirds ) ;
392+ export const selectSaveAllImagesToGallery = buildCanvasSharedSettingsSelector ( ( state ) => state . saveAllImagesToGallery ) ;
393+ export const selectStagingAreaAutoSwitch = buildCanvasSharedSettingsSelector ( ( state ) => state . stagingAreaAutoSwitch ) ;
394+ export const selectActiveColor = buildCanvasInstanceSettingsSelector ( ( state ) => state . activeColor ) ;
395+ export const selectBgColor = buildCanvasInstanceSettingsSelector ( ( state ) => state . bgColor ) ;
396+ export const selectFgColor = buildCanvasInstanceSettingsSelector ( ( state ) => state . fgColor ) ;
397+ export const selectBrushWidth = buildCanvasInstanceSettingsSelector ( ( state ) => state . brushWidth ) ;
398+ export const selectEraserWidth = buildCanvasInstanceSettingsSelector ( ( state ) => state . eraserWidth ) ;
0 commit comments