@yogiswara/honcho-editor-ui 2.0.2 → 2.0.4

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.
@@ -40,7 +40,7 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
40
40
  const [headerMenuAnchorEl, setHeaderMenuAnchorEl] = useState(null);
41
41
  const [anchorMenuZoom, setAnchorMenuZoom] = useState(null);
42
42
  // Panel Expansion State
43
- const [colorAdjustmentExpandedPanels, setColorAdjustmentExpandedPanels] = useState(['whiteBalance']);
43
+ const [colorAdjustmentExpandedPanels, setColorAdjustmentExpandedPanels] = useState(['whiteBalance', 'light', 'details']);
44
44
  const [presetExpandedPanels, setPresetExpandedPanels] = useState(['preset']);
45
45
  // Watermark State
46
46
  const [isCreatingWatermark, setIsCreatingWatermark] = useState(false);
@@ -78,6 +78,7 @@ export function useHonchoEditorBulk(controller, initImageId, firebaseUid) {
78
78
  const updateAdjustments = useCallback((newValues) => {
79
79
  const newState = { ...currentState, ...newValues };
80
80
  historyActions.pushState(newState);
81
+ console.log('Updated adjustments:', newState);
81
82
  }, [currentState, historyActions]);
82
83
  const createRelativeAdjuster = (key, amount) => () => {
83
84
  const currentValue = currentState[key];
@@ -0,0 +1,114 @@
1
+ import { AdjustmentState } from './editor/useHonchoEditor';
2
+ /**
3
+ * Batch adjustment state - maps image IDs to their adjustment states
4
+ */
5
+ export interface BatchAdjustmentState {
6
+ [imageId: string]: AdjustmentState;
7
+ }
8
+ /**
9
+ * Configuration options for the batch adjustment history hook
10
+ */
11
+ interface BatchHistoryOptions {
12
+ /** Maximum number of history entries to keep. Use 'unlimited' for no limit */
13
+ maxSize?: number | 'unlimited';
14
+ /** Enable development warnings for performance issues */
15
+ devWarnings?: boolean;
16
+ /** Default adjustment state for new images */
17
+ defaultAdjustmentState?: Partial<AdjustmentState>;
18
+ }
19
+ /**
20
+ * Information about the current batch history state
21
+ */
22
+ export interface BatchHistoryInfo {
23
+ /** Whether undo operation is available for selected images */
24
+ canUndo: boolean;
25
+ /** Whether redo operation is available for selected images */
26
+ canRedo: boolean;
27
+ /** Current position in history (0-based index) */
28
+ currentIndex: number;
29
+ /** Total number of states in history */
30
+ totalStates: number;
31
+ /** Number of currently selected images */
32
+ selectedCount: number;
33
+ /** Total number of images being managed */
34
+ totalImages: number;
35
+ /** Current size of history in memory */
36
+ historySize: number;
37
+ }
38
+ /**
39
+ * Actions available for batch history management
40
+ */
41
+ export interface BatchHistoryActions {
42
+ /** Apply adjustment deltas to selected images */
43
+ adjustSelected: (delta: Partial<AdjustmentState>) => void;
44
+ /** Set specific adjustment states for specified images */
45
+ setAdjustments: (adjustments: Partial<BatchAdjustmentState>) => void;
46
+ /** Undo last changes to selected images */
47
+ undo: () => void;
48
+ /** Redo next changes to selected images */
49
+ redo: () => void;
50
+ /** Reset selected images to default state */
51
+ reset: (imageIds?: string[]) => void;
52
+ /** Set which images are selected */
53
+ setSelection: (imageIds: string[]) => void;
54
+ /** Add or remove image from selection */
55
+ toggleSelection: (imageId: string) => void;
56
+ /** Select all images */
57
+ selectAll: () => void;
58
+ /** Clear selection */
59
+ clearSelection: () => void;
60
+ /** Jump to specific index in history */
61
+ jumpToIndex: (index: number) => void;
62
+ /** Clear all history and start fresh */
63
+ clearHistory: () => void;
64
+ /** Get copy of current batch state */
65
+ getCurrentBatch: () => BatchAdjustmentState;
66
+ /** Sync entire batch state */
67
+ syncBatch: (newBatch: BatchAdjustmentState, targetIndex?: number) => void;
68
+ }
69
+ /**
70
+ * Configuration actions for runtime adjustment
71
+ */
72
+ export interface BatchHistoryConfig {
73
+ /** Set maximum history size */
74
+ setMaxSize: (size: number | 'unlimited') => void;
75
+ /** Get current memory usage estimate */
76
+ getMemoryUsage: () => number;
77
+ /** Add new images to the batch */
78
+ addImages: (imageIds: string[], selectNew?: boolean) => void;
79
+ /** Remove images from the batch */
80
+ removeImages: (imageIds: string[]) => void;
81
+ }
82
+ /**
83
+ * Return type for the useAdjustmentHistoryBatch hook
84
+ */
85
+ export interface UseAdjustmentHistoryBatchReturn {
86
+ /** Current batch adjustment state */
87
+ currentBatch: BatchAdjustmentState;
88
+ /** Currently selected image IDs */
89
+ selectedIds: string[];
90
+ /** All image IDs being managed */
91
+ allImageIds: string[];
92
+ /** Information about history state */
93
+ historyInfo: BatchHistoryInfo;
94
+ /** Available history actions */
95
+ actions: BatchHistoryActions;
96
+ /** Configuration options */
97
+ config: BatchHistoryConfig;
98
+ }
99
+ /**
100
+ * Advanced hook for managing batch AdjustmentState history with selective undo/redo functionality.
101
+ *
102
+ * Features:
103
+ * - Manages multiple images with individual adjustment states
104
+ * - Selective operations that only affect selected images
105
+ * - Proper history tracking for batch operations
106
+ * - Memory usage monitoring and optimization
107
+ * - Flexible selection management
108
+ *
109
+ * @param imageIds - Array of image IDs to manage
110
+ * @param options - Configuration options for history behavior
111
+ * @returns Object with current batch, selection, history info, actions, and config
112
+ */
113
+ export declare function useAdjustmentHistoryBatch(imageIds: string[], options?: BatchHistoryOptions): UseAdjustmentHistoryBatchReturn;
114
+ export {};
@@ -0,0 +1,444 @@
1
+ import { useState, useCallback, useMemo, useRef, useEffect } from 'react';
2
+ /**
3
+ * Create default adjustment state
4
+ */
5
+ const createDefaultAdjustmentState = (overrides) => ({
6
+ tempScore: 0,
7
+ tintScore: 0,
8
+ vibranceScore: 0,
9
+ saturationScore: 0,
10
+ exposureScore: 0,
11
+ highlightsScore: 0,
12
+ shadowsScore: 0,
13
+ whitesScore: 0,
14
+ blacksScore: 0,
15
+ contrastScore: 0,
16
+ clarityScore: 0,
17
+ sharpnessScore: 0,
18
+ ...overrides
19
+ });
20
+ /**
21
+ * Compare two BatchAdjustmentState objects for equality
22
+ */
23
+ const compareBatchStates = (a, b) => {
24
+ const aKeys = Object.keys(a);
25
+ const bKeys = Object.keys(b);
26
+ if (aKeys.length !== bKeys.length)
27
+ return false;
28
+ for (const key of aKeys) {
29
+ if (!b[key])
30
+ return false;
31
+ try {
32
+ if (JSON.stringify(a[key]) !== JSON.stringify(b[key]))
33
+ return false;
34
+ }
35
+ catch (error) {
36
+ // Fallback comparison
37
+ const stateA = a[key];
38
+ const stateB = b[key];
39
+ if (stateA.tempScore !== stateB.tempScore ||
40
+ stateA.tintScore !== stateB.tintScore ||
41
+ stateA.vibranceScore !== stateB.vibranceScore ||
42
+ stateA.saturationScore !== stateB.saturationScore ||
43
+ stateA.exposureScore !== stateB.exposureScore ||
44
+ stateA.highlightsScore !== stateB.highlightsScore ||
45
+ stateA.shadowsScore !== stateB.shadowsScore ||
46
+ stateA.whitesScore !== stateB.whitesScore ||
47
+ stateA.blacksScore !== stateB.blacksScore ||
48
+ stateA.contrastScore !== stateB.contrastScore ||
49
+ stateA.clarityScore !== stateB.clarityScore ||
50
+ stateA.sharpnessScore !== stateB.sharpnessScore) {
51
+ return false;
52
+ }
53
+ }
54
+ }
55
+ return true;
56
+ };
57
+ /**
58
+ * Advanced hook for managing batch AdjustmentState history with selective undo/redo functionality.
59
+ *
60
+ * Features:
61
+ * - Manages multiple images with individual adjustment states
62
+ * - Selective operations that only affect selected images
63
+ * - Proper history tracking for batch operations
64
+ * - Memory usage monitoring and optimization
65
+ * - Flexible selection management
66
+ *
67
+ * @param imageIds - Array of image IDs to manage
68
+ * @param options - Configuration options for history behavior
69
+ * @returns Object with current batch, selection, history info, actions, and config
70
+ */
71
+ export function useAdjustmentHistoryBatch(imageIds, options = {}) {
72
+ // Stabilize imageIds to prevent unnecessary re-renders
73
+ const stableImageIds = useMemo(() => {
74
+ // Return same reference if content is identical
75
+ return imageIds;
76
+ }, [imageIds.join(',')]); // Only re-memoize if actual content changes
77
+ // Internal stabilization
78
+ const internalOptions = useMemo(() => ({
79
+ maxSize: options.maxSize ?? 'unlimited',
80
+ devWarnings: options.devWarnings ?? false,
81
+ defaultAdjustmentState: options.defaultAdjustmentState ?? {}
82
+ }), [
83
+ options.maxSize,
84
+ options.devWarnings,
85
+ options.defaultAdjustmentState
86
+ ]);
87
+ // Initialize batch state with all images
88
+ const createInitialBatch = useCallback((ids) => {
89
+ const batch = {};
90
+ for (const id of ids) {
91
+ batch[id] = createDefaultAdjustmentState(internalOptions.defaultAdjustmentState);
92
+ }
93
+ return batch;
94
+ }, [internalOptions.defaultAdjustmentState]);
95
+ // Core state management - use stable imageIds for initialization
96
+ const [allImageIds, setAllImageIds] = useState(stableImageIds);
97
+ const [selectedIds, setSelectedIds] = useState(stableImageIds); // Default select all
98
+ const [history, setHistory] = useState(() => [createInitialBatch(stableImageIds)]);
99
+ const [currentIndex, setCurrentIndex] = useState(0);
100
+ const [currentBatch, setCurrentBatch] = useState(() => createInitialBatch(stableImageIds));
101
+ // Configuration refs
102
+ const maxSizeRef = useRef(internalOptions.maxSize);
103
+ const devWarningsRef = useRef(internalOptions.devWarnings);
104
+ // Sync currentBatch with history
105
+ useEffect(() => {
106
+ setCurrentBatch(history[currentIndex]);
107
+ }, [history, currentIndex]);
108
+ // Update when stableImageIds actually changes (content-wise)
109
+ useEffect(() => {
110
+ // Only update if the actual content is different, not just reference
111
+ const currentIdString = allImageIds.join(',');
112
+ const newIdString = stableImageIds.join(',');
113
+ if (currentIdString !== newIdString) {
114
+ const newBatch = createInitialBatch(stableImageIds);
115
+ setAllImageIds([...stableImageIds]); // Create new array to avoid reference issues
116
+ setSelectedIds([...stableImageIds]); // Default select all new images
117
+ setHistory([newBatch]);
118
+ setCurrentIndex(0);
119
+ setCurrentBatch(newBatch);
120
+ if (internalOptions.devWarnings) {
121
+ console.log('useAdjustmentHistoryBatch: ImageIds updated', {
122
+ from: allImageIds,
123
+ to: stableImageIds
124
+ });
125
+ }
126
+ }
127
+ }, [stableImageIds, allImageIds, createInitialBatch, internalOptions.devWarnings]);
128
+ // Memory usage calculation
129
+ const getMemoryUsage = useCallback(() => {
130
+ try {
131
+ const historyString = JSON.stringify(history);
132
+ return historyString.length * 2; // Rough estimate: 2 bytes per character
133
+ }
134
+ catch (error) {
135
+ console.warn('Failed to estimate memory usage:', error);
136
+ return history.length * allImageIds.length * 1000; // Fallback estimate
137
+ }
138
+ }, [history, allImageIds.length]);
139
+ // Trim history to specified size
140
+ const trimHistoryToSize = useCallback((size) => {
141
+ if (size <= 0)
142
+ return;
143
+ setHistory(prevHistory => {
144
+ if (prevHistory.length <= size)
145
+ return prevHistory;
146
+ const startIndex = Math.max(0, prevHistory.length - size);
147
+ const trimmedHistory = prevHistory.slice(startIndex);
148
+ // Adjust current index
149
+ setCurrentIndex(prevIndex => {
150
+ const adjustedIndex = prevIndex - startIndex;
151
+ return Math.max(0, Math.min(adjustedIndex, trimmedHistory.length - 1));
152
+ });
153
+ return trimmedHistory;
154
+ });
155
+ }, []);
156
+ // Apply max size limit
157
+ const enforceMaxSize = useCallback(() => {
158
+ if (maxSizeRef.current === 'unlimited')
159
+ return;
160
+ const maxSize = maxSizeRef.current;
161
+ if (history.length > maxSize) {
162
+ trimHistoryToSize(maxSize);
163
+ }
164
+ }, [history.length, trimHistoryToSize]);
165
+ // Push new batch state to history
166
+ const pushBatchState = useCallback((newBatch) => {
167
+ // Skip if batch hasn't changed
168
+ if (compareBatchStates(newBatch, currentBatch)) {
169
+ return;
170
+ }
171
+ // Update currentBatch immediately for smooth UI
172
+ setCurrentBatch(newBatch);
173
+ // Update history
174
+ setHistory(prevHistory => {
175
+ const truncatedHistory = prevHistory.slice(0, currentIndex + 1);
176
+ const newHistory = [...truncatedHistory, newBatch];
177
+ setCurrentIndex(newHistory.length - 1);
178
+ return newHistory;
179
+ });
180
+ }, [currentBatch, currentIndex]);
181
+ // Apply adjustment deltas to selected images
182
+ const adjustSelected = useCallback((delta) => {
183
+ if (selectedIds.length === 0)
184
+ return;
185
+ const newBatch = { ...currentBatch };
186
+ for (const imageId of selectedIds) {
187
+ if (newBatch[imageId]) {
188
+ newBatch[imageId] = {
189
+ ...newBatch[imageId],
190
+ ...Object.fromEntries(Object.entries(delta).map(([key, value]) => [
191
+ key,
192
+ newBatch[imageId][key] + value
193
+ ]))
194
+ };
195
+ }
196
+ }
197
+ pushBatchState(newBatch);
198
+ }, [selectedIds, currentBatch, pushBatchState]);
199
+ // Set specific adjustment states for specified images
200
+ const setAdjustments = useCallback((adjustments) => {
201
+ const newBatch = { ...currentBatch };
202
+ for (const [imageId, adjustment] of Object.entries(adjustments)) {
203
+ if (newBatch[imageId]) {
204
+ newBatch[imageId] = { ...newBatch[imageId], ...adjustment };
205
+ }
206
+ }
207
+ pushBatchState(newBatch);
208
+ }, [currentBatch, pushBatchState]);
209
+ // Undo last changes to selected images
210
+ const undo = useCallback(() => {
211
+ if (currentIndex > 0 && selectedIds.length > 0) {
212
+ const previousBatch = history[currentIndex - 1];
213
+ const newBatch = { ...currentBatch };
214
+ // Only restore selected images from previous state
215
+ for (const imageId of selectedIds) {
216
+ if (previousBatch[imageId] && newBatch[imageId]) {
217
+ newBatch[imageId] = { ...previousBatch[imageId] };
218
+ }
219
+ }
220
+ // Update current batch and move index back
221
+ setCurrentBatch(newBatch);
222
+ setCurrentIndex(currentIndex - 1);
223
+ // Update the current history entry with the new mixed state
224
+ setHistory(prevHistory => {
225
+ const newHistory = [...prevHistory];
226
+ newHistory[currentIndex] = newBatch;
227
+ return newHistory;
228
+ });
229
+ }
230
+ }, [currentIndex, selectedIds, history, currentBatch]);
231
+ // Redo next changes to selected images
232
+ const redo = useCallback(() => {
233
+ if (currentIndex < history.length - 1 && selectedIds.length > 0) {
234
+ const nextBatch = history[currentIndex + 1];
235
+ const newBatch = { ...currentBatch };
236
+ // Only restore selected images from next state
237
+ for (const imageId of selectedIds) {
238
+ if (nextBatch[imageId] && newBatch[imageId]) {
239
+ newBatch[imageId] = { ...nextBatch[imageId] };
240
+ }
241
+ }
242
+ // Update current batch and move index forward
243
+ setCurrentBatch(newBatch);
244
+ setCurrentIndex(currentIndex + 1);
245
+ // Update the current history entry with the new mixed state
246
+ setHistory(prevHistory => {
247
+ const newHistory = [...prevHistory];
248
+ newHistory[currentIndex + 1] = newBatch;
249
+ return newHistory;
250
+ });
251
+ }
252
+ }, [currentIndex, selectedIds, history, currentBatch]);
253
+ // Reset selected images to default state
254
+ const reset = useCallback((imageIds) => {
255
+ const idsToReset = imageIds || selectedIds;
256
+ if (idsToReset.length === 0)
257
+ return;
258
+ const newBatch = { ...currentBatch };
259
+ const defaultState = createDefaultAdjustmentState(internalOptions.defaultAdjustmentState);
260
+ for (const imageId of idsToReset) {
261
+ if (newBatch[imageId]) {
262
+ newBatch[imageId] = { ...defaultState };
263
+ }
264
+ }
265
+ pushBatchState(newBatch);
266
+ }, [selectedIds, currentBatch, pushBatchState, internalOptions.defaultAdjustmentState]);
267
+ // Selection management
268
+ const setSelection = useCallback((imageIds) => {
269
+ // Validate that all imageIds exist
270
+ const validIds = imageIds.filter(id => allImageIds.includes(id));
271
+ setSelectedIds(validIds);
272
+ if (devWarningsRef.current && validIds.length !== imageIds.length) {
273
+ console.warn('Some image IDs in setSelection do not exist:', imageIds.filter(id => !allImageIds.includes(id)));
274
+ }
275
+ }, [allImageIds]);
276
+ const toggleSelection = useCallback((imageId) => {
277
+ if (!allImageIds.includes(imageId)) {
278
+ if (devWarningsRef.current) {
279
+ console.warn('toggleSelection: Image ID does not exist:', imageId);
280
+ }
281
+ return;
282
+ }
283
+ setSelectedIds(prev => prev.includes(imageId)
284
+ ? prev.filter(id => id !== imageId)
285
+ : [...prev, imageId]);
286
+ }, [allImageIds]);
287
+ const selectAll = useCallback(() => {
288
+ setSelectedIds([...allImageIds]);
289
+ }, [allImageIds]);
290
+ const clearSelection = useCallback(() => {
291
+ setSelectedIds([]);
292
+ }, []);
293
+ // Other history actions
294
+ const jumpToIndex = useCallback((index) => {
295
+ if (index >= 0 && index < history.length) {
296
+ setCurrentIndex(index);
297
+ setCurrentBatch(history[index]);
298
+ }
299
+ }, [history]);
300
+ const clearHistory = useCallback(() => {
301
+ const freshBatch = createInitialBatch(allImageIds);
302
+ setHistory([freshBatch]);
303
+ setCurrentIndex(0);
304
+ setCurrentBatch(freshBatch);
305
+ }, [allImageIds, createInitialBatch]);
306
+ const getCurrentBatch = useCallback(() => {
307
+ return { ...currentBatch };
308
+ }, [currentBatch]);
309
+ const syncBatch = useCallback((newBatch, targetIndex) => {
310
+ // Validate input
311
+ if (!newBatch || typeof newBatch !== 'object') {
312
+ console.warn('syncBatch: newBatch must be a valid BatchAdjustmentState object');
313
+ return;
314
+ }
315
+ // Validate all items are AdjustmentState objects
316
+ const isValidBatch = Object.values(newBatch).every(state => state && typeof state === 'object' &&
317
+ typeof state.tempScore === 'number' &&
318
+ typeof state.tintScore === 'number' &&
319
+ typeof state.vibranceScore === 'number' &&
320
+ typeof state.saturationScore === 'number' &&
321
+ typeof state.exposureScore === 'number' &&
322
+ typeof state.highlightsScore === 'number' &&
323
+ typeof state.shadowsScore === 'number' &&
324
+ typeof state.whitesScore === 'number' &&
325
+ typeof state.blacksScore === 'number' &&
326
+ typeof state.contrastScore === 'number' &&
327
+ typeof state.clarityScore === 'number' &&
328
+ typeof state.sharpnessScore === 'number');
329
+ if (!isValidBatch) {
330
+ console.warn('syncBatch: All values in newBatch must be valid AdjustmentState objects');
331
+ return;
332
+ }
333
+ // Update current state
334
+ setCurrentBatch({ ...newBatch });
335
+ // Replace history with single entry
336
+ setHistory([{ ...newBatch }]);
337
+ setCurrentIndex(0);
338
+ if (devWarningsRef.current) {
339
+ console.log('syncBatch: Synchronized batch state with', Object.keys(newBatch).length, 'images');
340
+ }
341
+ }, []);
342
+ // Configuration actions
343
+ const setMaxSize = useCallback((size) => {
344
+ maxSizeRef.current = size;
345
+ if (size !== 'unlimited') {
346
+ enforceMaxSize();
347
+ }
348
+ }, [enforceMaxSize]);
349
+ const addImages = useCallback((imageIds, selectNew = true) => {
350
+ const newIds = imageIds.filter(id => !allImageIds.includes(id));
351
+ if (newIds.length === 0)
352
+ return;
353
+ const updatedAllIds = [...allImageIds, ...newIds];
354
+ const newBatch = { ...currentBatch };
355
+ // Add default states for new images
356
+ for (const id of newIds) {
357
+ newBatch[id] = createDefaultAdjustmentState(internalOptions.defaultAdjustmentState);
358
+ }
359
+ setAllImageIds(updatedAllIds);
360
+ setCurrentBatch(newBatch);
361
+ // Update history
362
+ setHistory(prevHistory => {
363
+ const newHistory = [...prevHistory];
364
+ newHistory[currentIndex] = newBatch;
365
+ return newHistory;
366
+ });
367
+ // Optionally select new images
368
+ if (selectNew) {
369
+ setSelectedIds(prev => [...prev, ...newIds]);
370
+ }
371
+ }, [allImageIds, currentBatch, currentIndex, internalOptions.defaultAdjustmentState]);
372
+ const removeImages = useCallback((imageIds) => {
373
+ const updatedAllIds = allImageIds.filter(id => !imageIds.includes(id));
374
+ const updatedSelectedIds = selectedIds.filter(id => !imageIds.includes(id));
375
+ const newBatch = { ...currentBatch };
376
+ // Remove images from batch
377
+ for (const id of imageIds) {
378
+ delete newBatch[id];
379
+ }
380
+ setAllImageIds(updatedAllIds);
381
+ setSelectedIds(updatedSelectedIds);
382
+ setCurrentBatch(newBatch);
383
+ // Update history
384
+ setHistory(prevHistory => {
385
+ const newHistory = prevHistory.map(batch => {
386
+ const cleanedBatch = { ...batch };
387
+ for (const id of imageIds) {
388
+ delete cleanedBatch[id];
389
+ }
390
+ return cleanedBatch;
391
+ });
392
+ return newHistory;
393
+ });
394
+ }, [allImageIds, selectedIds, currentBatch]);
395
+ // History info object
396
+ const historyInfo = useMemo(() => ({
397
+ canUndo: currentIndex > 0 && selectedIds.length > 0,
398
+ canRedo: currentIndex < history.length - 1 && selectedIds.length > 0,
399
+ currentIndex,
400
+ totalStates: history.length,
401
+ selectedCount: selectedIds.length,
402
+ totalImages: allImageIds.length,
403
+ historySize: getMemoryUsage()
404
+ }), [currentIndex, history.length, selectedIds.length, allImageIds.length, getMemoryUsage]);
405
+ // Actions object - stabilized with useMemo
406
+ const actions = useMemo(() => ({
407
+ adjustSelected,
408
+ setAdjustments,
409
+ undo,
410
+ redo,
411
+ reset,
412
+ setSelection,
413
+ toggleSelection,
414
+ selectAll,
415
+ clearSelection,
416
+ jumpToIndex,
417
+ clearHistory,
418
+ getCurrentBatch,
419
+ syncBatch
420
+ }), [
421
+ adjustSelected, setAdjustments, undo, redo, reset,
422
+ setSelection, toggleSelection, selectAll, clearSelection,
423
+ jumpToIndex, clearHistory, getCurrentBatch, syncBatch
424
+ ]);
425
+ // Config object - stabilized with useMemo
426
+ const config = useMemo(() => ({
427
+ setMaxSize,
428
+ getMemoryUsage,
429
+ addImages,
430
+ removeImages
431
+ }), [setMaxSize, getMemoryUsage, addImages, removeImages]);
432
+ // Apply max size enforcement when history changes
433
+ useEffect(() => {
434
+ enforceMaxSize();
435
+ }, [enforceMaxSize]);
436
+ return {
437
+ currentBatch,
438
+ selectedIds,
439
+ allImageIds,
440
+ historyInfo,
441
+ actions,
442
+ config
443
+ };
444
+ }
package/dist/index.d.ts CHANGED
@@ -20,6 +20,8 @@ export { default as HModalMobile } from './components/editor/HModalMobile';
20
20
  export { default as HPresetOptionsMenu } from './components/editor/HPresetOptionMenu';
21
21
  export { HAlertInternetBox, HAlertCopyBox, HAlertInternetConnectionBox, HAlertPresetSave } from './components/editor/HAlertBox';
22
22
  export { useHonchoEditorBulk } from './hooks/editor/useHonchoEditorBulk';
23
+ export { useAdjustmentHistory, type UseAdjustmentHistoryReturn, type HistoryInfo, type HistoryActions, type HistoryConfig } from './hooks/useAdjustmentHistory';
24
+ export { useAdjustmentHistoryBatch, type UseAdjustmentHistoryBatchReturn, type BatchAdjustmentState, type BatchHistoryInfo, type BatchHistoryActions, type BatchHistoryConfig } from './hooks/useAdjustmentHistoryBatch';
23
25
  export { default as useColors } from './themes/colors';
24
26
  export { default as useHonchoTypography } from './themes/honchoTheme';
25
27
  export { default as useIsMobile } from './utils/isMobile';
package/dist/index.js CHANGED
@@ -18,6 +18,9 @@ export { default as HModalMobile } from './components/editor/HModalMobile';
18
18
  export { default as HPresetOptionsMenu } from './components/editor/HPresetOptionMenu';
19
19
  export { HAlertInternetBox, HAlertCopyBox, HAlertInternetConnectionBox, HAlertPresetSave } from './components/editor/HAlertBox';
20
20
  export { useHonchoEditorBulk } from './hooks/editor/useHonchoEditorBulk';
21
+ // --- History Hooks ---
22
+ export { useAdjustmentHistory } from './hooks/useAdjustmentHistory';
23
+ export { useAdjustmentHistoryBatch } from './hooks/useAdjustmentHistoryBatch';
21
24
  // --- Theme & Utils ---
22
25
  export { default as useColors } from './themes/colors';
23
26
  export { default as useHonchoTypography } from './themes/honchoTheme';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yogiswara/honcho-editor-ui",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "A complete UI component library for the Honcho photo editor.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",