@yogiswara/honcho-editor-ui 1.4.2 → 1.4.3

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.
@@ -152,6 +152,7 @@ export declare function useHonchoEditor(controller: Controller, initImageId: str
152
152
  handleToggleCopyDialogExpand: (section: "color" | "light" | "details") => void;
153
153
  handleConfirmCopy: () => void;
154
154
  handleCopyEdit: () => void;
155
+ handlePasteEdit: () => void;
155
156
  setActivePanel: import("react").Dispatch<import("react").SetStateAction<string>>;
156
157
  setActiveSubPanel: import("react").Dispatch<import("react").SetStateAction<string>>;
157
158
  setHeaderMenuAnchorEl: import("react").Dispatch<import("react").SetStateAction<HTMLElement | null>>;
@@ -91,59 +91,6 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
91
91
  const initialHeight = useRef(0);
92
92
  const panelRef = useRef(null);
93
93
  const contentRef = useRef(null);
94
- // Mobile Panel Drag Handlers
95
- const handleContentHeightChange = useCallback((height) => {
96
- if (height > 0 && height !== contentHeight)
97
- setContentHeight(height);
98
- }, [contentHeight]);
99
- const handleDragStart = useCallback((e) => {
100
- setIsDragging(true);
101
- const startY = 'touches' in e ? e.touches[0].clientY : e.clientY;
102
- dragStartPos.current = startY;
103
- initialHeight.current = panelHeight;
104
- if (panelRef.current)
105
- panelRef.current.style.transition = 'none';
106
- }, [panelHeight]);
107
- const handleDragMove = useCallback((e) => {
108
- if (!isDragging)
109
- return;
110
- const currentY = 'touches' in e ? e.touches[0].clientY : e.clientY;
111
- const deltaY = dragStartPos.current - currentY;
112
- const newHeight = initialHeight.current + deltaY;
113
- const dynamicPanelFullHeight = contentHeight + PANEL_CHROME_HEIGHT;
114
- const clampedHeight = Math.max(PEEK_HEIGHT, Math.min(newHeight, dynamicPanelFullHeight));
115
- setPanelHeight(clampedHeight);
116
- }, [isDragging, contentHeight]);
117
- const handleDragEnd = useCallback(() => {
118
- if (!isDragging)
119
- return;
120
- setIsDragging(false);
121
- dragStartPos.current = 0;
122
- if (panelRef.current)
123
- panelRef.current.style.transition = 'height 0.3s ease-in-out';
124
- const dynamicPanelFullHeight = contentHeight + PANEL_CHROME_HEIGHT;
125
- const snapPointLow = (PEEK_HEIGHT + COLLAPSED_HEIGHT) / 2;
126
- const snapPointHigh = (COLLAPSED_HEIGHT + dynamicPanelFullHeight) / 2;
127
- if (panelHeight < snapPointLow) {
128
- setPanelHeight(PEEK_HEIGHT);
129
- }
130
- else if (panelHeight >= snapPointLow && panelHeight < snapPointHigh) {
131
- setPanelHeight(COLLAPSED_HEIGHT);
132
- }
133
- else {
134
- setPanelHeight(dynamicPanelFullHeight);
135
- }
136
- }, [isDragging, panelHeight, contentHeight]);
137
- // Keyboard Shortcut Handler
138
- const handleKeyDown = useCallback((event) => {
139
- const target = event.target;
140
- if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')
141
- return;
142
- if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
143
- event.preventDefault();
144
- handleOpenCopyDialog(); // Assumes handleOpenCopyDialog is defined in the hook
145
- }
146
- }, [ /* handleOpenCopyDialog dependency */]);
147
94
  // Effect for measuring mobile panel content
148
95
  // useEffect(() => {
149
96
  // const timeoutId = setTimeout(() => {
@@ -157,40 +104,6 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
157
104
  // isBulkEditing
158
105
  // Effect for keyboard shortcuts
159
106
  // MARK: - Core Editor Logic
160
- const updateCanvasEditor = useCallback(() => {
161
- if ((editorRef.current?.getInitialized() === true) && canvasRef.current) {
162
- editorRef.current.processImage();
163
- editorRef.current.renderToCanvas(canvasRef.current);
164
- }
165
- }, [canvasRef.current, editorRef.current]);
166
- const extractPathFromGallery = useCallback((data) => {
167
- const imagePath = data?.raw_edited?.path
168
- ? data.raw_edited.path
169
- : data?.download?.path;
170
- console.log("[DEBUG] Extracted imagePath to load:", imagePath);
171
- return imagePath;
172
- }, []);
173
- const loadImageEditorFromUrl = useCallback(async (url) => {
174
- try {
175
- if (!editorRef.current)
176
- return;
177
- setEditorStatus("Downloading image...");
178
- console.log(`[DEBUG] Attempting to fetch image from URL: ${url}`);
179
- const response = await fetch(url);
180
- if (!response.ok)
181
- throw new Error(`Failed to fetch image from URL: ${url}`);
182
- const blob = await response.blob();
183
- const filename = url.substring(url.lastIndexOf('/') + 1) || 'image.jpg';
184
- const file = new File([blob], filename, { type: blob.type });
185
- await editorRef.current.loadImageFromFile(file);
186
- setIsImageLoaded(true);
187
- }
188
- catch (error) {
189
- console.error(error);
190
- setEditorStatus("Error: Could not load image from URL.");
191
- setIsImageLoaded(false);
192
- }
193
- }, [editorRef.current]);
194
107
  // MARK: Batch Edit logic
195
108
  // const handleToggleImageSelection = useCallback((imageId: string) => {
196
109
  // const newSelectedIds = new Set(selectedImageIds);
@@ -305,6 +218,93 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
305
218
  // const handleBulkSharpnessDecrease = createRelativeAdjuster('sharpnessScore', setSharpnessScore, -5);
306
219
  // const handleBulkSharpnessIncrease = createRelativeAdjuster('sharpnessScore', setSharpnessScore, 5);
307
220
  // const handleBulkSharpnessIncreaseMax = createRelativeAdjuster('sharpnessScore', setSharpnessScore, 20);
221
+ // Mobile Panel Drag Handlers
222
+ const handleContentHeightChange = useCallback((height) => {
223
+ if (height > 0 && height !== contentHeight)
224
+ setContentHeight(height);
225
+ }, [contentHeight]);
226
+ const handleDragStart = useCallback((e) => {
227
+ setIsDragging(true);
228
+ const startY = 'touches' in e ? e.touches[0].clientY : e.clientY;
229
+ dragStartPos.current = startY;
230
+ initialHeight.current = panelHeight;
231
+ if (panelRef.current)
232
+ panelRef.current.style.transition = 'none';
233
+ }, [panelHeight]);
234
+ const handleDragMove = useCallback((e) => {
235
+ if (!isDragging)
236
+ return;
237
+ const currentY = 'touches' in e ? e.touches[0].clientY : e.clientY;
238
+ const deltaY = dragStartPos.current - currentY;
239
+ const newHeight = initialHeight.current + deltaY;
240
+ const dynamicPanelFullHeight = contentHeight + PANEL_CHROME_HEIGHT;
241
+ const clampedHeight = Math.max(PEEK_HEIGHT, Math.min(newHeight, dynamicPanelFullHeight));
242
+ setPanelHeight(clampedHeight);
243
+ }, [isDragging, contentHeight]);
244
+ const handleDragEnd = useCallback(() => {
245
+ if (!isDragging)
246
+ return;
247
+ setIsDragging(false);
248
+ dragStartPos.current = 0;
249
+ if (panelRef.current)
250
+ panelRef.current.style.transition = 'height 0.3s ease-in-out';
251
+ const dynamicPanelFullHeight = contentHeight + PANEL_CHROME_HEIGHT;
252
+ const snapPointLow = (PEEK_HEIGHT + COLLAPSED_HEIGHT) / 2;
253
+ const snapPointHigh = (COLLAPSED_HEIGHT + dynamicPanelFullHeight) / 2;
254
+ if (panelHeight < snapPointLow) {
255
+ setPanelHeight(PEEK_HEIGHT);
256
+ }
257
+ else if (panelHeight >= snapPointLow && panelHeight < snapPointHigh) {
258
+ setPanelHeight(COLLAPSED_HEIGHT);
259
+ }
260
+ else {
261
+ setPanelHeight(dynamicPanelFullHeight);
262
+ }
263
+ }, [isDragging, panelHeight, contentHeight]);
264
+ // Keyboard Shortcut Handler
265
+ const handleKeyDown = useCallback((event) => {
266
+ const target = event.target;
267
+ if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')
268
+ return;
269
+ if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
270
+ event.preventDefault();
271
+ handleOpenCopyDialog(); // Assumes handleOpenCopyDialog is defined in the hook
272
+ }
273
+ }, [ /* handleOpenCopyDialog dependency */]);
274
+ const updateCanvasEditor = useCallback(() => {
275
+ if ((editorRef.current?.getInitialized() === true) && canvasRef.current) {
276
+ editorRef.current.processImage();
277
+ editorRef.current.renderToCanvas(canvasRef.current);
278
+ }
279
+ }, [canvasRef.current, editorRef.current]);
280
+ const extractPathFromGallery = useCallback((data) => {
281
+ const imagePath = data?.raw_edited?.path
282
+ ? data.raw_edited.path
283
+ : data?.download?.path;
284
+ console.log("[DEBUG] Extracted imagePath to load:", imagePath);
285
+ return imagePath;
286
+ }, []);
287
+ const loadImageEditorFromUrl = useCallback(async (url) => {
288
+ try {
289
+ if (!editorRef.current)
290
+ return;
291
+ setEditorStatus("Downloading image...");
292
+ console.log(`[DEBUG] Attempting to fetch image from URL: ${url}`);
293
+ const response = await fetch(url);
294
+ if (!response.ok)
295
+ throw new Error(`Failed to fetch image from URL: ${url}`);
296
+ const blob = await response.blob();
297
+ const filename = url.substring(url.lastIndexOf('/') + 1) || 'image.jpg';
298
+ const file = new File([blob], filename, { type: blob.type });
299
+ await editorRef.current.loadImageFromFile(file);
300
+ setIsImageLoaded(true);
301
+ }
302
+ catch (error) {
303
+ console.error(error);
304
+ setEditorStatus("Error: Could not load image from URL.");
305
+ setIsImageLoaded(false);
306
+ }
307
+ }, [editorRef.current]);
308
308
  const handleScriptReady = useCallback(async () => {
309
309
  console.log("[Editor] Script tag is ready."); // Log entry
310
310
  if (typeof window.Module === 'function' && !editorRef.current) {
@@ -336,94 +336,6 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
336
336
  controller.handleBack(firebaseUid, galleryImageData.id);
337
337
  }, [controller, firebaseUid, galleryImageData]);
338
338
  // MARK: - UI Handlers (Moved from page.tsx)
339
- // Header and Dialog Handlers
340
- const handleHeaderMenuClick = (event) => setHeaderMenuAnchorEl(event.currentTarget);
341
- const handleHeaderMenuClose = () => setHeaderMenuAnchorEl(null);
342
- const handleAlertClose = () => {
343
- setIsConnectionSlow(false);
344
- };
345
- const handleOpenCopyDialog = () => {
346
- const newColorChecks = {
347
- temperature: currentAdjustmentsState.tempScore !== 0,
348
- tint: currentAdjustmentsState.tintScore !== 0,
349
- vibrance: currentAdjustmentsState.vibranceScore !== 0,
350
- saturation: currentAdjustmentsState.saturationScore !== 0,
351
- };
352
- const newLightChecks = {
353
- exposure: currentAdjustmentsState.exposureScore !== 0,
354
- contrast: currentAdjustmentsState.contrastScore !== 0,
355
- highlights: currentAdjustmentsState.highlightsScore !== 0,
356
- shadows: currentAdjustmentsState.shadowsScore !== 0,
357
- whites: currentAdjustmentsState.whitesScore !== 0,
358
- blacks: currentAdjustmentsState.blacksScore !== 0,
359
- };
360
- const newDetailsChecks = {
361
- clarity: currentAdjustmentsState.clarityScore !== 0,
362
- sharpness: currentAdjustmentsState.sharpnessScore !== 0,
363
- };
364
- setCopyColorChecks(newColorChecks);
365
- setCopyLightChecks(newLightChecks);
366
- setCopyDetailsChecks(newDetailsChecks);
367
- setCopyDialogExpanded({
368
- color: Object.values(newColorChecks).some(isChecked => isChecked),
369
- light: Object.values(newLightChecks).some(isChecked => isChecked),
370
- details: Object.values(newDetailsChecks).some(isChecked => isChecked),
371
- });
372
- setCopyDialogOpen(true);
373
- handleHeaderMenuClose();
374
- };
375
- const handleCloseCopyDialog = () => setCopyDialogOpen(false);
376
- const handleCopyParentChange = (event, setter) => {
377
- const isChecked = event.target.checked;
378
- setter((prev) => {
379
- const newState = {};
380
- Object.keys(prev).forEach(key => { newState[key] = isChecked; });
381
- return newState;
382
- });
383
- };
384
- const handleCopyChildChange = (event, setter) => {
385
- setter((prev) => ({
386
- ...prev,
387
- [event.target.name]: event.target.checked,
388
- }));
389
- };
390
- const handleToggleCopyDialogExpand = (section) => {
391
- setCopyDialogExpanded(prev => ({ ...prev, [section]: !prev[section] }));
392
- };
393
- const handleCopyEdit = useCallback(() => {
394
- const adjustmentsToCopy = {};
395
- // Color Adjustments
396
- if (copyColorChecks.temperature)
397
- adjustmentsToCopy.tempScore = currentAdjustmentsState.tempScore;
398
- if (copyColorChecks.tint)
399
- adjustmentsToCopy.tintScore = currentAdjustmentsState.tintScore;
400
- if (copyColorChecks.vibrance)
401
- adjustmentsToCopy.vibranceScore = currentAdjustmentsState.vibranceScore;
402
- if (copyColorChecks.saturation)
403
- adjustmentsToCopy.saturationScore = currentAdjustmentsState.saturationScore;
404
- // Light Adjustments
405
- if (copyLightChecks.exposure)
406
- adjustmentsToCopy.exposureScore = currentAdjustmentsState.exposureScore;
407
- if (copyLightChecks.contrast)
408
- adjustmentsToCopy.contrastScore = currentAdjustmentsState.contrastScore;
409
- if (copyLightChecks.highlights)
410
- adjustmentsToCopy.highlightsScore = currentAdjustmentsState.highlightsScore;
411
- if (copyLightChecks.shadows)
412
- adjustmentsToCopy.shadowsScore = currentAdjustmentsState.shadowsScore;
413
- if (copyLightChecks.whites)
414
- adjustmentsToCopy.whitesScore = currentAdjustmentsState.whitesScore;
415
- if (copyLightChecks.blacks)
416
- adjustmentsToCopy.blacksScore = currentAdjustmentsState.blacksScore;
417
- // Details Adjustments
418
- if (copyDetailsChecks.clarity)
419
- adjustmentsToCopy.clarityScore = currentAdjustmentsState.clarityScore;
420
- if (copyDetailsChecks.sharpness)
421
- adjustmentsToCopy.sharpnessScore = currentAdjustmentsState.sharpnessScore;
422
- // Combine with existing copied adjustments to not lose unchecked values from a previous copy
423
- setCopiedAdjustments(prev => ({ ...initialAdjustments, ...prev, ...adjustmentsToCopy }));
424
- console.log("Copied selected adjustments:", adjustmentsToCopy);
425
- }, [copyColorChecks, copyLightChecks, copyDetailsChecks, currentAdjustmentsState]);
426
- const handleConfirmCopy = () => { handleCopyEdit(); handleCloseCopyDialog(); setShowCopyAlert(true); };
427
339
  // MARK: - UI Handlers
428
340
  // Panel Handlers
429
341
  const handleColorAccordionChange = (panel) => (_, isExpanded) => {
@@ -601,6 +513,100 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
601
513
  const setContrastScore = (value) => updateAdjustments({ contrastScore: value });
602
514
  const setClarityScore = (value) => updateAdjustments({ clarityScore: value });
603
515
  const setSharpnessScore = (value) => updateAdjustments({ sharpnessScore: value });
516
+ // MARK: Copied ClipBoard
517
+ const handleHeaderMenuClick = (event) => setHeaderMenuAnchorEl(event.currentTarget);
518
+ const handleHeaderMenuClose = () => setHeaderMenuAnchorEl(null);
519
+ const handleAlertClose = () => {
520
+ setIsConnectionSlow(false);
521
+ };
522
+ const handleOpenCopyDialog = () => {
523
+ const newColorChecks = {
524
+ temperature: currentAdjustmentsState.tempScore !== 0,
525
+ tint: currentAdjustmentsState.tintScore !== 0,
526
+ vibrance: currentAdjustmentsState.vibranceScore !== 0,
527
+ saturation: currentAdjustmentsState.saturationScore !== 0,
528
+ };
529
+ const newLightChecks = {
530
+ exposure: currentAdjustmentsState.exposureScore !== 0,
531
+ contrast: currentAdjustmentsState.contrastScore !== 0,
532
+ highlights: currentAdjustmentsState.highlightsScore !== 0,
533
+ shadows: currentAdjustmentsState.shadowsScore !== 0,
534
+ whites: currentAdjustmentsState.whitesScore !== 0,
535
+ blacks: currentAdjustmentsState.blacksScore !== 0,
536
+ };
537
+ const newDetailsChecks = {
538
+ clarity: currentAdjustmentsState.clarityScore !== 0,
539
+ sharpness: currentAdjustmentsState.sharpnessScore !== 0,
540
+ };
541
+ setCopyColorChecks(newColorChecks);
542
+ setCopyLightChecks(newLightChecks);
543
+ setCopyDetailsChecks(newDetailsChecks);
544
+ setCopyDialogExpanded({
545
+ color: Object.values(newColorChecks).some(isChecked => isChecked),
546
+ light: Object.values(newLightChecks).some(isChecked => isChecked),
547
+ details: Object.values(newDetailsChecks).some(isChecked => isChecked),
548
+ });
549
+ setCopyDialogOpen(true);
550
+ handleHeaderMenuClose();
551
+ };
552
+ const handleCopyParentChange = (event, setter) => {
553
+ const isChecked = event.target.checked;
554
+ setter((prev) => {
555
+ const newState = {};
556
+ Object.keys(prev).forEach(key => { newState[key] = isChecked; });
557
+ return newState;
558
+ });
559
+ };
560
+ const handleCopyChildChange = (event, setter) => {
561
+ setter((prev) => ({
562
+ ...prev,
563
+ [event.target.name]: event.target.checked,
564
+ }));
565
+ };
566
+ const handleToggleCopyDialogExpand = (section) => {
567
+ setCopyDialogExpanded(prev => ({ ...prev, [section]: !prev[section] }));
568
+ };
569
+ const handleCopyEdit = useCallback(() => {
570
+ const adjustmentsToCopy = {};
571
+ // Color Adjustments
572
+ if (copyColorChecks.temperature)
573
+ adjustmentsToCopy.tempScore = currentAdjustmentsState.tempScore;
574
+ if (copyColorChecks.tint)
575
+ adjustmentsToCopy.tintScore = currentAdjustmentsState.tintScore;
576
+ if (copyColorChecks.vibrance)
577
+ adjustmentsToCopy.vibranceScore = currentAdjustmentsState.vibranceScore;
578
+ if (copyColorChecks.saturation)
579
+ adjustmentsToCopy.saturationScore = currentAdjustmentsState.saturationScore;
580
+ // Light Adjustments
581
+ if (copyLightChecks.exposure)
582
+ adjustmentsToCopy.exposureScore = currentAdjustmentsState.exposureScore;
583
+ if (copyLightChecks.contrast)
584
+ adjustmentsToCopy.contrastScore = currentAdjustmentsState.contrastScore;
585
+ if (copyLightChecks.highlights)
586
+ adjustmentsToCopy.highlightsScore = currentAdjustmentsState.highlightsScore;
587
+ if (copyLightChecks.shadows)
588
+ adjustmentsToCopy.shadowsScore = currentAdjustmentsState.shadowsScore;
589
+ if (copyLightChecks.whites)
590
+ adjustmentsToCopy.whitesScore = currentAdjustmentsState.whitesScore;
591
+ if (copyLightChecks.blacks)
592
+ adjustmentsToCopy.blacksScore = currentAdjustmentsState.blacksScore;
593
+ // Details Adjustments
594
+ if (copyDetailsChecks.clarity)
595
+ adjustmentsToCopy.clarityScore = currentAdjustmentsState.clarityScore;
596
+ if (copyDetailsChecks.sharpness)
597
+ adjustmentsToCopy.sharpnessScore = currentAdjustmentsState.sharpnessScore;
598
+ // Combine with existing copied adjustments to not lose unchecked values from a previous copy
599
+ setCopiedAdjustments(prev => ({ ...initialAdjustments, ...prev, ...adjustmentsToCopy }));
600
+ console.log("Copied selected adjustments:", adjustmentsToCopy);
601
+ }, [copyColorChecks, copyLightChecks, copyDetailsChecks, currentAdjustmentsState]);
602
+ const handlePasteEdit = useCallback(() => {
603
+ if (!copiedAdjustments)
604
+ return;
605
+ updateAdjustments(copiedAdjustments);
606
+ handleHeaderMenuClose();
607
+ }, [copiedAdjustments, updateAdjustments]);
608
+ const handleCloseCopyDialog = () => setCopyDialogOpen(false);
609
+ const handleConfirmCopy = () => { handleCopyEdit(); handleCloseCopyDialog(); setShowCopyAlert(true); };
604
610
  // MARK: useEffect HERE!
605
611
  useEffect(() => {
606
612
  if (showCopyAlert) {
@@ -793,6 +799,7 @@ export function useHonchoEditor(controller, initImageId, firebaseUid) {
793
799
  handleToggleCopyDialogExpand,
794
800
  handleConfirmCopy,
795
801
  handleCopyEdit,
802
+ handlePasteEdit,
796
803
  // adjustClarityBulk,
797
804
  // adjustSharpnessBulk,
798
805
  // Setters & Handlers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yogiswara/honcho-editor-ui",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
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",