@yogiswara/honcho-editor-ui 2.5.9 → 2.6.0
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.
- package/dist/components/editor/HBulkPreset.js +12 -2
- package/dist/hooks/demo/HonchoEditorBulkDemo.d.ts +3 -0
- package/dist/hooks/demo/HonchoEditorBulkDemo.js +228 -0
- package/dist/hooks/demo/HonchoEditorSingleCleanDemo.d.ts +3 -0
- package/dist/hooks/demo/HonchoEditorSingleCleanDemo.js +354 -0
- package/dist/hooks/demo/index.d.ts +2 -0
- package/dist/hooks/demo/index.js +2 -0
- package/dist/hooks/editor/type.d.ts +71 -0
- package/dist/hooks/editor/useHonchoEditorBulk.d.ts +12 -12
- package/dist/hooks/editor/useHonchoEditorBulk.js +155 -42
- package/dist/hooks/editor/useHonchoEditorSingle.d.ts +43 -0
- package/dist/hooks/editor/useHonchoEditorSingle.js +158 -0
- package/dist/hooks/useAdjustmentHistory.d.ts +9 -5
- package/dist/hooks/useAdjustmentHistory.js +187 -31
- package/dist/hooks/useAdjustmentHistoryBatch.d.ts +18 -1
- package/dist/hooks/useAdjustmentHistoryBatch.js +627 -201
- package/dist/hooks/useGallerySwipe.d.ts +1 -1
- package/dist/hooks/usePaging.d.ts +89 -0
- package/dist/hooks/usePaging.js +211 -0
- package/dist/hooks/usePreset.d.ts +1 -1
- package/dist/hooks/usePreset.js +35 -35
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -1
- package/dist/lib/context/EditorContext.d.ts +10 -0
- package/dist/lib/context/EditorContext.js +4 -2
- package/dist/lib/hooks/useEditorHeadless.d.ts +18 -2
- package/dist/lib/hooks/useEditorHeadless.js +142 -63
- package/dist/utils/adjustment.d.ts +2 -1
- package/dist/utils/adjustment.js +16 -0
- package/dist/utils/imageLoader.d.ts +11 -0
- package/dist/utils/imageLoader.js +53 -0
- package/package.json +1 -1
- package/dist/components/editor/GalleryAlbum/SimplifiedAlbumGallery.d.ts +0 -17
- package/dist/components/editor/GalleryAlbum/SimplifiedAlbumGallery.js +0 -14
- package/dist/components/editor/GalleryAlbum/SimplifiedImageItem.d.ts +0 -8
- package/dist/components/editor/GalleryAlbum/SimplifiedImageItem.js +0 -30
- package/dist/components/editor/HImageEditorPage.d.ts +0 -1
- package/dist/components/editor/HImageEditorPage.js +0 -187
- package/dist/hooks/__tests__/useGallerySwipe.test.d.ts +0 -0
- package/dist/hooks/__tests__/useGallerySwipe.test.js +0 -619
- package/dist/hooks/editor/useHonchoEditor.d.ts +0 -203
- package/dist/hooks/editor/useHonchoEditor.js +0 -716
- package/dist/hooks/useAdjustmentHistory.demo.d.ts +0 -8
- package/dist/hooks/useAdjustmentHistory.demo.js +0 -106
- package/dist/hooks/useAdjustmentHistory.example.d.ts +0 -38
- package/dist/hooks/useAdjustmentHistory.example.js +0 -182
- package/dist/hooks/useAdjustmentHistory.syncDemo.d.ts +0 -8
- package/dist/hooks/useAdjustmentHistory.syncDemo.js +0 -180
- package/dist/hooks/useGallerySwipe.example.d.ts +0 -24
- package/dist/hooks/useGallerySwipe.example.js +0 -184
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Gallery } from './editor/type';
|
|
2
|
+
import { Controller } from "./editor/type";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for the paging hook
|
|
5
|
+
*/
|
|
6
|
+
export interface PagingOptions {
|
|
7
|
+
/** Enable development warnings for debugging */
|
|
8
|
+
devWarnings?: boolean;
|
|
9
|
+
/** Auto-load first page on hook initialization */
|
|
10
|
+
autoLoad?: boolean;
|
|
11
|
+
/** Reset pagination when dependencies change */
|
|
12
|
+
autoReset?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Information about the current paging state
|
|
16
|
+
*/
|
|
17
|
+
export interface PagingInfo {
|
|
18
|
+
/** Whether images are currently being loaded */
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
/** Whether more pages are being loaded */
|
|
21
|
+
isLoadingMore: boolean;
|
|
22
|
+
/** Error message if any operation failed */
|
|
23
|
+
error: string | null;
|
|
24
|
+
/** Current page number */
|
|
25
|
+
currentPage: number;
|
|
26
|
+
/** Whether there are more pages to load */
|
|
27
|
+
hasMore: boolean;
|
|
28
|
+
/** Total number of images loaded */
|
|
29
|
+
totalImages: number;
|
|
30
|
+
/** Whether the hook has been initialized */
|
|
31
|
+
isInitialized: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Actions available for paging management
|
|
35
|
+
*/
|
|
36
|
+
export interface PagingActions {
|
|
37
|
+
/** Load more images (next page) - only one instance can run at a time */
|
|
38
|
+
loadMore: () => Promise<void>;
|
|
39
|
+
/** Refresh/reload from first page */
|
|
40
|
+
refresh: () => Promise<void>;
|
|
41
|
+
/** Reset pagination state */
|
|
42
|
+
reset: () => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Return type for the usePaging hook
|
|
46
|
+
*/
|
|
47
|
+
export interface UsePagingReturn {
|
|
48
|
+
/** Current list of images */
|
|
49
|
+
images: Gallery[];
|
|
50
|
+
/** Information about paging state */
|
|
51
|
+
info: PagingInfo;
|
|
52
|
+
/** Available paging actions */
|
|
53
|
+
actions: PagingActions;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Hook for managing paginated image loading with ControllerBulk.
|
|
57
|
+
*
|
|
58
|
+
* **Key Features:**
|
|
59
|
+
* - **Paginated Loading**: Handles page-by-page image loading
|
|
60
|
+
* - **State Management**: Maintains image list and pagination state
|
|
61
|
+
* - **Load More**: Seamlessly loads and appends next pages
|
|
62
|
+
* - **Mutation**: Update specific images without full reload
|
|
63
|
+
* - **Error Handling**: Provides error states for failed operations
|
|
64
|
+
* - **Auto-loading**: Optional automatic first page loading
|
|
65
|
+
*
|
|
66
|
+
* **Typical Usage:**
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const { images, info, actions } = usePaging(controller, firebaseUid, eventId, {
|
|
69
|
+
* autoLoad: true,
|
|
70
|
+
* autoReset: true
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* // Load more images
|
|
74
|
+
* await actions.loadMore();
|
|
75
|
+
*
|
|
76
|
+
* // Refresh from beginning
|
|
77
|
+
* await actions.refresh();
|
|
78
|
+
*
|
|
79
|
+
* // Update specific image
|
|
80
|
+
* actions.mutateImage(imageId, (img) => ({ ...img, isSelected: true }));
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @param controller - Backend controller for API communication
|
|
84
|
+
* @param firebaseUid - User identifier for backend operations
|
|
85
|
+
* @param eventId - Event identifier for image list
|
|
86
|
+
* @param options - Configuration options
|
|
87
|
+
* @returns Object with images, info, and actions
|
|
88
|
+
*/
|
|
89
|
+
export declare function usePaging(controller: Controller | null, firebaseUid: string, eventId: string, options?: PagingOptions): UsePagingReturn;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for managing paginated image loading with ControllerBulk.
|
|
4
|
+
*
|
|
5
|
+
* **Key Features:**
|
|
6
|
+
* - **Paginated Loading**: Handles page-by-page image loading
|
|
7
|
+
* - **State Management**: Maintains image list and pagination state
|
|
8
|
+
* - **Load More**: Seamlessly loads and appends next pages
|
|
9
|
+
* - **Mutation**: Update specific images without full reload
|
|
10
|
+
* - **Error Handling**: Provides error states for failed operations
|
|
11
|
+
* - **Auto-loading**: Optional automatic first page loading
|
|
12
|
+
*
|
|
13
|
+
* **Typical Usage:**
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const { images, info, actions } = usePaging(controller, firebaseUid, eventId, {
|
|
16
|
+
* autoLoad: true,
|
|
17
|
+
* autoReset: true
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Load more images
|
|
21
|
+
* await actions.loadMore();
|
|
22
|
+
*
|
|
23
|
+
* // Refresh from beginning
|
|
24
|
+
* await actions.refresh();
|
|
25
|
+
*
|
|
26
|
+
* // Update specific image
|
|
27
|
+
* actions.mutateImage(imageId, (img) => ({ ...img, isSelected: true }));
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @param controller - Backend controller for API communication
|
|
31
|
+
* @param firebaseUid - User identifier for backend operations
|
|
32
|
+
* @param eventId - Event identifier for image list
|
|
33
|
+
* @param options - Configuration options
|
|
34
|
+
* @returns Object with images, info, and actions
|
|
35
|
+
*/
|
|
36
|
+
export function usePaging(controller, firebaseUid, eventId, options = {}) {
|
|
37
|
+
// Memoize options to prevent re-renders when object is recreated with same values
|
|
38
|
+
const memoizedOptions = useMemo(() => ({
|
|
39
|
+
devWarnings: options.devWarnings ?? false,
|
|
40
|
+
autoLoad: options.autoLoad ?? false,
|
|
41
|
+
autoReset: options.autoReset ?? true
|
|
42
|
+
}), [options.devWarnings, options.autoLoad, options.autoReset]);
|
|
43
|
+
// Core state
|
|
44
|
+
const [images, setImages] = useState([]);
|
|
45
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
46
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
47
|
+
const [error, setError] = useState(null);
|
|
48
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
49
|
+
const [hasMore, setHasMore] = useState(true);
|
|
50
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
51
|
+
// Track if loadMore is currently running to prevent spam
|
|
52
|
+
const isLoadMoreRunningRef = useRef(false);
|
|
53
|
+
// Track dependencies with stable refs
|
|
54
|
+
const controllerRef = useRef(controller);
|
|
55
|
+
const firebaseUidRef = useRef(firebaseUid);
|
|
56
|
+
const eventIdRef = useRef(eventId);
|
|
57
|
+
// Only update refs when values actually change
|
|
58
|
+
if (controllerRef.current !== controller) {
|
|
59
|
+
controllerRef.current = controller;
|
|
60
|
+
}
|
|
61
|
+
if (firebaseUidRef.current !== firebaseUid) {
|
|
62
|
+
firebaseUidRef.current = firebaseUid;
|
|
63
|
+
}
|
|
64
|
+
if (eventIdRef.current !== eventId) {
|
|
65
|
+
eventIdRef.current = eventId;
|
|
66
|
+
}
|
|
67
|
+
// Helper function to log debug messages
|
|
68
|
+
const debugLog = useCallback((message, data) => {
|
|
69
|
+
if (memoizedOptions.devWarnings) {
|
|
70
|
+
console.log(`[usePaging] ${message}`, data || '');
|
|
71
|
+
}
|
|
72
|
+
}, [memoizedOptions.devWarnings]);
|
|
73
|
+
// Helper function to handle errors
|
|
74
|
+
const handleError = useCallback((operation, error) => {
|
|
75
|
+
const errorMessage = `Failed to ${operation}: ${error instanceof Error ? error.message : String(error)}`;
|
|
76
|
+
setError(errorMessage);
|
|
77
|
+
debugLog(`Error in ${operation}`, error);
|
|
78
|
+
}, [debugLog]);
|
|
79
|
+
// Load images for a specific page
|
|
80
|
+
const loadPage = useCallback(async (pageNum, isLoadMore = false) => {
|
|
81
|
+
if (!controllerRef.current || !firebaseUidRef.current || !eventIdRef.current) {
|
|
82
|
+
debugLog('Load skipped: missing controller, firebaseUid, or eventId');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Set appropriate loading state
|
|
86
|
+
if (isLoadMore) {
|
|
87
|
+
setIsLoadingMore(true);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
setIsLoading(true);
|
|
91
|
+
}
|
|
92
|
+
setError(null);
|
|
93
|
+
try {
|
|
94
|
+
debugLog(`Loading page ${pageNum}...`, { isLoadMore });
|
|
95
|
+
const response = await controllerRef.current.getImageList(firebaseUidRef.current, eventIdRef.current, pageNum);
|
|
96
|
+
debugLog('Page loaded successfully', {
|
|
97
|
+
page: response.current_page,
|
|
98
|
+
imageCount: response.gallery.length,
|
|
99
|
+
hasNext: response.next_page > 0
|
|
100
|
+
});
|
|
101
|
+
// Update images list
|
|
102
|
+
setImages(prev => {
|
|
103
|
+
if (isLoadMore) {
|
|
104
|
+
// Append new images for load more
|
|
105
|
+
return [...prev, ...response.gallery];
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Replace all images for initial load or refresh
|
|
109
|
+
return response.gallery;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
// Update pagination state
|
|
113
|
+
setCurrentPage(response.current_page);
|
|
114
|
+
setHasMore(response.next_page > 0 && response.gallery.length > 0);
|
|
115
|
+
if (!isInitialized) {
|
|
116
|
+
setIsInitialized(true);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
handleError(`load page ${pageNum}`, err);
|
|
121
|
+
// On error, don't change images if it's load more
|
|
122
|
+
if (!isLoadMore) {
|
|
123
|
+
setImages([]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
if (isLoadMore) {
|
|
128
|
+
setIsLoadingMore(false);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
setIsLoading(false);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}, [debugLog, handleError, isInitialized]);
|
|
135
|
+
// Load more images (next page) - spam-protected
|
|
136
|
+
const loadMore = useCallback(async () => {
|
|
137
|
+
// Prevent multiple concurrent loadMore calls
|
|
138
|
+
if (isLoadMoreRunningRef.current || isLoadingMore || !hasMore) {
|
|
139
|
+
debugLog('Load more skipped', {
|
|
140
|
+
isLoadMoreRunning: isLoadMoreRunningRef.current,
|
|
141
|
+
isLoadingMore,
|
|
142
|
+
hasMore
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
// Mark as running to prevent spam
|
|
147
|
+
isLoadMoreRunningRef.current = true;
|
|
148
|
+
try {
|
|
149
|
+
debugLog('Loading more images...', { nextPage: currentPage + 1 });
|
|
150
|
+
await loadPage(currentPage + 1, true);
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
// Always reset the running flag
|
|
154
|
+
isLoadMoreRunningRef.current = false;
|
|
155
|
+
}
|
|
156
|
+
}, [isLoadingMore, hasMore, currentPage, loadPage, debugLog]);
|
|
157
|
+
// Refresh from first page
|
|
158
|
+
const refresh = useCallback(async () => {
|
|
159
|
+
debugLog('Refreshing from first page...');
|
|
160
|
+
setCurrentPage(1);
|
|
161
|
+
setHasMore(true);
|
|
162
|
+
await loadPage(1, false);
|
|
163
|
+
}, [loadPage, debugLog]);
|
|
164
|
+
// Reset pagination state
|
|
165
|
+
const reset = useCallback(() => {
|
|
166
|
+
debugLog('Resetting pagination state');
|
|
167
|
+
setImages([]);
|
|
168
|
+
setCurrentPage(1);
|
|
169
|
+
setHasMore(true);
|
|
170
|
+
setError(null);
|
|
171
|
+
setIsInitialized(false);
|
|
172
|
+
// Reset loadMore running flag when page changes
|
|
173
|
+
isLoadMoreRunningRef.current = false;
|
|
174
|
+
}, [debugLog]);
|
|
175
|
+
// Auto-load first page on initialization
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
if (memoizedOptions.autoLoad && controller && firebaseUid && eventId && !isInitialized) {
|
|
178
|
+
debugLog('Auto-loading first page...');
|
|
179
|
+
loadPage(1, false);
|
|
180
|
+
}
|
|
181
|
+
}, [memoizedOptions.autoLoad, controller, firebaseUid, eventId, isInitialized, loadPage, debugLog]);
|
|
182
|
+
// Reset when dependencies change (if autoReset is enabled)
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (memoizedOptions.autoReset && isInitialized) {
|
|
185
|
+
debugLog('Dependencies changed, resetting state');
|
|
186
|
+
reset();
|
|
187
|
+
}
|
|
188
|
+
}, [controller, firebaseUid, eventId, memoizedOptions.autoReset, isInitialized, reset, debugLog]);
|
|
189
|
+
// Paging info object - memoized to prevent re-renders
|
|
190
|
+
const info = useMemo(() => ({
|
|
191
|
+
isLoading,
|
|
192
|
+
isLoadingMore,
|
|
193
|
+
error,
|
|
194
|
+
currentPage,
|
|
195
|
+
hasMore,
|
|
196
|
+
totalImages: images.length,
|
|
197
|
+
isInitialized
|
|
198
|
+
}), [isLoading, isLoadingMore, error, currentPage, hasMore, images.length, isInitialized]);
|
|
199
|
+
// Actions object - memoized to prevent re-renders
|
|
200
|
+
const actions = useMemo(() => ({
|
|
201
|
+
loadMore,
|
|
202
|
+
refresh,
|
|
203
|
+
reset
|
|
204
|
+
}), [loadMore, refresh, reset]);
|
|
205
|
+
// Return object - memoized to prevent re-renders
|
|
206
|
+
return useMemo(() => ({
|
|
207
|
+
images,
|
|
208
|
+
info,
|
|
209
|
+
actions
|
|
210
|
+
}), [images, info, actions]);
|
|
211
|
+
}
|
package/dist/hooks/usePreset.js
CHANGED
|
@@ -42,25 +42,27 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
42
42
|
const [isLoading, setIsLoading] = useState(false);
|
|
43
43
|
const [error, setError] = useState(null);
|
|
44
44
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
45
|
-
// Track controller and firebaseUid changes with stable refs
|
|
46
|
-
const controllerRef = useRef(controller);
|
|
47
|
-
const firebaseUidRef = useRef(firebaseUid);
|
|
48
|
-
// Only update refs when values actually change
|
|
49
|
-
if (controllerRef.current !== controller) {
|
|
50
|
-
controllerRef.current = controller;
|
|
51
|
-
}
|
|
52
|
-
if (firebaseUidRef.current !== firebaseUid) {
|
|
53
|
-
firebaseUidRef.current = firebaseUid;
|
|
54
|
-
}
|
|
55
45
|
// Helper function to log debug messages - memoized to prevent re-renders
|
|
56
46
|
const debugLog = useCallback((message, data) => {
|
|
57
47
|
if (memoizedOptions.devWarnings) {
|
|
58
48
|
console.log(`[usePreset] ${message}`, data || '');
|
|
59
49
|
}
|
|
60
50
|
}, [memoizedOptions.devWarnings]);
|
|
51
|
+
// Stable references for controller and firebaseUid to detect actual changes
|
|
52
|
+
const stableControllerRef = useRef(controller);
|
|
53
|
+
const stableFirebaseUidRef = useRef(firebaseUid);
|
|
54
|
+
const prevStableControllerRef = useRef(controller);
|
|
55
|
+
const prevStableFirebaseUidRef = useRef(firebaseUid);
|
|
56
|
+
// Update refs only when values actually change (by reference)
|
|
57
|
+
if (stableControllerRef.current !== controller) {
|
|
58
|
+
stableControllerRef.current = controller;
|
|
59
|
+
}
|
|
60
|
+
if (stableFirebaseUidRef.current !== firebaseUid) {
|
|
61
|
+
stableFirebaseUidRef.current = firebaseUid;
|
|
62
|
+
}
|
|
61
63
|
// Helper function to handle errors
|
|
62
64
|
const handleError = useCallback((operation, error) => {
|
|
63
|
-
const errorMessage = `Failed to ${operation}: ${error
|
|
65
|
+
const errorMessage = `Failed to ${operation}: ${error instanceof Error ? error.message : String(error)}`;
|
|
64
66
|
setError(errorMessage);
|
|
65
67
|
debugLog(`Error in ${operation}`, error);
|
|
66
68
|
return false;
|
|
@@ -68,50 +70,44 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
68
70
|
// Load presets from backend
|
|
69
71
|
const load = useCallback(async () => {
|
|
70
72
|
console.log("Load Presets Get Function Called");
|
|
71
|
-
if (!
|
|
73
|
+
if (!stableControllerRef.current || !stableFirebaseUidRef.current) {
|
|
72
74
|
debugLog('Load skipped: missing controller or firebaseUid');
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
75
77
|
setIsLoading(true);
|
|
76
78
|
setError(null);
|
|
77
|
-
console.log('before GOINT to load 2.5. STATE UPDATE: setPresets is being called with:', presets);
|
|
78
79
|
try {
|
|
79
80
|
debugLog('Loading presets from backend...');
|
|
80
|
-
const loadedPresets = await
|
|
81
|
-
console.log('✅ 3. STATE UPDATE: setPresets is being called with:', loadedPresets);
|
|
81
|
+
const loadedPresets = await stableControllerRef.current.getPresets(stableFirebaseUidRef.current);
|
|
82
82
|
setPresets(loadedPresets);
|
|
83
|
-
console.log('✅ 4. STATE UPDATE: setIsInitialized is being called with:', true);
|
|
84
|
-
console.log('presets thats called:', presets);
|
|
85
83
|
setIsInitialized(true);
|
|
86
84
|
debugLog('Presets loaded successfully', { count: loadedPresets.length });
|
|
87
85
|
}
|
|
88
86
|
catch (err) {
|
|
89
87
|
handleError('load presets', err);
|
|
90
|
-
console.log('4. catch ERROR!');
|
|
91
88
|
setPresets([]); // Clear presets on error
|
|
92
89
|
}
|
|
93
90
|
finally {
|
|
94
|
-
console.log('5. STATE UPDATE: setIsLoading is being called with:', false);
|
|
95
91
|
setIsLoading(false);
|
|
96
92
|
}
|
|
97
93
|
}, [debugLog, handleError]);
|
|
98
94
|
// Fire-and-forget version of load for internal use
|
|
99
95
|
const loadInBackground = useCallback(() => {
|
|
100
|
-
if (!
|
|
96
|
+
if (!stableControllerRef.current || !stableFirebaseUidRef.current) {
|
|
101
97
|
debugLog('Background load skipped: missing controller or firebaseUid');
|
|
102
98
|
return;
|
|
103
99
|
}
|
|
104
100
|
debugLog('Background loading presets...');
|
|
105
101
|
// Don't set loading state for background operations
|
|
106
|
-
|
|
107
|
-
.then(loadedPresets => {
|
|
102
|
+
stableControllerRef.current.getPresets(stableFirebaseUidRef.current)
|
|
103
|
+
.then((loadedPresets) => {
|
|
108
104
|
setPresets(loadedPresets);
|
|
109
105
|
if (!isInitialized) {
|
|
110
106
|
setIsInitialized(true);
|
|
111
107
|
}
|
|
112
108
|
debugLog('Background presets loaded successfully', { count: loadedPresets.length });
|
|
113
109
|
})
|
|
114
|
-
.catch(err => {
|
|
110
|
+
.catch((err) => {
|
|
115
111
|
debugLog('Background load failed:', err);
|
|
116
112
|
// Don't set error state for background operations
|
|
117
113
|
});
|
|
@@ -119,7 +115,7 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
119
115
|
// Create a new preset
|
|
120
116
|
const create = useCallback(async (name, settings) => {
|
|
121
117
|
console.log("Create Preset Get Function Called");
|
|
122
|
-
if (!
|
|
118
|
+
if (!stableControllerRef.current || !stableFirebaseUidRef.current) {
|
|
123
119
|
debugLog('Create skipped: missing controller or firebaseUid');
|
|
124
120
|
return null;
|
|
125
121
|
}
|
|
@@ -137,7 +133,7 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
137
133
|
try {
|
|
138
134
|
debugLog('Creating preset...', { name, settings });
|
|
139
135
|
// Fire the create request but don't wait for preset data in response
|
|
140
|
-
await
|
|
136
|
+
await stableControllerRef.current.createPreset(stableFirebaseUidRef.current, name, settings);
|
|
141
137
|
debugLog('Preset creation request completed');
|
|
142
138
|
const newPreset = {
|
|
143
139
|
id: `temp-${Date.now()}`, // Use a temporary ID
|
|
@@ -178,7 +174,7 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
178
174
|
}, [presets, debugLog, handleError, loadInBackground]);
|
|
179
175
|
// Rename an existing preset
|
|
180
176
|
const rename = useCallback(async (presetId, newName) => {
|
|
181
|
-
if (!
|
|
177
|
+
if (!stableControllerRef.current || !stableFirebaseUidRef.current) {
|
|
182
178
|
debugLog('Rename skipped: missing controller or firebaseUid');
|
|
183
179
|
return false;
|
|
184
180
|
}
|
|
@@ -201,7 +197,7 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
201
197
|
try {
|
|
202
198
|
debugLog('Renaming preset...', { presetId, oldName: existingPreset.name, newName });
|
|
203
199
|
const updatedPreset = { ...existingPreset, name: newName };
|
|
204
|
-
await
|
|
200
|
+
await stableControllerRef.current.updatePreset(stableFirebaseUidRef.current, updatedPreset);
|
|
205
201
|
// Update local state
|
|
206
202
|
setPresets(prev => prev.map(p => p.id === presetId ? updatedPreset : p));
|
|
207
203
|
debugLog('Preset renamed successfully');
|
|
@@ -218,7 +214,7 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
218
214
|
// Delete a preset
|
|
219
215
|
const deletePreset = useCallback(async (presetId) => {
|
|
220
216
|
console.log("Delete Presets Get Function Called");
|
|
221
|
-
if (!
|
|
217
|
+
if (!stableControllerRef.current || !stableFirebaseUidRef.current) {
|
|
222
218
|
debugLog('Delete skipped: missing controller or firebaseUid');
|
|
223
219
|
return false;
|
|
224
220
|
}
|
|
@@ -231,7 +227,7 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
231
227
|
setError(null);
|
|
232
228
|
try {
|
|
233
229
|
debugLog('Deleting preset...', { presetId, name: existingPreset.name });
|
|
234
|
-
await
|
|
230
|
+
await stableControllerRef.current.deletePreset(stableFirebaseUidRef.current, presetId);
|
|
235
231
|
// Remove from local state
|
|
236
232
|
setPresets(prev => prev.filter(p => p.id !== presetId));
|
|
237
233
|
debugLog('Preset deleted successfully');
|
|
@@ -294,20 +290,24 @@ export function usePreset(controller, firebaseUid, options = {}) {
|
|
|
294
290
|
}, [presets, debugLog]);
|
|
295
291
|
// Auto-load presets on initialization - stable dependencies
|
|
296
292
|
useEffect(() => {
|
|
297
|
-
if (memoizedOptions.autoLoad &&
|
|
293
|
+
if (memoizedOptions.autoLoad && stableControllerRef.current && stableFirebaseUidRef.current && !isInitialized) {
|
|
298
294
|
debugLog('Auto-loading presets...');
|
|
299
295
|
load();
|
|
300
296
|
}
|
|
301
|
-
}, [memoizedOptions.autoLoad,
|
|
302
|
-
// Clear state when controller or firebaseUid changes
|
|
297
|
+
}, [memoizedOptions.autoLoad, isInitialized, load]);
|
|
298
|
+
// Clear state when controller or firebaseUid changes - but only when they actually change
|
|
303
299
|
useEffect(() => {
|
|
304
|
-
|
|
300
|
+
const controllerChanged = prevStableControllerRef.current !== stableControllerRef.current;
|
|
301
|
+
const firebaseUidChanged = prevStableFirebaseUidRef.current !== stableFirebaseUidRef.current;
|
|
302
|
+
if ((controllerChanged || firebaseUidChanged) && isInitialized) {
|
|
305
303
|
debugLog('Controller or firebaseUid changed, clearing state');
|
|
306
|
-
// setPresets([]);
|
|
307
304
|
setError(null);
|
|
308
305
|
setIsInitialized(false);
|
|
306
|
+
// Don't clear presets to avoid flicker - they'll be reloaded
|
|
309
307
|
}
|
|
310
|
-
|
|
308
|
+
prevStableControllerRef.current = stableControllerRef.current;
|
|
309
|
+
prevStableFirebaseUidRef.current = stableFirebaseUidRef.current;
|
|
310
|
+
}, [stableControllerRef.current, stableFirebaseUidRef.current, isInitialized]);
|
|
311
311
|
// Preset info object - memoized to prevent re-renders
|
|
312
312
|
const info = useMemo(() => ({
|
|
313
313
|
isLoading,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type { Controller, AdjustmentState, Preset, ImageItem, } from './hooks/editor/useHonchoEditor';
|
|
1
|
+
export { useHonchoEditorSingle } from './hooks/editor/useHonchoEditorSingle';
|
|
3
2
|
export { useHonchoEditorBulk } from './hooks/editor/useHonchoEditorBulk';
|
|
4
|
-
export type {
|
|
3
|
+
export type { Controller, AdjustmentState, Preset, ImageItem, } from './hooks/editor/type';
|
|
4
|
+
export type { PhotoData } from './hooks/editor/useHonchoEditorBulk';
|
|
5
5
|
export type { Gallery, Content } from './hooks/editor/type';
|
|
6
6
|
export { default as HHeaderEditor } from './components/editor/HHeaderEditor';
|
|
7
7
|
export { default as HFooter } from './components/editor/HFooter';
|
|
@@ -29,6 +29,7 @@ export { useEditorHeadless } from './lib/hooks/useEditorHeadless';
|
|
|
29
29
|
export { useAdjustmentHistory, type UseAdjustmentHistoryReturn, type HistoryInfo, type HistoryActions, type HistoryConfig } from './hooks/useAdjustmentHistory';
|
|
30
30
|
export { useAdjustmentHistoryBatch, type UseAdjustmentHistoryBatchReturn, type BatchAdjustmentState, type ImageAdjustmentConfig, type BatchHistoryInfo, type BatchHistoryActions, type BatchHistoryConfig } from './hooks/useAdjustmentHistoryBatch';
|
|
31
31
|
export { usePreset, type UsePresetReturn, type PresetInfo, type PresetActions, type PresetOptions } from './hooks/usePreset';
|
|
32
|
+
export { usePaging, type UsePagingReturn, type PagingInfo, type PagingActions, type PagingOptions } from './hooks/usePaging';
|
|
32
33
|
export { default as useColors } from './themes/colors';
|
|
33
34
|
export { default as useHonchoTypography } from './themes/honchoTheme';
|
|
34
35
|
export { default as useIsMobile } from './utils/isMobile';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { useHonchoEditorSingle } from './hooks/editor/useHonchoEditorSingle';
|
|
2
2
|
export { useHonchoEditorBulk } from './hooks/editor/useHonchoEditorBulk';
|
|
3
3
|
export { default as HHeaderEditor } from './components/editor/HHeaderEditor';
|
|
4
4
|
export { default as HFooter } from './components/editor/HFooter';
|
|
@@ -28,6 +28,8 @@ export { useAdjustmentHistory } from './hooks/useAdjustmentHistory';
|
|
|
28
28
|
export { useAdjustmentHistoryBatch } from './hooks/useAdjustmentHistoryBatch';
|
|
29
29
|
// --- Preset Hook ---
|
|
30
30
|
export { usePreset } from './hooks/usePreset';
|
|
31
|
+
// --- Paging Hook ---
|
|
32
|
+
export { usePaging } from './hooks/usePaging';
|
|
31
33
|
// --- Theme & Utils ---
|
|
32
34
|
export { default as useColors } from './themes/colors';
|
|
33
35
|
export { default as useHonchoTypography } from './themes/honchoTheme';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { EditorProcessingService } from '../context/EditorProcessingService';
|
|
3
|
+
import HonchoEditor from "../editor/honcho-editor";
|
|
3
4
|
interface EditorContextValue {
|
|
4
5
|
isReady: boolean;
|
|
5
6
|
error: Error | null;
|
|
@@ -9,9 +10,18 @@ interface EditorContextValue {
|
|
|
9
10
|
isProcessing: boolean;
|
|
10
11
|
hasProcessor: boolean;
|
|
11
12
|
};
|
|
13
|
+
editor: HonchoEditor | null;
|
|
14
|
+
loadImageFromUrl: ((url: string) => Promise<{
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}>) | null;
|
|
12
18
|
}
|
|
13
19
|
interface EditorProviderProps {
|
|
14
20
|
children: React.ReactNode;
|
|
21
|
+
/** URL to the honcho-photo-editor.js script (defaults to '/honcho-photo-editor.js') */
|
|
22
|
+
scriptUrl?: string;
|
|
23
|
+
/** URL to the honcho-photo-editor.wasm file (defaults to '/honcho-photo-editor.wasm') */
|
|
24
|
+
wasmUrl?: string;
|
|
15
25
|
}
|
|
16
26
|
export declare const EditorProvider: React.FC<EditorProviderProps>;
|
|
17
27
|
export declare const useEditorContext: () => EditorContextValue;
|
|
@@ -4,9 +4,9 @@ import { createContext, useContext, useEffect, useState } from 'react';
|
|
|
4
4
|
import { useEditorHeadless } from '../hooks/useEditorHeadless';
|
|
5
5
|
import { EditorProcessingService } from '../context/EditorProcessingService';
|
|
6
6
|
const EditorContext = createContext(null);
|
|
7
|
-
export const EditorProvider = ({ children }) => {
|
|
7
|
+
export const EditorProvider = ({ children, scriptUrl = '/honcho-photo-editor.js', wasmUrl = '/honcho-photo-editor.wasm' }) => {
|
|
8
8
|
// Single editor instance for the entire app
|
|
9
|
-
const { editor, isReady, error, processImage } = useEditorHeadless();
|
|
9
|
+
const { editor, isReady, error, processImage, loadImageFromUrl } = useEditorHeadless({ scriptUrl, wasmUrl });
|
|
10
10
|
// Single processing service instance
|
|
11
11
|
const [processingService] = useState(() => new EditorProcessingService());
|
|
12
12
|
const [queueStatus, setQueueStatus] = useState(processingService.getQueueStatus());
|
|
@@ -45,6 +45,8 @@ export const EditorProvider = ({ children }) => {
|
|
|
45
45
|
error,
|
|
46
46
|
processingService,
|
|
47
47
|
queueStatus,
|
|
48
|
+
editor: editor,
|
|
49
|
+
loadImageFromUrl
|
|
48
50
|
};
|
|
49
51
|
return (_jsx(EditorContext.Provider, { value: contextValue, children: children }));
|
|
50
52
|
};
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import { AdjustmentValues, HonchoEditor } from '../editor/honcho-editor';
|
|
1
|
+
import type { AdjustmentValues, HonchoEditor } from '../editor/honcho-editor';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
HonchoEditor: new () => any;
|
|
5
|
+
HonchoEditorUtils: {
|
|
6
|
+
imageDataToBlob: (imageData: ImageData, format?: string, quality?: number) => Promise<Blob>;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
2
10
|
interface EditorTask {
|
|
3
11
|
id: string;
|
|
4
12
|
path: string;
|
|
@@ -9,10 +17,18 @@ interface EditorResponse {
|
|
|
9
17
|
id: string;
|
|
10
18
|
path: string;
|
|
11
19
|
}
|
|
12
|
-
|
|
20
|
+
interface UseEditorHeadlessOptions {
|
|
21
|
+
scriptUrl?: string;
|
|
22
|
+
wasmUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function useEditorHeadless(options?: UseEditorHeadlessOptions): {
|
|
13
25
|
editor: HonchoEditor | null;
|
|
14
26
|
isReady: boolean;
|
|
15
27
|
error: Error | null;
|
|
16
28
|
processImage: (task: EditorTask) => Promise<EditorResponse>;
|
|
29
|
+
loadImageFromUrl: (url: string) => Promise<{
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
}>;
|
|
17
33
|
};
|
|
18
34
|
export {};
|