@yogiswara/honcho-editor-ui 2.7.13 → 2.7.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/package.json +1 -1
  2. package/dist/color.d.ts +0 -9
  3. package/dist/color.js +0 -9
  4. package/dist/components/editor/GalleryAlbum/AlbumImageGallery.d.ts +0 -8
  5. package/dist/components/editor/GalleryAlbum/AlbumImageGallery.js +0 -28
  6. package/dist/components/editor/GalleryAlbum/ImageItem.d.ts +0 -10
  7. package/dist/components/editor/GalleryAlbum/ImageItem.js +0 -81
  8. package/dist/components/editor/HAccordionAspectRatio.d.ts +0 -14
  9. package/dist/components/editor/HAccordionAspectRatio.js +0 -102
  10. package/dist/components/editor/HAccordionColor.d.ts +0 -16
  11. package/dist/components/editor/HAccordionColor.js +0 -282
  12. package/dist/components/editor/HAccordionColorAdjustment.d.ts +0 -35
  13. package/dist/components/editor/HAccordionColorAdjustment.js +0 -31
  14. package/dist/components/editor/HAccordionDetails.d.ts +0 -12
  15. package/dist/components/editor/HAccordionDetails.js +0 -157
  16. package/dist/components/editor/HAccordionLight.d.ts +0 -20
  17. package/dist/components/editor/HAccordionLight.js +0 -414
  18. package/dist/components/editor/HAccordionPreset.d.ts +0 -23
  19. package/dist/components/editor/HAccordionPreset.js +0 -50
  20. package/dist/components/editor/HAlertBox.d.ts +0 -8
  21. package/dist/components/editor/HAlertBox.js +0 -55
  22. package/dist/components/editor/HAspectRatioMobile.d.ts +0 -0
  23. package/dist/components/editor/HAspectRatioMobile.js +0 -1
  24. package/dist/components/editor/HBulkAccordionColorAdjustment.d.ts +0 -55
  25. package/dist/components/editor/HBulkAccordionColorAdjustment.js +0 -31
  26. package/dist/components/editor/HBulkAccordionColorAdjustmentColors.d.ts +0 -20
  27. package/dist/components/editor/HBulkAccordionColorAdjustmentColors.js +0 -121
  28. package/dist/components/editor/HBulkAccordionColorAdjustmentDetails.d.ts +0 -12
  29. package/dist/components/editor/HBulkAccordionColorAdjustmentDetails.js +0 -65
  30. package/dist/components/editor/HBulkAccordionColorAdjustmentLight.d.ts +0 -28
  31. package/dist/components/editor/HBulkAccordionColorAdjustmentLight.js +0 -177
  32. package/dist/components/editor/HBulkColorAdjustmentMobile.d.ts +0 -53
  33. package/dist/components/editor/HBulkColorAdjustmentMobile.js +0 -16
  34. package/dist/components/editor/HBulkColorMobile.d.ts +0 -20
  35. package/dist/components/editor/HBulkColorMobile.js +0 -121
  36. package/dist/components/editor/HBulkDetailsMobile.d.ts +0 -12
  37. package/dist/components/editor/HBulkDetailsMobile.js +0 -65
  38. package/dist/components/editor/HBulkLightMobile.d.ts +0 -28
  39. package/dist/components/editor/HBulkLightMobile.js +0 -192
  40. package/dist/components/editor/HBulkPreset.d.ts +0 -24
  41. package/dist/components/editor/HBulkPreset.js +0 -43
  42. package/dist/components/editor/HBulkPresetMobile.d.ts +0 -15
  43. package/dist/components/editor/HBulkPresetMobile.js +0 -26
  44. package/dist/components/editor/HDialogBox.d.ts +0 -18
  45. package/dist/components/editor/HDialogBox.js +0 -51
  46. package/dist/components/editor/HDialogCopy.d.ts +0 -40
  47. package/dist/components/editor/HDialogCopy.js +0 -80
  48. package/dist/components/editor/HFooter.d.ts +0 -12
  49. package/dist/components/editor/HFooter.js +0 -24
  50. package/dist/components/editor/HHeaderEditor.d.ts +0 -17
  51. package/dist/components/editor/HHeaderEditor.js +0 -36
  52. package/dist/components/editor/HImageEditorBulkDekstop.d.ts +0 -15
  53. package/dist/components/editor/HImageEditorBulkDekstop.js +0 -29
  54. package/dist/components/editor/HImageEditorBulkMobile.d.ts +0 -72
  55. package/dist/components/editor/HImageEditorBulkMobile.js +0 -81
  56. package/dist/components/editor/HImageEditorDekstop.d.ts +0 -15
  57. package/dist/components/editor/HImageEditorDekstop.js +0 -29
  58. package/dist/components/editor/HImageEditorMobile.d.ts +0 -51
  59. package/dist/components/editor/HImageEditorMobile.js +0 -92
  60. package/dist/components/editor/HImageEditorMobileLayout.d.ts +0 -14
  61. package/dist/components/editor/HImageEditorMobileLayout.js +0 -58
  62. package/dist/components/editor/HModalEditorDekstop.d.ts +0 -13
  63. package/dist/components/editor/HModalEditorDekstop.js +0 -22
  64. package/dist/components/editor/HModalMobile.d.ts +0 -13
  65. package/dist/components/editor/HModalMobile.js +0 -7
  66. package/dist/components/editor/HPresetDelete.d.ts +0 -7
  67. package/dist/components/editor/HPresetDelete.js +0 -7
  68. package/dist/components/editor/HPresetOptionMenu.d.ts +0 -9
  69. package/dist/components/editor/HPresetOptionMenu.js +0 -20
  70. package/dist/components/editor/HSliderColorMobile.d.ts +0 -16
  71. package/dist/components/editor/HSliderColorMobile.js +0 -270
  72. package/dist/components/editor/HSliderDetailsMobile.d.ts +0 -12
  73. package/dist/components/editor/HSliderDetailsMobile.js +0 -154
  74. package/dist/components/editor/HSliderLightMobile.d.ts +0 -20
  75. package/dist/components/editor/HSliderLightMobile.js +0 -420
  76. package/dist/components/editor/HTabAspectRatioMobile.d.ts +0 -0
  77. package/dist/components/editor/HTabAspectRatioMobile.js +0 -1
  78. package/dist/components/editor/HTabColorAdjustmentMobile.d.ts +0 -33
  79. package/dist/components/editor/HTabColorAdjustmentMobile.js +0 -16
  80. package/dist/components/editor/HTabPresetMobile.d.ts +0 -14
  81. package/dist/components/editor/HTabPresetMobile.js +0 -10
  82. package/dist/components/editor/HTextField.d.ts +0 -14
  83. package/dist/components/editor/HTextField.js +0 -51
  84. package/dist/components/editor/HWatermarkView.d.ts +0 -6
  85. package/dist/components/editor/HWatermarkView.js +0 -16
  86. package/dist/components/editor/svg/Tick.d.ts +0 -2
  87. package/dist/components/editor/svg/Tick.js +0 -6
  88. package/dist/components/modal/HModalDialog.d.ts +0 -12
  89. package/dist/components/modal/HModalDialog.js +0 -18
  90. package/dist/components/modal/HModalRename.d.ts +0 -14
  91. package/dist/components/modal/HModalRename.js +0 -35
  92. package/dist/hooks/demo/HonchoEditorBulkDemo.d.ts +0 -3
  93. package/dist/hooks/demo/HonchoEditorBulkDemo.js +0 -410
  94. package/dist/hooks/demo/HonchoEditorSingleCleanDemo.d.ts +0 -3
  95. package/dist/hooks/demo/HonchoEditorSingleCleanDemo.js +0 -354
  96. package/dist/hooks/demo/index.d.ts +0 -2
  97. package/dist/hooks/demo/index.js +0 -2
  98. package/dist/hooks/editor/type.d.ts +0 -174
  99. package/dist/hooks/editor/type.js +0 -1
  100. package/dist/hooks/editor/useHonchoEditorBulk.d.ts +0 -96
  101. package/dist/hooks/editor/useHonchoEditorBulk.js +0 -427
  102. package/dist/hooks/editor/useHonchoEditorSingle.d.ts +0 -44
  103. package/dist/hooks/editor/useHonchoEditorSingle.js +0 -162
  104. package/dist/hooks/useAdjustmentHistory.d.ts +0 -97
  105. package/dist/hooks/useAdjustmentHistory.js +0 -493
  106. package/dist/hooks/useAdjustmentHistoryBatch.d.ts +0 -177
  107. package/dist/hooks/useAdjustmentHistoryBatch.js +0 -1189
  108. package/dist/hooks/useGallerySwipe.d.ts +0 -36
  109. package/dist/hooks/useGallerySwipe.js +0 -344
  110. package/dist/hooks/usePaging.d.ts +0 -89
  111. package/dist/hooks/usePaging.js +0 -211
  112. package/dist/hooks/usePreset.d.ts +0 -82
  113. package/dist/hooks/usePreset.js +0 -344
  114. package/dist/index.d.ts +0 -41
  115. package/dist/index.js +0 -44
  116. package/dist/lib/context/EditorContext.d.ts +0 -28
  117. package/dist/lib/context/EditorContext.js +0 -60
  118. package/dist/lib/context/EditorProcessingService.d.ts +0 -36
  119. package/dist/lib/context/EditorProcessingService.js +0 -249
  120. package/dist/lib/editor/honcho-editor.d.ts +0 -324
  121. package/dist/lib/editor/honcho-editor.js +0 -825
  122. package/dist/lib/hooks/useEditor.d.ts +0 -22
  123. package/dist/lib/hooks/useEditor.js +0 -35
  124. package/dist/lib/hooks/useEditorHeadless.d.ts +0 -34
  125. package/dist/lib/hooks/useEditorHeadless.js +0 -207
  126. package/dist/lib/hooks/useImageProcessor.d.ts +0 -18
  127. package/dist/lib/hooks/useImageProcessor.js +0 -113
  128. package/dist/setupTests.d.ts +0 -1
  129. package/dist/setupTests.js +0 -1
  130. package/dist/themes/colors.d.ts +0 -12
  131. package/dist/themes/colors.js +0 -12
  132. package/dist/themes/honchoTheme.d.ts +0 -25
  133. package/dist/themes/honchoTheme.js +0 -94
  134. package/dist/utils/adjustment.d.ts +0 -6
  135. package/dist/utils/adjustment.js +0 -48
  136. package/dist/utils/imageLoader.d.ts +0 -11
  137. package/dist/utils/imageLoader.js +0 -48
  138. package/dist/utils/isMobile.d.ts +0 -1
  139. package/dist/utils/isMobile.js +0 -5
@@ -1,97 +0,0 @@
1
- import { AdjustmentState, Controller } from './editor/type';
2
- /**
3
- * Configuration options for the adjustment history hook
4
- */
5
- export interface HistoryOptions {
6
- /** Maximum number of history entries to keep. Use 'unlimited' for no limit */
7
- maxSize?: number | 'unlimited';
8
- /** Whether to enable batch mode for grouping multiple changes */
9
- enableBatching?: boolean;
10
- /** Enable development warnings for performance issues */
11
- devWarnings?: boolean;
12
- }
13
- /**
14
- * Information about the current history state
15
- */
16
- export interface HistoryInfo {
17
- /** Whether undo operation is available */
18
- canUndo: boolean;
19
- /** Whether redo operation is available */
20
- canRedo: boolean;
21
- /** Current position in history (0-based index) */
22
- currentIndex: number;
23
- /** Total number of states in history */
24
- totalStates: number;
25
- /** Current size of history in memory */
26
- historySize: number;
27
- /** Whether batch mode is currently active */
28
- isBatchMode: boolean;
29
- }
30
- /**
31
- * Actions available for history management
32
- */
33
- export interface HistoryActions {
34
- /** Add a new adjustment state to history */
35
- pushState: (state: AdjustmentState) => void;
36
- /** Undo to previous adjustment state */
37
- undo: () => void;
38
- /** Redo to next adjustment state */
39
- redo: () => void;
40
- /** Reset history with new initial adjustment state */
41
- reset: (newInitialState: AdjustmentState) => void;
42
- /** Jump to specific index in history */
43
- jumpToIndex: (index: number) => void;
44
- /** Clear all history and start fresh */
45
- clearHistory: () => void;
46
- /** Get a copy of the entire history array */
47
- getHistory: () => AdjustmentState[];
48
- /** Trim history to specified size, keeping most recent entries */
49
- trimHistory: (keepLast: number) => void;
50
- /** Replace entire history with new list of adjustment states */
51
- syncHistory: (newHistory: AdjustmentState[], targetIndex?: number) => void;
52
- }
53
- /**
54
- * Configuration actions for runtime adjustment
55
- */
56
- export interface HistoryConfig {
57
- /** Set maximum history size */
58
- setMaxSize: (size: number | 'unlimited') => void;
59
- /** Enable or disable batch mode */
60
- setBatchMode: (enabled: boolean) => Promise<void>;
61
- /** Get current memory usage estimate */
62
- getMemoryUsage: () => number;
63
- /** Force sync current state to backend */
64
- syncToBackend: () => Promise<void>;
65
- }
66
- /**
67
- * Return type for the useAdjustmentHistory hook
68
- */
69
- export interface UseAdjustmentHistoryReturn {
70
- /** Current adjustment state value */
71
- currentState: AdjustmentState;
72
- /** Information about history state */
73
- historyInfo: HistoryInfo;
74
- /** Available history actions */
75
- actions: HistoryActions;
76
- /** Configuration options */
77
- config: HistoryConfig;
78
- }
79
- /**
80
- * Advanced hook for managing AdjustmentState history with undo/redo functionality.
81
- *
82
- * Features:
83
- * - Unlimited or configurable history size
84
- * - Batch mode for grouping multiple changes into single undo operations
85
- * - Memory usage monitoring and optimization
86
- * - Internal stabilization to prevent re-render issues
87
- * - Jump to any point in history
88
- * - Automatic AdjustmentState comparison
89
- *
90
- * @param initialState - The initial AdjustmentState value
91
- * @param controller - Controller for backend operations (optional)
92
- * @param firebaseUid - Firebase UID for backend operations (optional)
93
- * @param currentImageId - Current image ID for backend operations (optional)
94
- * @param options - Configuration options for history behavior
95
- * @returns Object with current state, history info, actions, and config
96
- */
97
- export declare function useAdjustmentHistory(initialState: AdjustmentState, controller?: Controller, firebaseUid?: string, currentImageId?: string, options?: HistoryOptions): UseAdjustmentHistoryReturn;
@@ -1,493 +0,0 @@
1
- import { useState, useCallback, useMemo, useRef, useEffect } from 'react';
2
- /**
3
- * Convert AdjustmentState to ColorAdjustment format for backend
4
- */
5
- const convertAdjustmentStateToColorAdjustment = (adjustmentState) => {
6
- return {
7
- temperature: adjustmentState.tempScore,
8
- tint: adjustmentState.tintScore,
9
- saturation: adjustmentState.saturationScore,
10
- vibrance: adjustmentState.vibranceScore,
11
- exposure: adjustmentState.exposureScore,
12
- contrast: adjustmentState.contrastScore,
13
- highlights: adjustmentState.highlightsScore,
14
- shadows: adjustmentState.shadowsScore,
15
- whites: adjustmentState.whitesScore,
16
- blacks: adjustmentState.blacksScore,
17
- clarity: adjustmentState.clarityScore,
18
- sharpness: adjustmentState.sharpnessScore,
19
- };
20
- };
21
- /**
22
- * Compare two AdjustmentState objects for equality
23
- * Uses JSON.stringify for deep comparison of all adjustment values
24
- */
25
- const compareAdjustmentStates = (a, b) => {
26
- try {
27
- return JSON.stringify(a) === JSON.stringify(b);
28
- }
29
- catch (error) {
30
- // Fallback to manual comparison if JSON.stringify fails
31
- console.warn('Failed to compare adjustment states with JSON.stringify, falling back to manual comparison:', error);
32
- return (a.tempScore === b.tempScore &&
33
- a.tintScore === b.tintScore &&
34
- a.vibranceScore === b.vibranceScore &&
35
- a.saturationScore === b.saturationScore &&
36
- a.exposureScore === b.exposureScore &&
37
- a.highlightsScore === b.highlightsScore &&
38
- a.shadowsScore === b.shadowsScore &&
39
- a.whitesScore === b.whitesScore &&
40
- a.blacksScore === b.blacksScore &&
41
- a.contrastScore === b.contrastScore &&
42
- a.clarityScore === b.clarityScore &&
43
- a.sharpnessScore === b.sharpnessScore);
44
- }
45
- };
46
- /**
47
- * Advanced hook for managing AdjustmentState history with undo/redo functionality.
48
- *
49
- * Features:
50
- * - Unlimited or configurable history size
51
- * - Batch mode for grouping multiple changes into single undo operations
52
- * - Memory usage monitoring and optimization
53
- * - Internal stabilization to prevent re-render issues
54
- * - Jump to any point in history
55
- * - Automatic AdjustmentState comparison
56
- *
57
- * @param initialState - The initial AdjustmentState value
58
- * @param controller - Controller for backend operations (optional)
59
- * @param firebaseUid - Firebase UID for backend operations (optional)
60
- * @param currentImageId - Current image ID for backend operations (optional)
61
- * @param options - Configuration options for history behavior
62
- * @returns Object with current state, history info, actions, and config
63
- */
64
- export function useAdjustmentHistory(initialState, controller, firebaseUid, currentImageId, options = {}) {
65
- // Internal stabilization - prevent re-renders from options object recreation
66
- const internalOptions = useMemo(() => ({
67
- maxSize: options.maxSize ?? 'unlimited',
68
- enableBatching: options.enableBatching ?? false,
69
- devWarnings: options.devWarnings ?? false,
70
- controller: controller,
71
- firebaseUid: firebaseUid,
72
- currentImageId: currentImageId
73
- }), [
74
- options.maxSize,
75
- options.enableBatching,
76
- options.devWarnings,
77
- controller,
78
- firebaseUid,
79
- currentImageId
80
- ]);
81
- // Core state management
82
- const [history, setHistory] = useState([{ state: initialState }]);
83
- const [currentIndex, setCurrentIndex] = useState(0);
84
- const [currentState, setCurrentState] = useState(initialState);
85
- // Batch mode state - ref to avoid triggering effects
86
- const batchModeRef = useRef(internalOptions.enableBatching);
87
- const batchStartIndexRef = useRef(null);
88
- const batchStartStateRef = useRef(null);
89
- const batchModeProcessingRef = useRef(false); // Guard against double execution
90
- // Configuration refs - prevent re-renders when config changes
91
- const maxSizeRef = useRef(internalOptions.maxSize);
92
- const devWarningsRef = useRef(internalOptions.devWarnings);
93
- // Performance monitoring
94
- const performanceRef = useRef({
95
- lastHistorySize: 1,
96
- lastUpdateTime: Date.now(),
97
- largeHistoryWarningShown: false
98
- });
99
- // Sync currentState with history when not in batch mode
100
- useEffect(() => {
101
- if (!batchModeRef.current) {
102
- setCurrentState(history[currentIndex]?.state || initialState);
103
- }
104
- }, [history, currentIndex, initialState]);
105
- const getMemoryUsage = useCallback(() => {
106
- try {
107
- const historyString = JSON.stringify(history);
108
- return historyString.length * 2; // Rough estimate: 2 bytes per character
109
- }
110
- catch (error) {
111
- console.warn('Failed to estimate memory usage:', error);
112
- return history.length * 1000; // Fallback estimate
113
- }
114
- }, [history]);
115
- // Development warnings for performance
116
- const checkPerformance = useCallback(() => {
117
- if (!devWarningsRef.current)
118
- return;
119
- const now = Date.now();
120
- const perfData = performanceRef.current;
121
- // Warn about large history sizes
122
- if (history.length > 1000 && !perfData.largeHistoryWarningShown) {
123
- console.warn(`useAdjustmentHistory: Large history size detected (${history.length} entries). Consider setting a maxSize limit.`);
124
- perfData.largeHistoryWarningShown = true;
125
- }
126
- // Update performance tracking
127
- perfData.lastHistorySize = history.length;
128
- perfData.lastUpdateTime = now;
129
- }, [history.length]);
130
- // Trim history to specified size, keeping most recent entries
131
- const trimHistoryToSize = useCallback((size) => {
132
- if (size <= 0)
133
- return;
134
- setHistory(prevHistory => {
135
- if (prevHistory.length <= size)
136
- return prevHistory;
137
- const startIndex = Math.max(0, prevHistory.length - size);
138
- const trimmedHistory = prevHistory.slice(startIndex);
139
- // Adjust current index to maintain relative position
140
- setCurrentIndex(prevIndex => {
141
- const adjustedIndex = prevIndex - startIndex;
142
- return Math.max(0, Math.min(adjustedIndex, trimmedHistory.length - 1));
143
- });
144
- return trimmedHistory;
145
- });
146
- }, []);
147
- // Apply max size limit when history grows
148
- const enforceMaxSize = useCallback(() => {
149
- if (maxSizeRef.current === 'unlimited')
150
- return;
151
- const maxSize = maxSizeRef.current;
152
- if (history.length > maxSize) {
153
- trimHistoryToSize(maxSize);
154
- }
155
- }, [history.length, trimHistoryToSize]);
156
- // Push new state to history
157
- const pushState = useCallback((newState) => {
158
- // Always update currentState immediately for smooth UI
159
- setCurrentState(newState);
160
- if (batchModeRef.current) {
161
- // In batch mode: Don't update history yet, just update UI state
162
- // History will be updated when batch mode ends
163
- return;
164
- }
165
- // Normal mode: Update history immediately
166
- setHistory(prevHistory => {
167
- const truncatedHistory = prevHistory.slice(0, currentIndex + 1);
168
- const newHistory = [...truncatedHistory, { state: newState }];
169
- setCurrentIndex(newHistory.length - 1);
170
- return newHistory;
171
- });
172
- }, [currentState, currentIndex]);
173
- // Undo to previous state
174
- const undo = useCallback(async () => {
175
- if (currentIndex > 0) {
176
- const newIndex = currentIndex - 1;
177
- const historyEntry = history[newIndex];
178
- const newState = historyEntry.state;
179
- setCurrentIndex(newIndex);
180
- setCurrentState(newState);
181
- // Call controller to set history index in backend if taskId exists
182
- if (historyEntry.taskId && internalOptions.controller && internalOptions.firebaseUid && internalOptions.currentImageId) {
183
- try {
184
- console.log(`🔙 Undo: Setting history index to taskId: ${historyEntry.taskId}`);
185
- await internalOptions.controller.setHistoryIndex(internalOptions.firebaseUid, internalOptions.currentImageId, historyEntry.taskId);
186
- console.log('✅ Successfully set history index for undo');
187
- }
188
- catch (error) {
189
- console.error('❌ Failed to set history index for undo:', error);
190
- }
191
- }
192
- // Exit batch mode when undoing
193
- if (batchModeRef.current) {
194
- batchModeRef.current = false;
195
- batchStartIndexRef.current = null;
196
- batchStartStateRef.current = null;
197
- }
198
- }
199
- }, [currentIndex, history, internalOptions]);
200
- // Redo to next state
201
- const redo = useCallback(async () => {
202
- if (currentIndex < history.length - 1) {
203
- const newIndex = currentIndex + 1;
204
- const historyEntry = history[newIndex];
205
- const newState = historyEntry.state;
206
- setCurrentIndex(newIndex);
207
- setCurrentState(newState);
208
- // Call controller to set history index in backend if taskId exists
209
- if (historyEntry.taskId && internalOptions.controller && internalOptions.firebaseUid && internalOptions.currentImageId) {
210
- try {
211
- console.log(`🔄 Redo: Setting history index to taskId: ${historyEntry.taskId}`);
212
- await internalOptions.controller.setHistoryIndex(internalOptions.firebaseUid, internalOptions.currentImageId, historyEntry.taskId);
213
- console.log('✅ Successfully set history index for redo');
214
- }
215
- catch (error) {
216
- console.error('❌ Failed to set history index for redo:', error);
217
- }
218
- }
219
- }
220
- }, [currentIndex, history, internalOptions]);
221
- // Reset history with new initial state
222
- const reset = useCallback((newInitialState) => {
223
- setHistory([{ state: newInitialState }]);
224
- setCurrentIndex(0);
225
- setCurrentState(newInitialState);
226
- batchModeRef.current = internalOptions.enableBatching;
227
- batchStartIndexRef.current = null;
228
- batchStartStateRef.current = null;
229
- }, [internalOptions.enableBatching]);
230
- // Jump to specific index in history
231
- const jumpToIndex = useCallback((index) => {
232
- if (index >= 0 && index < history.length) {
233
- const historyEntry = history[index];
234
- const newState = historyEntry.state;
235
- setCurrentIndex(index);
236
- setCurrentState(newState);
237
- // Exit batch mode when jumping
238
- if (batchModeRef.current) {
239
- batchModeRef.current = false;
240
- batchStartIndexRef.current = null;
241
- batchStartStateRef.current = null;
242
- }
243
- }
244
- }, [history]);
245
- // Clear all history and start fresh
246
- const clearHistory = useCallback(() => {
247
- setHistory([{ state: currentState }]);
248
- setCurrentIndex(0);
249
- batchModeRef.current = internalOptions.enableBatching;
250
- batchStartIndexRef.current = null;
251
- batchStartStateRef.current = null;
252
- }, [currentState, internalOptions.enableBatching]);
253
- // Get copy of entire history
254
- const getHistory = useCallback(() => {
255
- return history.map(entry => entry.state);
256
- }, [history]);
257
- // Manually trim history
258
- const trimHistory = useCallback((keepLast) => {
259
- trimHistoryToSize(keepLast);
260
- }, [trimHistoryToSize]);
261
- // Sync/replace entire history with new list
262
- const syncHistory = useCallback((newHistory, targetIndex) => {
263
- // Validate input
264
- if (!Array.isArray(newHistory) || newHistory.length === 0) {
265
- console.warn('syncHistory: newHistory must be a non-empty array');
266
- return;
267
- }
268
- // Validate all items are AdjustmentState objects
269
- const isValidHistory = newHistory.every(state => state && typeof state === 'object' &&
270
- typeof state.tempScore === 'number' &&
271
- typeof state.tintScore === 'number' &&
272
- typeof state.vibranceScore === 'number' &&
273
- typeof state.saturationScore === 'number' &&
274
- typeof state.exposureScore === 'number' &&
275
- typeof state.highlightsScore === 'number' &&
276
- typeof state.shadowsScore === 'number' &&
277
- typeof state.whitesScore === 'number' &&
278
- typeof state.blacksScore === 'number' &&
279
- typeof state.contrastScore === 'number' &&
280
- typeof state.clarityScore === 'number' &&
281
- typeof state.sharpnessScore === 'number');
282
- if (!isValidHistory) {
283
- console.warn('syncHistory: All items in newHistory must be valid AdjustmentState objects');
284
- return;
285
- }
286
- // Exit batch mode if active
287
- if (batchModeRef.current) {
288
- batchModeRef.current = false;
289
- batchStartIndexRef.current = null;
290
- batchStartStateRef.current = null;
291
- }
292
- // Determine target index
293
- let finalIndex = targetIndex ?? newHistory.length - 1; // Default to last item
294
- finalIndex = Math.max(0, Math.min(finalIndex, newHistory.length - 1)); // Clamp to valid range
295
- // Create a copy of the new history to avoid mutations and convert to HistoryEntry format
296
- const historyToSet = newHistory.map(state => ({ state: { ...state } }));
297
- // Apply max size limit if needed
298
- if (maxSizeRef.current !== 'unlimited' && historyToSet.length > maxSizeRef.current) {
299
- const trimAmount = historyToSet.length - maxSizeRef.current;
300
- const trimmedHistory = historyToSet.slice(trimAmount);
301
- // Adjust target index
302
- finalIndex = Math.max(0, finalIndex - trimAmount);
303
- setHistory(trimmedHistory);
304
- setCurrentIndex(finalIndex);
305
- setCurrentState(trimmedHistory[finalIndex].state);
306
- if (devWarningsRef.current) {
307
- console.warn(`syncHistory: Trimmed ${trimAmount} entries to respect maxSize of ${maxSizeRef.current}`);
308
- }
309
- }
310
- else {
311
- // Set history as-is
312
- setHistory(historyToSet);
313
- setCurrentIndex(finalIndex);
314
- setCurrentState(historyToSet[finalIndex].state);
315
- }
316
- if (devWarningsRef.current) {
317
- console.log(`syncHistory: Synchronized ${historyToSet.length} states, current index: ${finalIndex}`);
318
- }
319
- }, []);
320
- // Configuration setters
321
- const setMaxSize = useCallback((size) => {
322
- maxSizeRef.current = size;
323
- if (size !== 'unlimited') {
324
- enforceMaxSize();
325
- }
326
- }, [enforceMaxSize]);
327
- const setBatchMode = useCallback(async (enabled) => {
328
- const wasInBatch = batchModeRef.current;
329
- console.log(`🔧 setBatchMode called: enabled=${enabled}, wasInBatch=${wasInBatch}, currentIndex=${currentIndex}, historyLength=${history.length}`);
330
- if (enabled && !wasInBatch) {
331
- // Starting batch mode - save current state as batch start
332
- batchModeRef.current = true;
333
- batchStartIndexRef.current = currentIndex;
334
- batchStartStateRef.current = currentState;
335
- console.log("Current start batch ", currentState, `batchStartIndex=${currentIndex}`);
336
- }
337
- else if (!enabled && wasInBatch) {
338
- // Guard against double execution
339
- if (batchModeProcessingRef.current) {
340
- console.log("⚠️ setBatchMode(false) already processing, skipping duplicate call");
341
- return;
342
- }
343
- // Ending batch mode - commit final state to history
344
- batchModeProcessingRef.current = true;
345
- batchModeRef.current = false;
346
- // Only add to history if state actually changed from batch start
347
- if (batchStartStateRef.current &&
348
- !compareAdjustmentStates(currentState, batchStartStateRef.current)) {
349
- // Generate a unique task ID for this history entry
350
- const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
351
- setHistory(prevHistory => {
352
- // Check if we were in the middle of history BEFORE any truncation
353
- // Handle case where batchStartIndexRef.current might be null (e.g., after undo)
354
- const batchStartIndex = batchStartIndexRef.current ?? currentIndex;
355
- const wasInMiddleOfHistory = batchStartIndex < prevHistory.length - 1;
356
- const truncatedHistory = prevHistory.slice(0, batchStartIndex + 1);
357
- const newHistoryEntry = {
358
- state: currentState,
359
- taskId: taskId
360
- };
361
- const newHistory = [...truncatedHistory, newHistoryEntry];
362
- setCurrentIndex(newHistory.length - 1);
363
- return newHistory;
364
- });
365
- // Call controller to create history in backend - OUTSIDE of setHistory callback
366
- if (internalOptions.controller && internalOptions.firebaseUid && internalOptions.currentImageId) {
367
- try {
368
- console.log('🔄 Creating editor history in backend for batch mode end');
369
- let replaceFromTaskId;
370
- const batchStartIndex = batchStartIndexRef.current ?? currentIndex;
371
- const wasInMiddleOfHistory = batchStartIndex < history.length - 1;
372
- if (wasInMiddleOfHistory) {
373
- // Get the task_id from the original history entry to use as replace_from
374
- const currentHistoryEntry = history[batchStartIndex];
375
- replaceFromTaskId = currentHistoryEntry?.taskId;
376
- console.log(`📍 Was in middle of history (index ${batchStartIndex}), using replace_from: ${replaceFromTaskId}`);
377
- }
378
- else {
379
- console.log(`📍 At latest history (index ${batchStartIndex}), no replace_from needed`);
380
- }
381
- const createEditorConfigPayload = {
382
- gallery_id: internalOptions.currentImageId,
383
- task_id: taskId,
384
- color_adjustment: convertAdjustmentStateToColorAdjustment(currentState),
385
- ...(replaceFromTaskId && { replace_from: replaceFromTaskId })
386
- };
387
- // Create editor config with current adjustments
388
- internalOptions.controller.createEditorConfig(internalOptions.firebaseUid, createEditorConfigPayload).then(() => {
389
- console.log('✅ Successfully created editor history in backend');
390
- }).catch((error) => {
391
- console.error('❌ Failed to create editor history in backend:', error);
392
- });
393
- }
394
- catch (error) {
395
- console.error('❌ Error calling controller.createEditorConfig:', error);
396
- }
397
- }
398
- else {
399
- if (internalOptions.devWarnings) {
400
- console.warn('⚠️ Controller, firebaseUid, or currentImageId not provided - skipping backend history creation');
401
- }
402
- }
403
- }
404
- batchStartIndexRef.current = null;
405
- batchStartStateRef.current = null;
406
- batchModeProcessingRef.current = false; // Reset processing flag
407
- }
408
- }, [currentIndex, currentState, internalOptions]);
409
- // History info object
410
- const historyInfo = useMemo(() => ({
411
- canUndo: currentIndex > 0,
412
- canRedo: currentIndex < history.length - 1,
413
- currentIndex,
414
- totalStates: history.length,
415
- historySize: getMemoryUsage(),
416
- isBatchMode: batchModeRef.current
417
- }), [currentIndex, history.length, getMemoryUsage]);
418
- // Actions object - stabilized with useMemo
419
- const actions = useMemo(() => ({
420
- pushState,
421
- undo,
422
- redo,
423
- reset,
424
- jumpToIndex,
425
- clearHistory,
426
- getHistory,
427
- trimHistory,
428
- syncHistory
429
- }), [pushState, undo, redo, reset, jumpToIndex, clearHistory, getHistory, trimHistory, syncHistory]);
430
- // Force sync current state to backend
431
- const syncToBackend = useCallback(async () => {
432
- if (internalOptions.controller && internalOptions.firebaseUid && internalOptions.currentImageId) {
433
- try {
434
- console.log('🔄 Force syncing current state to backend');
435
- // Check if we're in middle of history (not at the latest)
436
- const wasInMiddleOfHistory = currentIndex < history.length - 1;
437
- let replaceFromTaskId;
438
- if (wasInMiddleOfHistory) {
439
- // Get the task_id from the current history entry to use as replace_from
440
- const currentHistoryEntry = history[currentIndex];
441
- replaceFromTaskId = currentHistoryEntry?.taskId;
442
- console.log(`📍 In middle of history (index ${currentIndex}), using replace_from: ${replaceFromTaskId}`);
443
- }
444
- // Generate a unique task ID for this sync
445
- const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
446
- const createEditorConfigPayload = {
447
- gallery_id: internalOptions.currentImageId,
448
- task_id: taskId,
449
- color_adjustment: convertAdjustmentStateToColorAdjustment(currentState),
450
- ...(replaceFromTaskId && { replace_from: replaceFromTaskId })
451
- };
452
- await internalOptions.controller.createEditorConfig(internalOptions.firebaseUid, createEditorConfigPayload);
453
- console.log('✅ Successfully synced current state to backend');
454
- // Update the current history entry with the new task ID
455
- setHistory(prevHistory => {
456
- const newHistory = [...prevHistory];
457
- if (newHistory[currentIndex]) {
458
- newHistory[currentIndex] = {
459
- ...newHistory[currentIndex],
460
- taskId: taskId
461
- };
462
- }
463
- return newHistory;
464
- });
465
- }
466
- catch (error) {
467
- console.error('❌ Failed to sync current state to backend:', error);
468
- throw error;
469
- }
470
- }
471
- else {
472
- console.warn('⚠️ Controller, firebaseUid, or currentImageId not provided - skipping backend sync');
473
- }
474
- }, [currentState, currentIndex, history, internalOptions]);
475
- // Config object - stabilized with useMemo
476
- const config = useMemo(() => ({
477
- setMaxSize,
478
- setBatchMode,
479
- getMemoryUsage,
480
- syncToBackend
481
- }), [setMaxSize, setBatchMode, getMemoryUsage, syncToBackend]);
482
- // Apply max size enforcement when history changes
483
- useEffect(() => {
484
- enforceMaxSize();
485
- checkPerformance();
486
- }, [enforceMaxSize, checkPerformance]);
487
- return {
488
- currentState,
489
- historyInfo,
490
- actions,
491
- config
492
- };
493
- }