@yogiswara/honcho-editor-ui 2.1.0 → 2.1.2

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.
@@ -61,24 +61,24 @@ export interface Gallery {
61
61
  uid: string;
62
62
  event_id: string;
63
63
  download: Content;
64
- download_edited: Content | null;
64
+ download_edited: Content;
65
65
  raw?: Content;
66
66
  raw_edited?: Content;
67
67
  raw_preview?: Content;
68
68
  raw_thumbnail?: Content;
69
69
  original?: Content;
70
- original_edited?: Content | null;
70
+ original_edited?: Content;
71
71
  large?: Content;
72
- large_edited?: Content | null;
73
- medium?: Content | null;
74
- medium_edited?: Content | null;
75
- small?: Content | null;
76
- small_edited?: Content | null;
77
- mini?: Content | null;
78
- mini_edited?: Content | null;
72
+ large_edited?: Content;
73
+ medium?: Content;
74
+ medium_edited?: Content;
75
+ small?: Content;
76
+ small_edited?: Content;
77
+ mini?: Content;
78
+ mini_edited?: Content;
79
79
  create_from?: string[];
80
80
  thumbnail: Content;
81
- thumbnail_edited: Content | null;
81
+ thumbnail_edited: Content;
82
82
  is_original: boolean;
83
83
  available: boolean;
84
84
  show_gallery: boolean;
@@ -1,6 +1,15 @@
1
1
  import { SelectChangeEvent } from "@mui/material";
2
2
  import { AdjustmentState, ImageItem, Controller, Preset } from './useHonchoEditor';
3
3
  import { Gallery, ResponseGalleryPaging } from '../../hooks/editor/type';
4
+ export interface PhotoData {
5
+ key: string;
6
+ src: string;
7
+ width: number;
8
+ height: number;
9
+ alt: string;
10
+ isSelected: boolean;
11
+ originalData: Gallery;
12
+ }
4
13
  export interface ControllerBulk {
5
14
  onGetImage(firebaseUid: string, imageID: string): Promise<Gallery>;
6
15
  getImageList(firebaseUid: string, eventID: string, page: number): Promise<ResponseGalleryPaging>;
@@ -11,17 +20,26 @@ export interface ControllerBulk {
11
20
  deletePreset(firebaseUid: string, presetId: string): Promise<void>;
12
21
  }
13
22
  export declare function useHonchoEditorBulk(controllerBulk: Controller, eventID: string, firebaseUid: string): {
23
+ imageCollection: PhotoData[];
24
+ isSelectedMode: boolean;
25
+ isLoading: boolean;
26
+ error: string | null;
27
+ selectedImageIds: string[];
28
+ handleSelectedMode: () => void;
29
+ handleToggleSelect: (photoToToggle: PhotoData) => () => void;
30
+ handlePreview: (photo: PhotoData) => () => void;
31
+ handleBackCallbackBulk: () => void;
14
32
  isBulkEditing: boolean;
15
33
  selectedImages: string;
16
34
  imageList: ImageItem[];
17
- selectedImageIds: Set<string>;
35
+ currentBatch: import("../useAdjustmentHistoryBatch").BatchAdjustmentState;
36
+ selectedIds: string[];
37
+ allImageIds: string[];
18
38
  adjustmentsMap: Map<string, AdjustmentState>;
19
39
  selectedBulkPreset: string;
20
- handleFileChangeBulk: (event: React.ChangeEvent<HTMLInputElement>) => void;
21
40
  handleToggleImageSelection: (imageId: string) => void;
22
41
  toggleBulkEditing: () => void;
23
42
  handleSelectBulkPreset: (event: SelectChangeEvent<string>) => void;
24
- handleBackCallbackBulk: () => void;
25
43
  setTempScore: (value: number) => void;
26
44
  setTintScore: (value: number) => void;
27
45
  setVibranceScore: (value: number) => void;
@@ -1,81 +1,83 @@
1
1
  'use client';
2
- import { useState, useCallback, useEffect } from 'react';
2
+ import { useState, useCallback, useEffect, useMemo } from 'react';
3
3
  import { useAdjustmentHistory } from '../useAdjustmentHistory';
4
4
  import { useAdjustmentHistoryBatch } from '../useAdjustmentHistoryBatch';
5
+ // Helper function to map the API response to the format our UI component needs
6
+ const mapGalleryToPhotoData = (gallery) => ({
7
+ key: gallery.id,
8
+ src: gallery.raw_edited?.path || gallery.download?.path || '',
9
+ width: gallery.raw_edited?.width || 1, // Default to 1 to prevent division by zero
10
+ height: gallery.raw_edited?.height || 1,
11
+ alt: gallery.id || 'gallery image',
12
+ isSelected: false, // All images start as unselected
13
+ originalData: gallery,
14
+ });
5
15
  const initialAdjustments = {
6
16
  tempScore: 0, tintScore: 0, vibranceScore: 0, exposureScore: 0, highlightsScore: 0, shadowsScore: 0,
7
17
  whitesScore: 0, blacksScore: 0, saturationScore: 0, contrastScore: 0, clarityScore: 0, sharpnessScore: 0,
8
18
  };
9
19
  const clamp = (value) => Math.max(-100, Math.min(100, value));
20
+ function mapColorAdjustmentToAdjustmentState(adj) {
21
+ return {
22
+ tempScore: adj.temperature || 0,
23
+ tintScore: adj.tint || 0,
24
+ vibranceScore: adj.vibrance || 0,
25
+ saturationScore: adj.saturation || 0,
26
+ exposureScore: adj.exposure || 0,
27
+ highlightsScore: adj.highlights || 0,
28
+ shadowsScore: adj.shadows || 0,
29
+ whitesScore: adj.whites || 0,
30
+ blacksScore: adj.blacks || 0,
31
+ contrastScore: adj.contrast || 0,
32
+ clarityScore: adj.clarity || 0,
33
+ sharpnessScore: adj.sharpness || 0,
34
+ };
35
+ }
10
36
  export function useHonchoEditorBulk(controllerBulk, eventID, firebaseUid) {
11
- const { currentState, actions: historyActions, historyInfo } = useAdjustmentHistory(initialAdjustments);
12
- const { currentBatch, selectedIds, allImageIds, actions: batchActions, } = useAdjustmentHistoryBatch({
13
- maxSize: historyInfo.historySize,
14
- defaultAdjustmentState: currentState,
15
- });
37
+ const { currentState, actions: historyActions, } = useAdjustmentHistory(initialAdjustments);
38
+ const { currentBatch, selectedIds, allImageIds, actions: batchActions, historyInfo } = useAdjustmentHistoryBatch({});
16
39
  // State for Bulk Editing
40
+ const [imageCollection, setImageCollection] = useState([]);
41
+ const [isSelectedMode, setIsSelectedMode] = useState(false);
42
+ const [isLoading, setIsLoading] = useState(true);
43
+ const [error, setError] = useState(null);
17
44
  const [isBulkEditing, setIsBulkEditing] = useState(false);
18
45
  const [selectedImages, setSelectedImages] = useState('Select');
19
46
  const [imageList, setImageList] = useState([]);
20
- const [selectedImageIds, setSelectedImageIds] = useState(new Set());
21
47
  const [adjustmentsMap, setAdjustmentsMap] = useState(new Map());
22
48
  const [selectedBulkPreset, setSelectedBulkPreset] = useState('preset1');
49
+ const [isEditorReady, setIsEditorReady] = useState(false);
50
+ const selectedImageIds = useMemo(() => imageCollection.filter(p => p.isSelected).map(p => p.key), [imageCollection]);
23
51
  const handleBackCallbackBulk = useCallback(() => {
24
- // 1. Convert the Set of selected IDs into an array to get the last item.
25
- const selectedIdsArray = Array.from(selectedImageIds);
26
- // 2. Determine which ID to send back.
27
- // - If any images are selected, get the ID of the LAST one in the array.
28
- // - If no images are selected, fall back to using the eventID.
29
- const idToSendBack = selectedIdsArray.length > 0
30
- ? selectedIdsArray[selectedIdsArray.length - 1]
31
- : eventID;
32
- // 3. Check if we have an ID to send, otherwise log a warning.
33
- if (!idToSendBack) {
34
- console.warn("handleBack called, but no selected image ID or eventID was available.");
35
- window.history.back();
36
- return;
37
- }
38
- // 4. Call the controller with the chosen ID (either the last imageId or the eventId).
39
- controllerBulk.handleBack(firebaseUid, idToSendBack);
52
+ const lastSelectedId = selectedImageIds.length > 0 ? selectedImageIds[selectedImageIds.length - 1] : eventID;
53
+ controllerBulk.handleBack(firebaseUid, lastSelectedId);
40
54
  }, [controllerBulk, firebaseUid, selectedImageIds, eventID]);
41
- const handleFileChangeBulk = (event) => {
42
- const files = event.target?.files;
43
- if (!files || files.length <= 1) {
44
- // If it's not a bulk operation, we clear the state.
45
- setIsBulkEditing(false);
46
- setImageList([]);
47
- setSelectedImageIds(new Set());
48
- setAdjustmentsMap(new Map());
49
- return;
55
+ const handleSelectedMode = useCallback(() => {
56
+ setIsSelectedMode(true);
57
+ }, []);
58
+ const handleToggleSelect = useCallback((photoToToggle) => () => {
59
+ setImageCollection(currentCollection => currentCollection.map(photo => photo.key === photoToToggle.key
60
+ ? { ...photo, isSelected: !photo.isSelected }
61
+ : photo));
62
+ // Automatically enter selection mode on first selection
63
+ if (!isSelectedMode) {
64
+ setIsSelectedMode(true);
50
65
  }
51
- ;
52
- setIsBulkEditing(true);
53
- const newImageList = Array.from(files).map((file, index) => ({
54
- id: `${file.name}-${Date.now()}-${index}`,
55
- name: file.name,
56
- file: file,
57
- url: URL.createObjectURL(file),
58
- }));
59
- const newAdjustmentsMap = new Map();
60
- newImageList.forEach(image => {
61
- newAdjustmentsMap.set(image.id, { ...initialAdjustments });
62
- });
63
- setAdjustmentsMap(newAdjustmentsMap);
64
- setImageList(newImageList);
65
- setSelectedImageIds(new Set(newImageList.map(img => img.id)));
66
- };
67
- const handleToggleImageSelection = useCallback((imageId) => {
68
- const newSelectedIds = new Set(selectedImageIds);
69
- if (newSelectedIds.has(imageId)) {
70
- if (newSelectedIds.size > 1) { // Prevent deselecting the last image
71
- newSelectedIds.delete(imageId);
72
- }
73
- }
74
- else {
75
- newSelectedIds.add(imageId);
76
- }
77
- setSelectedImageIds(newSelectedIds);
78
- }, [selectedImageIds]);
66
+ }, [isSelectedMode]);
67
+ const handlePreview = useCallback((photo) => () => {
68
+ console.log("Previewing image:", photo.key);
69
+ }, []);
70
+ // const handleToggleImageSelection = useCallback((imageId: string) => {
71
+ // const newSelectedIds = new Set(selectedImageIds);
72
+ // if (newSelectedIds.has(imageId)) {
73
+ // if (newSelectedIds.size > 1) { // Prevent deselecting the last image
74
+ // newSelectedIds.delete(imageId);
75
+ // }
76
+ // } else {
77
+ // newSelectedIds.add(imageId);
78
+ // }
79
+ // setSelectedImageIds(newSelectedIds);
80
+ // }, [selectedImageIds]);
79
81
  const toggleBulkEditing = () => {
80
82
  setIsBulkEditing(prev => {
81
83
  const isNowBulk = !prev;
@@ -85,19 +87,6 @@ export function useHonchoEditorBulk(controllerBulk, eventID, firebaseUid) {
85
87
  };
86
88
  const handleSelectBulkPreset = (event) => setSelectedBulkPreset(event.target.value);
87
89
  // This factory creates functions that adjust a value for all selected images
88
- const createAbsoluteSetter = (key, setter) => (value) => {
89
- setter(value); // Update UI slider
90
- if (isBulkEditing) {
91
- setAdjustmentsMap(prevMap => {
92
- const newMap = new Map(prevMap);
93
- selectedImageIds.forEach(id => {
94
- const currentState = newMap.get(id) || initialAdjustments;
95
- newMap.set(id, { ...currentState, [key]: value });
96
- });
97
- return newMap;
98
- });
99
- }
100
- };
101
90
  const updateAdjustments = useCallback((newValues) => {
102
91
  const newState = { ...currentState, ...newValues };
103
92
  historyActions.pushState(newState);
@@ -108,18 +97,6 @@ export function useHonchoEditorBulk(controllerBulk, eventID, firebaseUid) {
108
97
  const newValue = clamp(currentValue + amount);
109
98
  updateAdjustments({ [key]: newValue });
110
99
  };
111
- useEffect(() => {
112
- if (!isBulkEditing)
113
- return;
114
- setAdjustmentsMap(prevMap => {
115
- const newMap = new Map(prevMap);
116
- selectedImageIds.forEach(id => {
117
- // Apply the new global state to each selected image
118
- newMap.set(id, currentState);
119
- });
120
- return newMap;
121
- });
122
- }, [currentState, selectedImageIds, isBulkEditing]);
123
100
  const setTempScore = (value) => updateAdjustments({ tempScore: value });
124
101
  const setTintScore = (value) => updateAdjustments({ tintScore: value });
125
102
  const setVibranceScore = (value) => updateAdjustments({ vibranceScore: value });
@@ -180,18 +157,57 @@ export function useHonchoEditorBulk(controllerBulk, eventID, firebaseUid) {
180
157
  const handleBulkSharpnessDecrease = createRelativeAdjuster('sharpnessScore', -5);
181
158
  const handleBulkSharpnessIncrease = createRelativeAdjuster('sharpnessScore', 5);
182
159
  const handleBulkSharpnessIncreaseMax = createRelativeAdjuster('sharpnessScore', 20);
160
+ // Extract selected image IDs for other operations (like applying bulk adjustments)
161
+ useEffect(() => {
162
+ if (eventID && firebaseUid) {
163
+ setIsLoading(true);
164
+ setError(null);
165
+ controllerBulk.getImageList(firebaseUid, eventID, 1)
166
+ .then(response => {
167
+ const images = response.gallery;
168
+ // Prepare the initial data for the batch history hook
169
+ const imageConfigs = images.map(img => ({
170
+ imageId: img.id,
171
+ adjustment: img.editor_config?.color_adjustment
172
+ ? mapColorAdjustmentToAdjustmentState(img.editor_config.color_adjustment)
173
+ : initialAdjustments
174
+ }));
175
+ // Populate the batch history with all fetched images
176
+ batchActions.setSelection(imageConfigs);
177
+ // Immediately clear the selection so no images are selected by default
178
+ batchActions.clearSelection();
179
+ })
180
+ .catch(err => {
181
+ console.error("Failed to fetch gallery:", err);
182
+ setError(err.message || "Could not load images.");
183
+ })
184
+ .finally(() => {
185
+ setIsLoading(false);
186
+ });
187
+ }
188
+ }, [eventID, firebaseUid, controllerBulk, batchActions]);
183
189
  return {
190
+ imageCollection,
191
+ isSelectedMode,
192
+ isLoading,
193
+ error,
194
+ selectedImageIds,
195
+ // Gallery Handlers
196
+ handleSelectedMode,
197
+ handleToggleSelect,
198
+ handlePreview,
199
+ handleBackCallbackBulk,
184
200
  isBulkEditing,
185
201
  selectedImages,
186
202
  imageList,
187
- selectedImageIds,
203
+ currentBatch,
204
+ selectedIds,
205
+ allImageIds,
188
206
  adjustmentsMap,
189
207
  selectedBulkPreset,
190
- handleFileChangeBulk,
191
- handleToggleImageSelection,
208
+ handleToggleImageSelection: batchActions.toggleSelection,
192
209
  toggleBulkEditing,
193
210
  handleSelectBulkPreset,
194
- handleBackCallbackBulk,
195
211
  // Bulk Adjustment Handlers
196
212
  setTempScore,
197
213
  setTintScore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yogiswara/honcho-editor-ui",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
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",