@yogiswara/honcho-editor-ui 2.0.7 → 2.1.1
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/color.d.ts +9 -0
- package/dist/color.js +9 -0
- package/dist/components/editor/GalleryAlbum/AlbumImageGallery.d.ts +18 -0
- package/dist/components/editor/GalleryAlbum/AlbumImageGallery.js +32 -52
- package/dist/components/editor/GalleryAlbum/ImageItem.d.ts +28 -0
- package/dist/components/editor/GalleryAlbum/ImageItem.js +165 -246
- package/dist/components/editor/svg/Tick.d.ts +2 -0
- package/dist/components/editor/svg/Tick.js +6 -0
- package/dist/hooks/editor/useHonchoEditorBulk.d.ts +21 -3
- package/dist/hooks/editor/useHonchoEditorBulk.js +105 -89
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +2 -1
package/dist/color.d.ts
ADDED
package/dist/color.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { GallerySetup } from "../../../hooks/editor/type";
|
|
3
|
+
import { AdjustmentValues } from "../../../lib/editor/honcho-editor";
|
|
4
|
+
interface PhotoData extends GallerySetup {
|
|
5
|
+
adjustments?: Partial<AdjustmentValues>;
|
|
6
|
+
frame?: string;
|
|
7
|
+
}
|
|
8
|
+
interface ImageGalleryProps {
|
|
9
|
+
imageCollection: PhotoData[];
|
|
10
|
+
isSelectedMode: boolean;
|
|
11
|
+
isHiddenGallery: boolean;
|
|
12
|
+
enableEditor: boolean;
|
|
13
|
+
onPreview: (photo: PhotoData) => () => void;
|
|
14
|
+
onSelectedMode: () => void;
|
|
15
|
+
onToggleSelect: (photo: PhotoData) => () => void;
|
|
16
|
+
}
|
|
17
|
+
declare const AlbumImageGallery: React.FC<ImageGalleryProps>;
|
|
18
|
+
export default AlbumImageGallery;
|
|
@@ -1,52 +1,32 @@
|
|
|
1
|
-
"use
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// index={index}
|
|
34
|
-
// photo={photo}
|
|
35
|
-
// direction="column"
|
|
36
|
-
// isFullScreenMode={false}
|
|
37
|
-
// isSelected={photo.isSelected}
|
|
38
|
-
// isSelectedMode={isSelectedMode}
|
|
39
|
-
// isHiddenGallery={isHiddenGallery}
|
|
40
|
-
// onPreview={onPreview(photo)}
|
|
41
|
-
// onSelectedMode={onSelectedMode}
|
|
42
|
-
// onToggleSelect={onToggleSelect(photo)}
|
|
43
|
-
// frame={photo.frame}
|
|
44
|
-
// />
|
|
45
|
-
// </Box>
|
|
46
|
-
// ))}
|
|
47
|
-
// </Masonry>
|
|
48
|
-
// </ResponsiveMasonry>
|
|
49
|
-
// </section>
|
|
50
|
-
// );
|
|
51
|
-
// };
|
|
52
|
-
// export default AlbumImageGallery;
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Box } from "@mui/material";
|
|
4
|
+
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry";
|
|
5
|
+
import GalleryImageItem from "./ImageItem";
|
|
6
|
+
const AlbumImageGallery = (props) => {
|
|
7
|
+
const { imageCollection, isSelectedMode, isHiddenGallery, enableEditor, // Destructure the new prop
|
|
8
|
+
onPreview, onSelectedMode, onToggleSelect, } = props;
|
|
9
|
+
return (_jsx("section", { children: _jsx(ResponsiveMasonry, { columnsCountBreakPoints: { 750: 2, 900: 4 }, children: _jsx(Masonry, { children: imageCollection.map((photo, index) => {
|
|
10
|
+
// This guard clause is still important for runtime safety.
|
|
11
|
+
if (!photo.key || !photo.src) {
|
|
12
|
+
console.warn("Skipping item without a key or src:", photo);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
// NEW: Create a new object that matches the 'PhotoProps' interface.
|
|
16
|
+
// This explicitly tells TypeScript that all required fields are present.
|
|
17
|
+
const imageItemPhotoProps = {
|
|
18
|
+
key: photo.key,
|
|
19
|
+
src: photo.src,
|
|
20
|
+
width: photo.width,
|
|
21
|
+
height: photo.height,
|
|
22
|
+
alt: photo.alt,
|
|
23
|
+
// We pass the original photo object in the generic 'photo' property
|
|
24
|
+
// in case ImageItem needs it for other operations.
|
|
25
|
+
photo: photo,
|
|
26
|
+
};
|
|
27
|
+
return (_jsx(Box, { sx: { m: 0.5 }, children: _jsx(GalleryImageItem, { margin: "0px", index: index,
|
|
28
|
+
// UPDATED: Pass the new, correctly-typed object.
|
|
29
|
+
photo: imageItemPhotoProps, direction: "column", isFullScreenMode: false, isSelected: photo.isSelected, isSelectedMode: isSelectedMode, isHiddenGallery: isHiddenGallery, onPreview: onPreview(photo), onSelectedMode: onSelectedMode, onToggleSelect: onToggleSelect(photo), enableEditor: enableEditor, adjustments: photo.adjustments, frame: photo.frame }) }, photo.key));
|
|
30
|
+
}) }) }) }));
|
|
31
|
+
};
|
|
32
|
+
export default AlbumImageGallery;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AdjustmentValues } from "../../../lib/editor/honcho-editor";
|
|
2
|
+
import { GallerySetup } from "../../../hooks/editor/type";
|
|
3
|
+
interface PhotoProps<T> {
|
|
4
|
+
src: string;
|
|
5
|
+
alt?: string;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
key: string;
|
|
9
|
+
photo?: T;
|
|
10
|
+
}
|
|
11
|
+
interface Props {
|
|
12
|
+
margin?: any;
|
|
13
|
+
index: number;
|
|
14
|
+
photo: PhotoProps<GallerySetup>;
|
|
15
|
+
direction: "row" | "column";
|
|
16
|
+
isSelectedMode: boolean;
|
|
17
|
+
isFullScreenMode: boolean;
|
|
18
|
+
isSelected?: boolean;
|
|
19
|
+
isHiddenGallery: boolean;
|
|
20
|
+
onToggleSelect: () => void;
|
|
21
|
+
onPreview: () => void;
|
|
22
|
+
onSelectedMode: () => void;
|
|
23
|
+
enableEditor?: boolean;
|
|
24
|
+
adjustments?: Partial<AdjustmentValues>;
|
|
25
|
+
frame?: string | null;
|
|
26
|
+
}
|
|
27
|
+
declare const GalleryImageItem: (props: Props) => import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export default GalleryImageItem;
|
|
@@ -1,246 +1,165 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
// margin,
|
|
167
|
-
// width: "100%",
|
|
168
|
-
// ...commonStyle,
|
|
169
|
-
// };
|
|
170
|
-
// } else {
|
|
171
|
-
// if (props.isSelected) {
|
|
172
|
-
// return { ...boxSelected };
|
|
173
|
-
// } else {
|
|
174
|
-
// return { ...boxNotSelected };
|
|
175
|
-
// }
|
|
176
|
-
// }
|
|
177
|
-
// }, [
|
|
178
|
-
// props.isFullScreenMode,
|
|
179
|
-
// photo.height,
|
|
180
|
-
// photo.width,
|
|
181
|
-
// commonStyle,
|
|
182
|
-
// boxSelected,
|
|
183
|
-
// boxNotSelected,
|
|
184
|
-
// margin,
|
|
185
|
-
// props.isSelected,
|
|
186
|
-
// ]);
|
|
187
|
-
// return (
|
|
188
|
-
// <Box id={"Box_image"} key={photo.key} sx={boxOuterSx} className={"image"}>
|
|
189
|
-
// {!props.isHiddenGallery &&
|
|
190
|
-
// (props.isSelected ? (
|
|
191
|
-
// <Box
|
|
192
|
-
// color={"primary.dark1"}
|
|
193
|
-
// onClick={handleImageSelectedIconClick}
|
|
194
|
-
// sx={{
|
|
195
|
-
// position: "absolute",
|
|
196
|
-
// width: "19px",
|
|
197
|
-
// height: "19px",
|
|
198
|
-
// zIndex: "2",
|
|
199
|
-
// left: "5px",
|
|
200
|
-
// top: "5px",
|
|
201
|
-
// borderRadius: { xs: "50%", sm: 0 },
|
|
202
|
-
// }}
|
|
203
|
-
// className={"checkbox"}
|
|
204
|
-
// >
|
|
205
|
-
// <CustomTickIcon />
|
|
206
|
-
// </Box>
|
|
207
|
-
// ) : (
|
|
208
|
-
// <Box
|
|
209
|
-
// color={"neutral.light2"}
|
|
210
|
-
// onClick={handleImageSelectedIconClick}
|
|
211
|
-
// sx={{
|
|
212
|
-
// position: "absolute",
|
|
213
|
-
// width: "19px",
|
|
214
|
-
// height: "19px",
|
|
215
|
-
// zIndex: "1",
|
|
216
|
-
// left: "5px",
|
|
217
|
-
// top: "5px",
|
|
218
|
-
// display: "none",
|
|
219
|
-
// visibility: {
|
|
220
|
-
// xs: props.isSelectedMode ? "visible" : "hidden",
|
|
221
|
-
// sm: "visible",
|
|
222
|
-
// },
|
|
223
|
-
// }}
|
|
224
|
-
// className={"checkbox"}
|
|
225
|
-
// >
|
|
226
|
-
// <TickCircle
|
|
227
|
-
// style={{ width: "24px", height: "24px" }}
|
|
228
|
-
// color="white"
|
|
229
|
-
// />
|
|
230
|
-
// </Box>
|
|
231
|
-
// ))}
|
|
232
|
-
// <CardMedia
|
|
233
|
-
// id="card_media"
|
|
234
|
-
// component="img"
|
|
235
|
-
// className="image"
|
|
236
|
-
// loading="lazy"
|
|
237
|
-
// alt={photo.alt}
|
|
238
|
-
// sx={imageSx}
|
|
239
|
-
// src={processedImageSrc}
|
|
240
|
-
// width="100%"
|
|
241
|
-
// onClick={handleImageClick}
|
|
242
|
-
// />
|
|
243
|
-
// </Box>
|
|
244
|
-
// );
|
|
245
|
-
// };
|
|
246
|
-
// export default ImageItem;
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { Box, CardMedia, useTheme } from "@mui/material";
|
|
4
|
+
import { TickCircle } from "iconsax-react";
|
|
5
|
+
import CustomTickIcon from "../svg/Tick";
|
|
6
|
+
import { neutral } from "../../../color";
|
|
7
|
+
const initialAdjustments = {
|
|
8
|
+
temperature: 0, tint: 0, saturation: 0, vibrance: 0, exposure: 0, contrast: 0,
|
|
9
|
+
highlights: 0, shadows: 0, whites: 0, blacks: 0, clarity: 0, sharpness: 0,
|
|
10
|
+
};
|
|
11
|
+
const imgStyle = {
|
|
12
|
+
transition: "transform .135s cubic-bezier(0.0,0.0,0.2,1),opacity linear .15s",
|
|
13
|
+
width: "100%",
|
|
14
|
+
// objectFit: "contain",
|
|
15
|
+
//height: "100%",
|
|
16
|
+
};
|
|
17
|
+
const selectedImgStyle = {
|
|
18
|
+
borderRadius: "8px",
|
|
19
|
+
transform: "translateZ(0px) scale3d(1, 1, 1)",
|
|
20
|
+
// transition: "transform .135s cubic-bezier(0.0,0.0,0.2,1),opacity linear .15s"
|
|
21
|
+
};
|
|
22
|
+
const GalleryImageItem = (props) => {
|
|
23
|
+
const { photo, margin, adjustments, isSelected = false } = props;
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
const hasAdjustments = useMemo(() => {
|
|
26
|
+
if (!adjustments)
|
|
27
|
+
return false;
|
|
28
|
+
return Object.keys(initialAdjustments).some(key => adjustments[key] !== initialAdjustments[key]);
|
|
29
|
+
}, [adjustments]);
|
|
30
|
+
const styleHiddenGallery = useMemo(() => {
|
|
31
|
+
if (props.isHiddenGallery) {
|
|
32
|
+
return { filter: "blur(20px)", pointerEvents: "none" };
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}, [props.isHiddenGallery]);
|
|
38
|
+
const commonStyle = useMemo(() => {
|
|
39
|
+
return {
|
|
40
|
+
backgroundColor: neutral.white,
|
|
41
|
+
overflow: "hidden",
|
|
42
|
+
position: "relative",
|
|
43
|
+
width: "100%",
|
|
44
|
+
aspectRatio: `${photo.width}/${photo.height}`,
|
|
45
|
+
};
|
|
46
|
+
}, [props.direction, props.photo]);
|
|
47
|
+
const handleImageClick = () => {
|
|
48
|
+
console.debug({
|
|
49
|
+
isFullMode: props.isFullScreenMode,
|
|
50
|
+
isShowGallery: props.isHiddenGallery,
|
|
51
|
+
}, "handleImageClick");
|
|
52
|
+
if (!props.isFullScreenMode && !props.isHiddenGallery) {
|
|
53
|
+
if (props.isSelectedMode) {
|
|
54
|
+
console.debug("handleImageClick with toggle select");
|
|
55
|
+
props.onToggleSelect();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.debug("handleImageClick with preview");
|
|
59
|
+
props.onPreview();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const handleImageSelectedIconClick = () => {
|
|
64
|
+
console.debug("handleImageSelectedIconClick");
|
|
65
|
+
if (!props.isFullScreenMode) {
|
|
66
|
+
if (!props.isSelectedMode) {
|
|
67
|
+
props.onSelectedMode();
|
|
68
|
+
}
|
|
69
|
+
props.onToggleSelect();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const imageSx = useMemo(() => {
|
|
73
|
+
const baseStyles = isSelected ? {
|
|
74
|
+
...imgStyle,
|
|
75
|
+
...selectedImgStyle,
|
|
76
|
+
...styleHiddenGallery,
|
|
77
|
+
aspectRatio: `${photo.width}/${photo.height}`,
|
|
78
|
+
} : {
|
|
79
|
+
...imgStyle,
|
|
80
|
+
...styleHiddenGallery,
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
...baseStyles,
|
|
84
|
+
opacity: 1, // Previously depended on isProcessingComplete
|
|
85
|
+
transition: 'opacity 0.3s ease-in-out',
|
|
86
|
+
};
|
|
87
|
+
}, [isSelected, styleHiddenGallery, photo.width, photo.height]);
|
|
88
|
+
const boxNotSelected = useMemo(() => ({
|
|
89
|
+
margin,
|
|
90
|
+
// height: photo.height,
|
|
91
|
+
...commonStyle,
|
|
92
|
+
transition: ".3s",
|
|
93
|
+
// "&:hover": { padding: "12px", backgroundColor: "primary.light1" },
|
|
94
|
+
"&:-webkit-transition": { transition: ".3s" },
|
|
95
|
+
"&:hover > .checkbox": { display: props.isHiddenGallery ? "" : "block" },
|
|
96
|
+
cursor: props.isFullScreenMode || props.isHiddenGallery ? "inherit" : "pointer",
|
|
97
|
+
backgroundColor: props.isFullScreenMode
|
|
98
|
+
? "rgba(0,0,0,0.1)"
|
|
99
|
+
: "transparent",
|
|
100
|
+
}), [margin, commonStyle, props.isHiddenGallery, props.isFullScreenMode]);
|
|
101
|
+
const boxSelected = useMemo(() => ({
|
|
102
|
+
margin,
|
|
103
|
+
// height: photo.height,
|
|
104
|
+
...commonStyle,
|
|
105
|
+
cursor: props.isFullScreenMode || props.isHiddenGallery ? "inherit" : "pointer",
|
|
106
|
+
transition: ".3s",
|
|
107
|
+
"&:-webkit-transition": { transition: ".3s" },
|
|
108
|
+
padding: { xs: "13px 12px", sm: "21.31px 25.56px 21.32px 27.68px" },
|
|
109
|
+
backgroundColor: theme.palette.light["Surface-Variant-2"],
|
|
110
|
+
}), [
|
|
111
|
+
margin,
|
|
112
|
+
commonStyle,
|
|
113
|
+
theme.palette.light,
|
|
114
|
+
props.isFullScreenMode,
|
|
115
|
+
props.isHiddenGallery,
|
|
116
|
+
]);
|
|
117
|
+
const boxOuterSx = useMemo(() => {
|
|
118
|
+
if (props.isFullScreenMode) {
|
|
119
|
+
return {
|
|
120
|
+
margin,
|
|
121
|
+
...commonStyle,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
if (props.isSelected) {
|
|
126
|
+
return { ...boxSelected };
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
return { ...boxNotSelected };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}, [
|
|
133
|
+
props.isFullScreenMode,
|
|
134
|
+
photo.height,
|
|
135
|
+
photo.width,
|
|
136
|
+
commonStyle,
|
|
137
|
+
boxSelected,
|
|
138
|
+
boxNotSelected,
|
|
139
|
+
margin,
|
|
140
|
+
props.isSelected,
|
|
141
|
+
]);
|
|
142
|
+
return (_jsxs(Box, { id: "Box_image", sx: boxOuterSx, className: "image", children: [!props.isHiddenGallery &&
|
|
143
|
+
(hasAdjustments && isSelected ? (_jsx(Box, { color: "primary.dark1", onClick: handleImageSelectedIconClick, sx: {
|
|
144
|
+
position: "absolute",
|
|
145
|
+
width: "19px",
|
|
146
|
+
height: "19px",
|
|
147
|
+
zIndex: "2",
|
|
148
|
+
left: "5px",
|
|
149
|
+
top: "5px",
|
|
150
|
+
borderRadius: { xs: "50%", sm: 0 },
|
|
151
|
+
}, className: "checkbox", children: _jsx(CustomTickIcon, {}) })) : (_jsx(Box, { color: "neutral.light2", onClick: handleImageSelectedIconClick, sx: {
|
|
152
|
+
position: "absolute",
|
|
153
|
+
width: "19px",
|
|
154
|
+
height: "19px",
|
|
155
|
+
zIndex: "1",
|
|
156
|
+
left: "5px",
|
|
157
|
+
top: "5px",
|
|
158
|
+
display: "none",
|
|
159
|
+
visibility: {
|
|
160
|
+
xs: props.isSelectedMode ? "visible" : "hidden",
|
|
161
|
+
sm: "visible",
|
|
162
|
+
},
|
|
163
|
+
}, className: "checkbox", children: _jsx(TickCircle, { style: { width: "24px", height: "24px" }, color: "white" }) }))), _jsx(CardMedia, { id: "card_media", component: "img", className: "image", loading: "lazy", alt: photo.alt ?? "Image", sx: imageSx, src: photo.src, width: "100%", onClick: handleImageClick })] }, photo.key));
|
|
164
|
+
};
|
|
165
|
+
export default GalleryImageItem;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from "@mui/material";
|
|
3
|
+
const Tick = () => {
|
|
4
|
+
return (_jsx(SvgIcon, { style: { width: "29px", height: "29px" }, children: _jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("rect", { x: "5", y: "5", width: "22", height: "22", rx: "11", fill: "black" }), _jsx("path", { d: "M20 13L14.5 18.5L12 16", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }) }));
|
|
5
|
+
};
|
|
6
|
+
export default Tick;
|
|
@@ -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
|
-
|
|
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,
|
|
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
|
-
|
|
25
|
-
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
203
|
+
currentBatch,
|
|
204
|
+
selectedIds,
|
|
205
|
+
allImageIds,
|
|
188
206
|
adjustmentsMap,
|
|
189
207
|
selectedBulkPreset,
|
|
190
|
-
|
|
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/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 { default as AlbumImageGallery } from './components/editor/GalleryAlbum/AlbumImageGallery';
|
|
24
|
+
export { default as GalleryImageItem } from './components/editor/GalleryAlbum/ImageItem';
|
|
23
25
|
export { useAdjustmentHistory, type UseAdjustmentHistoryReturn, type HistoryInfo, type HistoryActions, type HistoryConfig } from './hooks/useAdjustmentHistory';
|
|
24
26
|
export { useAdjustmentHistoryBatch, type UseAdjustmentHistoryBatchReturn, type BatchAdjustmentState, type ImageAdjustmentConfig, type BatchHistoryInfo, type BatchHistoryActions, type BatchHistoryConfig } from './hooks/useAdjustmentHistoryBatch';
|
|
25
27
|
export { default as useColors } from './themes/colors';
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,8 @@ 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
|
+
export { default as AlbumImageGallery } from './components/editor/GalleryAlbum/AlbumImageGallery';
|
|
22
|
+
export { default as GalleryImageItem } from './components/editor/GalleryAlbum/ImageItem';
|
|
21
23
|
// --- History Hooks ---
|
|
22
24
|
export { useAdjustmentHistory } from './hooks/useAdjustmentHistory';
|
|
23
25
|
export { useAdjustmentHistoryBatch } from './hooks/useAdjustmentHistoryBatch';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yogiswara/honcho-editor-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
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",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"keywords": [],
|
|
50
50
|
"author": "",
|
|
51
51
|
"dependencies": {
|
|
52
|
+
"iconsax-react": "^0.0.8",
|
|
52
53
|
"react-responsive-masonry": "^2.7.1"
|
|
53
54
|
}
|
|
54
55
|
}
|