@yogiswara/honcho-editor-ui 3.3.4 → 3.4.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.
Files changed (36) hide show
  1. package/dist/components/editor/GalleryAlbum/AlbumImageGallery.d.ts +14 -7
  2. package/dist/components/editor/GalleryAlbum/AlbumImageGallery.js +207 -5
  3. package/dist/components/editor/GalleryAlbum/ImageItemComponents.d.ts +25 -0
  4. package/dist/components/editor/GalleryAlbum/ImageItemComponents.js +179 -0
  5. package/dist/components/editor/GalleryAlbum/colorsGallery.d.ts +9 -0
  6. package/dist/components/editor/GalleryAlbum/colorsGallery.js +9 -0
  7. package/dist/components/editor/GalleryAlbum/svg/Tick.d.ts +2 -0
  8. package/dist/components/editor/GalleryAlbum/svg/Tick.js +6 -0
  9. package/dist/components/editor/HBulkAccordionColorAdjustment.js +1 -2
  10. package/dist/components/editor/HBulkAccordionColorAdjustmentColors.js +1 -1
  11. package/dist/components/editor/HBulkPreset.d.ts +3 -7
  12. package/dist/components/editor/HBulkPreset.js +21 -22
  13. package/dist/components/editor/HBulkPresetMobile.d.ts +2 -2
  14. package/dist/components/editor/HBulkPresetMobile.js +2 -2
  15. package/dist/components/editor/HImageEditorBulkMobile.d.ts +2 -2
  16. package/dist/hooks/demo/HonchoEditorBulkDemo.d.ts +0 -3
  17. package/dist/hooks/demo/HonchoEditorBulkDemo.js +770 -411
  18. package/dist/hooks/demo/HonchoEditorSingleCleanDemo.d.ts +0 -3
  19. package/dist/hooks/demo/HonchoEditorSingleCleanDemo.js +882 -354
  20. package/dist/hooks/demo/index.d.ts +0 -2
  21. package/dist/hooks/demo/index.js +3 -2
  22. package/dist/hooks/editor/type.d.ts +15 -13
  23. package/dist/hooks/editor/useHonchoEditorBulk.d.ts +47 -5
  24. package/dist/hooks/editor/useHonchoEditorBulk.js +252 -133
  25. package/dist/hooks/useAdjustmentHistory.js +12 -12
  26. package/dist/hooks/useAdjustmentHistoryBatch.d.ts +33 -31
  27. package/dist/hooks/useAdjustmentHistoryBatch.js +703 -170
  28. package/dist/hooks/usePreset.js +12 -12
  29. package/dist/index.d.ts +5 -7
  30. package/dist/index.js +5 -4
  31. package/dist/services/type.d.ts +14 -0
  32. package/dist/utils/adjustment.d.ts +1 -1
  33. package/dist/utils/adjustment.js +15 -14
  34. package/dist/utils/logger.d.ts +3 -0
  35. package/dist/utils/logger.js +11 -0
  36. package/package.json +4 -2
@@ -1,8 +1,15 @@
1
- import React from "react";
2
- import type { PhotoData } from "../../../hooks/editor/useHonchoEditorBulk";
3
- interface ImageGalleryProps {
4
- imageCollection: PhotoData[];
5
- onToggleSelect: (photo: PhotoData) => void;
1
+ import { GallerySetup } from "../../../services/type";
2
+ interface ImageGalleryInfiniteProps {
3
+ imageCollection: GallerySetup[];
4
+ isSelectedMode?: boolean;
5
+ isHiddenGallery?: boolean;
6
+ isLoading?: boolean;
7
+ isLoadingMore?: boolean;
8
+ hasMore?: boolean;
9
+ onPreview?: (photo: GallerySetup) => () => void;
10
+ onSelectedMode?: () => void;
11
+ onToggleSelect?: (photo: GallerySetup) => () => void;
12
+ onLoadMore?: () => Promise<void>;
6
13
  }
7
- export declare const AlbumImageGallery: React.FC<ImageGalleryProps>;
8
- export {};
14
+ declare const AlbumImageGalleryInfinite: React.FC<ImageGalleryInfiniteProps>;
15
+ export default AlbumImageGalleryInfinite;
@@ -1,7 +1,209 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { Stack } from "@mui/material";
4
- export const AlbumImageGallery = (props) => {
5
- const { imageCollection, onToggleSelect } = props;
6
- return (_jsx(Stack, { sx: { width: '100%', maxHeight: '100%', overflowY: 'auto' } }));
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Box, useMediaQuery, CircularProgress } from "@mui/material";
4
+ import { memo, useCallback, useMemo, useRef, useEffect } from "react";
5
+ import { MasonryInfiniteGrid } from "@egjs/react-infinitegrid";
6
+ import ImageItemComponents from "./ImageItemComponents";
7
+ import useColors from '../../../themes/colors';
8
+ // Custom comparison function for ImageItem (reusing existing logic)
9
+ const imageItemPropsAreEqual = (prevProps, nextProps) => {
10
+ // Compare photo data deeply
11
+ const prevPhoto = prevProps.photo;
12
+ const nextPhoto = nextProps.photo;
13
+ const prevData = prevProps.data;
14
+ const nextData = nextProps.data;
15
+ // Check if photo key/ID is the same
16
+ if (prevPhoto.key !== nextPhoto.key)
17
+ return false;
18
+ // Check critical photo properties that affect rendering
19
+ if (prevData.isSelected !== nextData.isSelected)
20
+ return false;
21
+ if (JSON.stringify(prevData.adjustments) !== JSON.stringify(nextData.adjustments))
22
+ return false;
23
+ if (prevData.frame !== nextData.frame)
24
+ return false;
25
+ if (prevPhoto.src !== nextPhoto.src)
26
+ return false;
27
+ // Compare other relevant props
28
+ if (prevProps.isSelectedMode !== nextProps.isSelectedMode)
29
+ return false;
30
+ if (prevProps.isHiddenGallery !== nextProps.isHiddenGallery)
31
+ return false;
32
+ if (prevProps.index !== nextProps.index)
33
+ return false;
34
+ if (prevProps.isSelected !== nextProps.isSelected)
35
+ return false;
36
+ // If all critical properties are the same, don't re-render
37
+ return true;
7
38
  };
39
+ // Memoized component with custom comparison
40
+ const MemoizedImageItem = memo(ImageItemComponents, imageItemPropsAreEqual);
41
+ // Custom comparison function for AlbumImageGalleryInfinite
42
+ const albumGalleryInfinitePropsAreEqual = (prevProps, nextProps) => {
43
+ // Compare simple props first
44
+ if (prevProps.isSelectedMode !== nextProps.isSelectedMode)
45
+ return false;
46
+ if (prevProps.isHiddenGallery !== nextProps.isHiddenGallery)
47
+ return false;
48
+ if (prevProps.isLoading !== nextProps.isLoading)
49
+ return false;
50
+ if (prevProps.isLoadingMore !== nextProps.isLoadingMore)
51
+ return false;
52
+ if (prevProps.hasMore !== nextProps.hasMore)
53
+ return false;
54
+ // Compare imageCollection array deeply
55
+ const prevCollection = prevProps.imageCollection;
56
+ const nextCollection = nextProps.imageCollection;
57
+ // Allow incremental updates - if next has more items, only check if existing items changed
58
+ const minLength = Math.min(prevCollection.length, nextCollection.length);
59
+ // If next collection is smaller, something was removed - need re-render
60
+ if (nextCollection.length < prevCollection.length)
61
+ return false;
62
+ // Check if existing items (at same positions) have changed
63
+ for (let i = 0; i < minLength; i++) {
64
+ const prev = prevCollection[i];
65
+ const next = nextCollection[i];
66
+ if (prev.key !== next.key)
67
+ return false;
68
+ if (prev.src !== next.src)
69
+ return false;
70
+ if (prev.isSelected !== next.isSelected)
71
+ return false;
72
+ if (prev.original !== next.original)
73
+ return false;
74
+ if (JSON.stringify(prev.adjustments) !== JSON.stringify(next.adjustments))
75
+ return false;
76
+ if (prev.frame !== next.frame)
77
+ return false;
78
+ }
79
+ // If we reach here, existing items are the same
80
+ // If lengths are equal, no changes - return true
81
+ // If next is longer, new items added - return true (let InfiniteGrid handle new items)
82
+ return true;
83
+ };
84
+ const AlbumImageGalleryInfinite = (props) => {
85
+ const { imageCollection, isSelectedMode, isHiddenGallery, onPreview,
86
+ // isLoading = false,
87
+ isLoadingMore = false, hasMore = false, onSelectedMode = () => { }, onToggleSelect, onLoadMore, } = props;
88
+ // const theme = useTheme();
89
+ const colors = useColors();
90
+ const scrollContainerRef = useRef(null);
91
+ const loadingTriggerRef = useRef(false);
92
+ // Responsive column calculation based on breakpoints (matching original)
93
+ const isMobile = useMediaQuery("(max-width: 750px)");
94
+ // const isTablet = useMediaQuery("(max-width: 900px)");
95
+ const columnWidth = useMemo(() => {
96
+ // if (isMobile) return "100%"; // 1 column on mobile
97
+ if (isMobile)
98
+ return "calc(50% - 0px)"; // 2 columns on tablet
99
+ return "calc(25% - 0px)"; // 4 columns on desktop
100
+ }, [isMobile, isMobile]);
101
+ // Memoize callback functions to prevent unnecessary re-renders
102
+ const handlePreview = useCallback((photo) => () => {
103
+ if (onPreview) {
104
+ onPreview(photo)();
105
+ }
106
+ }, [onPreview]);
107
+ const handleToggleSelect = useCallback((photo) => () => {
108
+ if (onToggleSelect) {
109
+ onToggleSelect(photo)();
110
+ }
111
+ }, [onToggleSelect]);
112
+ const handleScroll = useCallback(async (event) => {
113
+ if (!onLoadMore || !hasMore || isLoadingMore || loadingTriggerRef.current) {
114
+ return;
115
+ }
116
+ const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
117
+ const scrollPercent = (scrollTop + clientHeight) / scrollHeight;
118
+ // Trigger load more when user scrolls to 80% of the content
119
+ if (scrollPercent > 0.8) {
120
+ loadingTriggerRef.current = true;
121
+ try {
122
+ console.log('[AlbumImageGalleryInfinite] Loading more images...');
123
+ await onLoadMore();
124
+ }
125
+ catch (error) {
126
+ console.error('[AlbumImageGalleryInfinite] Error loading more images:', error);
127
+ }
128
+ finally {
129
+ // Reset the trigger after a short delay to prevent rapid firing
130
+ setTimeout(() => {
131
+ loadingTriggerRef.current = false;
132
+ }, 1000);
133
+ }
134
+ }
135
+ }, [onLoadMore, hasMore, isLoadingMore]);
136
+ // Reset loading trigger when loading state changes
137
+ useEffect(() => {
138
+ if (!isLoadingMore) {
139
+ loadingTriggerRef.current = false;
140
+ }
141
+ }, [isLoadingMore]);
142
+ return (_jsxs(Box, { ref: scrollContainerRef, onScroll: handleScroll, sx: {
143
+ width: '100%',
144
+ height: '100%',
145
+ overflowY: 'auto',
146
+ overflowX: 'hidden',
147
+ // Hide scrollbar
148
+ scrollbarWidth: 'none', // Firefox
149
+ msOverflowStyle: 'none', // IE/Edge
150
+ '&::-webkit-scrollbar': {
151
+ display: 'none'
152
+ }
153
+ }, children: [_jsx(MasonryInfiniteGrid, { className: "album-masonry-grid", gap: 0, useRecycle: false, threshold: 200, defaultDirection: "end", useFirstRender: true, container: true, containerTag: "div", column: isMobile ? 2 : 4, columnSize: 0, columnSizeRatio: 0,
154
+ // Animation and transition settings to reduce blinking
155
+ transitionDuration: 0, easing: "linear", isEqualSize: false, isConstantSize: false,
156
+ // Prevent layout shifts during updates
157
+ observeChildren: false, renderOnPropertyChange: false, style: {
158
+ // Disable CSS transitions that might cause blinking
159
+ transition: 'none',
160
+ // Improve rendering performance
161
+ willChange: 'auto',
162
+ // Prevent layout shifts
163
+ minHeight: 'auto',
164
+ // width: '100%',
165
+ minWidth: '100%',
166
+ overflow: 'hidden',
167
+ // overflowY: 'scroll', // Enable scrolling
168
+ scrollbarWidth: 'none', // Firefox
169
+ msOverflowStyle: 'none', // IE/Edge
170
+ '&::-webkit-scrollbar': {
171
+ display: 'none'
172
+ }
173
+ }, children: imageCollection.map((photo, index) => (_jsx(Box, { sx: {
174
+ width: columnWidth,
175
+ padding: "4px",
176
+ // Disable transitions to prevent blinking
177
+ transition: 'none !important',
178
+ // Ensure stable layout
179
+ // minHeight: 'auto',
180
+ // Improve rendering performance
181
+ willChange: 'auto',
182
+ // Ensure images maintain aspect ratio
183
+ "& img": {
184
+ width: "100%",
185
+ // height: "auto",
186
+ // objectFit: "cover",
187
+ // borderRadius: "8px",
188
+ // Disable image transitions
189
+ transition: 'none !important',
190
+ // Prevent layout shifts during loading
191
+ display: 'block'
192
+ }
193
+ }, children: _jsx(MemoizedImageItem, { margin: "0px", index: index, photo: photo, data: photo, direction: "column", isFullScreenMode: false, isSelected: photo.isSelected ?? false, isSelectedMode: isSelectedMode, isHiddenGallery: isHiddenGallery, onPreview: handlePreview(photo), onSelectedMode: onSelectedMode, onToggleSelect: handleToggleSelect(photo) }) }, photo.key + photo.adjustments?.toString()))) }), isLoadingMore && (_jsx(Box, { sx: {
194
+ display: 'flex',
195
+ justifyContent: 'center',
196
+ alignItems: 'center',
197
+ padding: 2,
198
+ width: '100%'
199
+ }, children: _jsx(CircularProgress, { size: 24, sx: { color: colors.onSurfaceVariant } }) })), !hasMore && imageCollection.length > 0 && (_jsx(Box, { sx: {
200
+ display: 'flex',
201
+ justifyContent: 'center',
202
+ alignItems: 'center',
203
+ padding: 2,
204
+ width: '100%',
205
+ color: colors.onSurfaceVariant,
206
+ fontSize: '0.875rem'
207
+ }, children: "No more images to load" }))] }));
208
+ };
209
+ export default AlbumImageGalleryInfinite;
@@ -0,0 +1,25 @@
1
+ import { GallerySetup } from "../../../services/type";
2
+ interface PhotoProps<T> {
3
+ src: string;
4
+ alt: string;
5
+ width: number;
6
+ height: number;
7
+ key: string;
8
+ }
9
+ interface Props {
10
+ margin?: any;
11
+ index: number;
12
+ photo: PhotoProps<GallerySetup>;
13
+ data: GallerySetup;
14
+ direction: "row" | "column";
15
+ isSelectedMode: boolean | undefined;
16
+ isFullScreenMode: boolean;
17
+ isSelected: boolean;
18
+ isHiddenGallery: boolean | undefined;
19
+ onToggleSelect: () => void;
20
+ onPreview: () => void;
21
+ onSelectedMode: () => void | undefined;
22
+ enableEditor?: boolean;
23
+ }
24
+ declare const ImageItemComponents: (props: Props) => import("react/jsx-runtime").JSX.Element;
25
+ export default ImageItemComponents;
@@ -0,0 +1,179 @@
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 useColors from '../../../themes/colors';
6
+ import CustomTickIcon from "./svg/Tick";
7
+ import { useImageProcessor } from "../../../lib/hooks/useImageProcessor";
8
+ import { neutral } from "./colorsGallery";
9
+ import { log } from "../../../utils/logger";
10
+ const imgStyle = {
11
+ transition: "transform .135s cubic-bezier(0.0,0.0,0.2,1),opacity linear .15s",
12
+ width: "100%",
13
+ // objectFit: "contain",
14
+ //height: "100%",
15
+ };
16
+ const selectedImgStyle = {
17
+ borderRadius: "8px",
18
+ transform: "translateZ(0px) scale3d(1, 1, 1)",
19
+ // transition: "transform .135s cubic-bezier(0.0,0.0,0.2,1),opacity linear .15s"
20
+ };
21
+ const ImageItemComponents = (props) => {
22
+ const { photo, margin, enableEditor = true, data } = props;
23
+ const theme = useTheme();
24
+ const imageData = data;
25
+ const colors = useColors();
26
+ // Memoize adjustments to prevent infinite re-renders
27
+ // Use the image processor hook
28
+ const { processedImageSrc, isProcessingComplete } = useImageProcessor({
29
+ photoId: photo.key,
30
+ photoSrc: photo.src,
31
+ enableEditor,
32
+ adjustments: imageData?.adjustments,
33
+ frame: imageData?.frame || null,
34
+ });
35
+ const styleHiddenGallery = useMemo(() => {
36
+ if (props.isHiddenGallery) {
37
+ return { filter: "blur(20px)", pointerEvents: "none" };
38
+ }
39
+ else {
40
+ return {};
41
+ }
42
+ }, [props.isHiddenGallery]);
43
+ const commonStyle = useMemo(() => {
44
+ return {
45
+ backgroundColor: neutral.white,
46
+ overflow: "hidden",
47
+ position: "relative",
48
+ width: "100%",
49
+ aspectRatio: `${photo.width}/${photo.height}`,
50
+ };
51
+ }, [props.direction, props.photo]);
52
+ const handleImageClick = () => {
53
+ log.debug({
54
+ isFullMode: props.isFullScreenMode,
55
+ isShowGallery: props.isHiddenGallery,
56
+ isSelectedMode: props.isSelectedMode,
57
+ isSelected: props.isSelected,
58
+ }, "handleImageClick");
59
+ if (!props.isSelectedMode && !props.isSelected) {
60
+ props.onSelectedMode();
61
+ }
62
+ if (!props.isFullScreenMode && !props.isHiddenGallery) {
63
+ if (props.isSelectedMode || props.isSelected) {
64
+ // If we're in selection mode OR this image is already selected,
65
+ // clicking toggles the selection
66
+ log.debug("handleImageClick with toggle select");
67
+ props.onToggleSelect();
68
+ }
69
+ else {
70
+ // Not in selection mode and image not selected
71
+ // Enter selection mode and select this image in one action
72
+ log.debug("handleImageClick entering selection mode and selecting image");
73
+ if (props.onSelectedMode) {
74
+ props.onSelectedMode(); // This should trigger selection mode globally
75
+ }
76
+ props.onToggleSelect(); // Select this specific image
77
+ }
78
+ }
79
+ };
80
+ const handleImageSelectedIconClick = () => {
81
+ log.debug("handleImageSelectedIconClick");
82
+ if (!props.isFullScreenMode) {
83
+ if (!props.isSelectedMode) {
84
+ props.onSelectedMode();
85
+ }
86
+ props.onToggleSelect();
87
+ }
88
+ };
89
+ const imageSx = useMemo(() => {
90
+ const baseStyles = props.isSelected ? {
91
+ ...imgStyle,
92
+ ...selectedImgStyle,
93
+ ...styleHiddenGallery,
94
+ aspectRatio: `${photo.width}/${photo.height}`,
95
+ } : {
96
+ ...imgStyle,
97
+ ...styleHiddenGallery,
98
+ };
99
+ return {
100
+ ...baseStyles,
101
+ // Show loading state only on first load, then keep images visible during transitions
102
+ opacity: (!processedImageSrc || !isProcessingComplete) && processedImageSrc === '' ? 0 : 1,
103
+ transition: 'opacity 0.15s ease-in-out',
104
+ };
105
+ }, [props.isSelected, styleHiddenGallery, photo.width, photo.height, processedImageSrc, isProcessingComplete]);
106
+ const boxNotSelected = useMemo(() => ({
107
+ margin,
108
+ // height: photo.height,
109
+ ...commonStyle,
110
+ transition: ".3s",
111
+ // "&:hover": { padding: "12px", backgroundColor: "primary.light1" },
112
+ "&:-webkit-transition": { transition: ".3s" },
113
+ "&:hover > .checkbox": { display: props.isHiddenGallery ? "" : "block" },
114
+ cursor: props.isFullScreenMode || props.isHiddenGallery ? "inherit" : "pointer",
115
+ backgroundColor: props.isFullScreenMode
116
+ ? "rgba(0,0,0,0.1)"
117
+ : "transparent",
118
+ }), [margin, commonStyle, props.isHiddenGallery, props.isFullScreenMode]);
119
+ const boxSelected = useMemo(() => ({
120
+ margin,
121
+ // height: photo.height,
122
+ ...commonStyle,
123
+ cursor: props.isFullScreenMode || props.isHiddenGallery ? "inherit" : "pointer",
124
+ transition: ".3s",
125
+ "&:-webkit-transition": { transition: ".3s" },
126
+ padding: { xs: "13px 12px", sm: "21.31px 25.56px 21.32px 27.68px" },
127
+ backgroundColor: colors.onSurface,
128
+ }), [margin, commonStyle, theme.palette.light, props.isFullScreenMode, props.isHiddenGallery,]);
129
+ const boxOuterSx = useMemo(() => {
130
+ if (props.isFullScreenMode) {
131
+ return {
132
+ margin,
133
+ ...commonStyle,
134
+ //width: props.data.width,
135
+ //height: props.data.height,
136
+ };
137
+ }
138
+ else {
139
+ if (props.isSelected) {
140
+ return { ...boxSelected };
141
+ }
142
+ else {
143
+ return { ...boxNotSelected };
144
+ }
145
+ }
146
+ }, [
147
+ props.isFullScreenMode,
148
+ photo.height,
149
+ photo.width,
150
+ commonStyle,
151
+ boxSelected,
152
+ boxNotSelected,
153
+ margin,
154
+ props.isSelected,
155
+ ]);
156
+ return (_jsxs(Box, { id: "Box_image", sx: boxOuterSx, className: "image", children: [!props.isHiddenGallery &&
157
+ (props.isSelected ? (_jsx(Box, { color: colors.onSurface, onClick: handleImageSelectedIconClick, sx: {
158
+ position: "absolute",
159
+ width: "19px",
160
+ height: "19px",
161
+ zIndex: "2",
162
+ left: "5px",
163
+ top: "5px",
164
+ borderRadius: { xs: "50%", sm: 0 },
165
+ }, className: "checkbox", children: _jsx(CustomTickIcon, {}) })) : (_jsx(Box, { color: "neutral.light2", onClick: handleImageSelectedIconClick, sx: {
166
+ position: "absolute",
167
+ width: "19px",
168
+ height: "19px",
169
+ zIndex: "1",
170
+ left: "5px",
171
+ top: "5px",
172
+ display: props.isSelectedMode ? "block" : "none",
173
+ visibility: {
174
+ xs: props.isSelectedMode ? "visible" : "hidden",
175
+ sm: "visible",
176
+ },
177
+ }, className: "checkbox", children: _jsx(TickCircle, { style: { width: "24px", height: "24px", fill: "black" }, color: "white" }) }))), _jsx(CardMedia, { id: "card_media", component: "img", className: "image", loading: "lazy", alt: photo.alt, sx: imageSx, src: processedImageSrc, width: "100%", onClick: handleImageClick })] }, photo.key));
178
+ };
179
+ export default ImageItemComponents;
@@ -0,0 +1,9 @@
1
+ export declare const neutral: {
2
+ white: string;
3
+ 10: string;
4
+ 25: string;
5
+ 50: string;
6
+ 75: string;
7
+ 100: string;
8
+ 200: string;
9
+ };
@@ -0,0 +1,9 @@
1
+ export const neutral = {
2
+ white: "#FFFFFF",
3
+ 10: "#F9F9F9",
4
+ 25: "#DBDBDB",
5
+ 50: "#8D8D8D",
6
+ 75: "#575757",
7
+ 100: "#0A0A1C",
8
+ 200: "#000000",
9
+ };
@@ -0,0 +1,2 @@
1
+ declare const Tick: () => import("react/jsx-runtime").JSX.Element;
2
+ export default Tick;
@@ -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: "white" }), _jsx("path", { d: "M20 13L14.5 18.5L12 16", stroke: "black", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }) }));
5
+ };
6
+ export default Tick;
@@ -4,7 +4,6 @@ import useHonchoTypography from "../../themes/honchoTheme";
4
4
  import useColors from "../../themes/colors";
5
5
  import HBulkAccordionColorAdjustmentColors from "./HBulkAccordionColorAdjustmentColors";
6
6
  import HBulkAccordionColorAdjustmentLight from "./HBulkAccordionColorAdjustmentLight";
7
- import HBulkAccordionColorAdjustmentDetails from "./HBulkAccordionColorAdjustmentDetails";
8
7
  export default function HBulkAccordionColorAdjustment(props) {
9
8
  const typography = useHonchoTypography();
10
9
  const colors = useColors();
@@ -27,5 +26,5 @@ export default function HBulkAccordionColorAdjustment(props) {
27
26
  }
28
27
  };
29
28
  const isPanelExpanded = (panelName) => props.expandedPanels.includes(panelName);
30
- return (_jsx(_Fragment, { children: _jsxs(Stack, { direction: "column", sx: { accordionStyle }, children: [_jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('whiteBalance'), onChange: props.onPanelChange('whiteBalance'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%' }, children: [_jsx(Typography, { sx: { ...typography.titleMedium }, children: "Color" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('whiteBalance') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pr: "4px" }, children: _jsx(HBulkAccordionColorAdjustmentColors, { onTempDecreaseMax: props.onTempDecreaseMax, onTempDecrease: props.onTempDecrease, onTempIncrease: props.onTempIncrease, onTempIncreaseMax: props.onTempIncreaseMax, onTintDecreaseMax: props.onTintDecreaseMax, onTintDecrease: props.onTintDecrease, onTintIncrease: props.onTintIncrease, onTintIncreaseMax: props.onTintIncreaseMax, onVibranceDecreaseMax: props.onVibranceDecreaseMax, onVibranceDecrease: props.onVibranceDecrease, onVibranceIncrease: props.onVibranceIncrease, onVibranceIncreaseMax: props.onVibranceIncreaseMax, onSaturationDecreaseMax: props.onSaturationDecreaseMax, onSaturationDecrease: props.onSaturationDecrease, onSaturationIncrease: props.onSaturationIncrease, onSaturationIncreaseMax: props.onSaturationIncreaseMax }) })] }), _jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('light'), onChange: props.onPanelChange('light'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%' }, children: [_jsx(Typography, { sx: { ...typography.titleMedium }, children: "Light" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('light') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pr: "4px" }, children: _jsx(HBulkAccordionColorAdjustmentLight, { onExposureDecreaseMax: props.onExposureDecreaseMax, onExposureDecrease: props.onExposureDecrease, onExposureIncrease: props.onExposureIncrease, onExposureIncreaseMax: props.onExposureIncreaseMax, onContrastDecreaseMax: props.onContrastDecreaseMax, onContrastDecrease: props.onContrastDecrease, onContrastIncrease: props.onContrastIncrease, onContrastIncreaseMax: props.onContrastIncreaseMax, onHighlightsDecreaseMax: props.onHighlightsDecreaseMax, onHighlightsDecrease: props.onHighlightsDecrease, onHighlightsIncrease: props.onHighlightsIncrease, onHighlightsIncreaseMax: props.onHighlightsIncreaseMax, onShadowsDecreaseMax: props.onShadowsDecreaseMax, onShadowsDecrease: props.onShadowsDecrease, onShadowsIncrease: props.onShadowsIncrease, onShadowsIncreaseMax: props.onShadowsIncreaseMax, onWhitesDecreaseMax: props.onWhitesDecreaseMax, onWhitesDecrease: props.onWhitesDecrease, onWhitesIncrease: props.onWhitesIncrease, onWhitesIncreaseMax: props.onWhitesIncreaseMax, onBlacksDecreaseMax: props.onBlacksDecreaseMax, onBlacksDecrease: props.onBlacksDecrease, onBlacksIncrease: props.onBlacksIncrease, onBlacksIncreaseMax: props.onBlacksIncreaseMax }) })] }), _jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('details'), onChange: props.onPanelChange('details'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%' }, children: [_jsx(Typography, { sx: { ...typography.titleMedium }, children: "Details" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('details') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pr: "4px" }, children: _jsx(HBulkAccordionColorAdjustmentDetails, { onClarityDecreaseMax: props.onClarityDecreaseMax, onClarityDecrease: props.onClarityDecrease, onClarityIncrease: props.onClarityIncrease, onClarityIncreaseMax: props.onClarityIncreaseMax, onSharpnessDecreaseMax: props.onSharpnessDecreaseMax, onSharpnessDecrease: props.onSharpnessDecrease, onSharpnessIncrease: props.onSharpnessIncrease, onSharpnessIncreaseMax: props.onSharpnessIncreaseMax }) })] })] }) }));
29
+ return (_jsx(_Fragment, { children: _jsxs(Stack, { direction: "column", sx: { accordionStyle }, children: [_jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('whiteBalance'), onChange: props.onPanelChange('whiteBalance'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%', pr: "16px" }, children: [_jsx(Typography, { sx: { ...typography.titleMedium }, children: "Color" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('whiteBalance') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pr: "2px" }, children: _jsx(HBulkAccordionColorAdjustmentColors, { onTempDecreaseMax: props.onTempDecreaseMax, onTempDecrease: props.onTempDecrease, onTempIncrease: props.onTempIncrease, onTempIncreaseMax: props.onTempIncreaseMax, onTintDecreaseMax: props.onTintDecreaseMax, onTintDecrease: props.onTintDecrease, onTintIncrease: props.onTintIncrease, onTintIncreaseMax: props.onTintIncreaseMax, onVibranceDecreaseMax: props.onVibranceDecreaseMax, onVibranceDecrease: props.onVibranceDecrease, onVibranceIncrease: props.onVibranceIncrease, onVibranceIncreaseMax: props.onVibranceIncreaseMax, onSaturationDecreaseMax: props.onSaturationDecreaseMax, onSaturationDecrease: props.onSaturationDecrease, onSaturationIncrease: props.onSaturationIncrease, onSaturationIncreaseMax: props.onSaturationIncreaseMax }) })] }), _jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('light'), onChange: props.onPanelChange('light'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%', pr: "16px" }, children: [_jsx(Typography, { sx: { ...typography.titleMedium }, children: "Light" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('light') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pr: "2px" }, children: _jsx(HBulkAccordionColorAdjustmentLight, { onExposureDecreaseMax: props.onExposureDecreaseMax, onExposureDecrease: props.onExposureDecrease, onExposureIncrease: props.onExposureIncrease, onExposureIncreaseMax: props.onExposureIncreaseMax, onContrastDecreaseMax: props.onContrastDecreaseMax, onContrastDecrease: props.onContrastDecrease, onContrastIncrease: props.onContrastIncrease, onContrastIncreaseMax: props.onContrastIncreaseMax, onHighlightsDecreaseMax: props.onHighlightsDecreaseMax, onHighlightsDecrease: props.onHighlightsDecrease, onHighlightsIncrease: props.onHighlightsIncrease, onHighlightsIncreaseMax: props.onHighlightsIncreaseMax, onShadowsDecreaseMax: props.onShadowsDecreaseMax, onShadowsDecrease: props.onShadowsDecrease, onShadowsIncrease: props.onShadowsIncrease, onShadowsIncreaseMax: props.onShadowsIncreaseMax, onWhitesDecreaseMax: props.onWhitesDecreaseMax, onWhitesDecrease: props.onWhitesDecrease, onWhitesIncrease: props.onWhitesIncrease, onWhitesIncreaseMax: props.onWhitesIncreaseMax, onBlacksDecreaseMax: props.onBlacksDecreaseMax, onBlacksDecrease: props.onBlacksDecrease, onBlacksIncrease: props.onBlacksIncrease, onBlacksIncreaseMax: props.onBlacksIncreaseMax }) })] })] }) }));
31
30
  }
@@ -89,7 +89,7 @@ export default function HBulkAccordionColorAdjustmentColors(props) {
89
89
  mr: "12px",
90
90
  border: "1px solid white",
91
91
  borderRadius: "100px",
92
- }, children: _jsx(CardMedia, { component: "img", image: "/v1/svg/bulk-editor-max-button-right.svg", sx: { ml: "2px" } }) })] }), _jsx(Stack, { direction: "row", justifyContent: "space-between", sx: { pb: "8px", pt: "16px" }, children: _jsx(Typography, { sx: { ...typography.bodyMedium }, children: "Saturation" }) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", sx: { p: "0px", m: "0px", pt: "2px", pb: "2px" }, children: [_jsx(IconButton, { onClick: props.onSaturationDecreaseMax, sx: {
92
+ }, children: _jsx(CardMedia, { component: "img", image: "/v1/svg/bulk-editor-max-button-right.svg", sx: { ml: "2px" } }) })] }), _jsx(Stack, { direction: "row", justifyContent: "space-between", sx: { pb: "8px", pt: "16px" }, children: _jsx(Typography, { sx: { ...typography.bodyMedium }, children: "Saturation" }) }), _jsxs(Stack, { direction: "row", justifyContent: "space-between", sx: { p: "0px", m: "0px", pt: "2px", pb: "16px" }, children: [_jsx(IconButton, { onClick: props.onSaturationDecreaseMax, sx: {
93
93
  width: "38.5px",
94
94
  height: "26px",
95
95
  py: "2px",
@@ -1,5 +1,4 @@
1
1
  import React from "react";
2
- import { SelectChangeEvent } from "@mui/material";
3
2
  type Preset = {
4
3
  id: string;
5
4
  name: string;
@@ -10,14 +9,11 @@ interface Props {
10
9
  expandedPanels: string[];
11
10
  presetMenuAnchorEl: null | HTMLElement;
12
11
  activePresetMenuId: string | null;
13
- isMenuOpen: boolean;
14
- onPanelChange: (panel: string) => (event: React.SyntheticEvent, isExpanded: boolean) => void;
15
- onSelectPreset: (event: SelectChangeEvent<string>) => void;
12
+ isPresetCreatedSet?: boolean;
13
+ onChange: (panel: string) => (event: React.SyntheticEvent, isExpanded: boolean) => void;
14
+ onSelectPreset: (id: string) => void;
16
15
  onPresetMenuClick: (event: React.MouseEvent<HTMLElement>, presetId: string) => void;
17
16
  onPresetMenuClose: () => void;
18
- onRemovePreset: () => void;
19
- onRenamePreset: () => void;
20
- onDeletePreset: () => void;
21
17
  onOpenPresetModal: () => void;
22
18
  }
23
19
  export default function HBulkPreset(props: Props): import("react/jsx-runtime").JSX.Element;
@@ -1,12 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback } from "react";
2
3
  import { Box, MenuItem, FormControl, Select, Stack, Accordion, AccordionSummary, AccordionDetails, CardMedia, Typography, IconButton, Button } from "@mui/material";
3
4
  import useHonchoTypography from "../../themes/honchoTheme";
4
5
  import useColors from "../../themes/colors";
5
- // Static `presets` array has been removed.
6
6
  export default function HBulkPreset(props) {
7
7
  const typography = useHonchoTypography();
8
8
  const colors = useColors();
9
- const isMenuOpen = Boolean(props.presetMenuAnchorEl);
10
9
  const isPanelExpanded = (panelName) => props.expandedPanels.includes(panelName);
11
10
  const accordionStyle = {
12
11
  backgroundColor: colors.onBackground,
@@ -18,26 +17,26 @@ export default function HBulkPreset(props) {
18
17
  };
19
18
  const CustomSelectIcon = (iconProps) => {
20
19
  const isExpanded = iconProps.className?.includes('MuiSelect-iconOpen');
21
- return (_jsx(CardMedia, { component: "img", image: isExpanded ? "/v1/svg/expand-editor.svg" : "/v1/svg/expanded-editor.svg", sx: { width: "11.67px", height: "5.83px", right: '14px', position: 'absolute', pointerEvents: 'none' } }));
20
+ return (_jsx(CardMedia, { component: "img", image: isExpanded ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px", right: '14px', position: 'absolute', pointerEvents: 'none' } }));
22
21
  };
23
- return (_jsx(_Fragment, { children: _jsx(Stack, { children: _jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('preset'), onChange: props.onPanelChange('preset'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%' }, children: [_jsx(Typography, { sx: { ...typography.titleMedium, color: colors.surface }, children: "Preset" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('preset') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pr: "4px" }, children: _jsx(FormControl, { fullWidth: true, children: _jsxs(Select, { fullWidth: true, value: props.selectedPreset, onChange: props.onSelectPreset, IconComponent: CustomSelectIcon, renderValue: (selectedId) => {
24
- // Handle empty selection case
25
- if (!selectedId) {
26
- return _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface, opacity: 0.7 }, children: "Select Preset" });
27
- }
28
- // Uses props.presets to find the name
29
- const selectedPresetObject = props.presets.find(p => p.id === selectedId);
30
- if (!selectedPresetObject) {
31
- return _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface, opacity: 0.7 }, children: "Select Preset" });
32
- }
33
- return _jsx(Typography, { sx: { ...typography.bodyMedium }, children: selectedPresetObject.name });
34
- }, MenuProps: {
22
+ const handleSelectChange = (event) => {
23
+ props.onSelectPreset(event.target.value);
24
+ };
25
+ const renderValue = useCallback((selectedId) => {
26
+ if (selectedId === 'MULTIPLE_PRESETS') {
27
+ return _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, children: "Multiple presets" });
28
+ }
29
+ if (selectedId === 'NO_SELECTION' || !selectedId || selectedId === '') {
30
+ return _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, children: "Select" });
31
+ }
32
+ const selectedPresetObject = props.presets.find(p => p.id === selectedId);
33
+ if (!selectedPresetObject) {
34
+ return _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, children: "Select" });
35
+ }
36
+ return _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.surface }, children: selectedPresetObject.name });
37
+ }, [props.presets, typography.bodyMedium, colors.surface]);
38
+ // The useEffect that forced re-renders has been removed.
39
+ return (_jsx(_Fragment, { children: _jsx(Stack, { children: _jsxs(Accordion, { sx: accordionStyle, expanded: isPanelExpanded('preset'), onChange: props.onChange('preset'), disableGutters: true, children: [_jsx(AccordionSummary, { sx: { pr: 0 }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { width: '100%', pr: "16px" }, children: [_jsx(Typography, { sx: { ...typography.titleMedium, color: colors.surface }, children: "Preset" }), _jsx(CardMedia, { component: "img", image: isPanelExpanded('preset') ? "/v1/svg/expanded-editor.svg" : "/v1/svg/expand-editor.svg", sx: { width: "11.67px", height: "5.83px" } })] }) }), _jsx(AccordionDetails, { sx: { pl: "16px" }, children: _jsx(FormControl, { fullWidth: true, children: _jsxs(Select, { fullWidth: true, value: props.selectedPreset, onChange: handleSelectChange, IconComponent: CustomSelectIcon, renderValue: renderValue, MenuProps: {
35
40
  slotProps: { paper: { sx: { backgroundColor: colors.onBackground, color: colors.surface, border: `1px solid ${colors.onSurfaceVariant1}`, mt: '20px', width: '178px', boxShadow: 'none' } } }
36
- }, sx: { border: `1px solid ${colors.outlineVariant}`, height: '44px', width: '215px', boxShadow: 'none' }, children: [_jsx(MenuItem, { value: "", sx: { borderRadius: '4px', py: '4px', my: '0px', px: '0px', mx: '0px' }, children: _jsx(Stack, { direction: "row", justifyContent: "center", alignItems: "center", sx: { width: '100%', py: '0px', px: '0px', mx: '0px', my: '4px' }, children: _jsx(Typography, { sx: {
37
- width: '100%',
38
- textAlign: 'center',
39
- color: colors.surface,
40
- opacity: 0.7,
41
- ...typography.bodyMedium
42
- }, children: "No Preset" }) }) }), props.presets.map((preset) => (_jsx(MenuItem, { value: preset.id, sx: { borderRadius: '4px', py: '4px', my: '0px', px: '0px', mx: '0px' }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-around", alignItems: "center", sx: { width: '100%', py: '0px', px: '0px', mx: '0px', my: '4px' }, children: [_jsx(CardMedia, { component: "img", image: "v1/svg/check-ratio-editor.svg", sx: { width: "20px", height: "20px", mr: '-16px', px: '0px', visibility: props.selectedPreset === preset.id ? 'visible' : 'hidden' } }), _jsx(Typography, { sx: { width: '24px', textWrap: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: 'block', color: colors.surface, pr: "82px", pl: "0px", ml: "0px", justifyContent: 'flex-start', ...typography.bodyMedium }, children: preset.name }), _jsx(IconButton, { "aria-label": `Options for ${preset.name}`, onClick: (event) => props.onPresetMenuClick(event, preset.id), sx: { padding: "0px", margin: "0px", mr: "0px" }, children: _jsx(CardMedia, { component: "img", image: "/v1/svg/dots-editor.svg", alt: "Options", sx: { width: '20px', height: '20px' } }) })] }) }, preset.id))), _jsx(Box, { sx: { px: '16px', my: '8px' }, children: _jsx(Button, { fullWidth: true, variant: "outlined", sx: { ...typography.labelMedium, height: '40px', color: colors.onBackground, backgroundColor: colors.surface, borderRadius: '100px', borderColor: colors.surface, textTransform: 'none', '&:hover': { backgroundColor: '#e0e0e0', borderColor: colors.surface } }, onClick: props.onOpenPresetModal, children: "Create Preset" }) })] }) }) })] }) }) }));
41
+ }, sx: { border: `1px solid ${colors.outlineVariant}`, height: '44px', width: '202px', boxShadow: 'none' }, children: [props.presets.map((preset) => (_jsx(MenuItem, { value: preset.id, sx: { borderRadius: '4px', py: '4px', my: '0px', px: '0px', mx: '0px' }, children: _jsxs(Stack, { direction: "row", justifyContent: "space-around", alignItems: "center", sx: { width: '100%', py: '0px', px: '0px', mx: '0px', my: '4px' }, children: [_jsx(CardMedia, { component: "img", image: "/v1/svg/check-ratio-editor.svg", sx: { width: "20px", height: "20px", mr: '-16px', px: '0px', visibility: props.selectedPreset === preset.id ? 'visible' : 'hidden' } }), _jsx(Typography, { sx: { width: '24px', textWrap: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: 'block', color: colors.surface, pr: "82px", pl: "0px", ml: "0px", justifyContent: 'flex-start', ...typography.bodyMedium }, children: preset.name }), _jsx(IconButton, { "aria-label": `Options for ${preset.name}`, onClick: (event) => props.onPresetMenuClick(event, preset.id), sx: { padding: "0px", margin: "0px", mr: "0px" }, children: _jsx(CardMedia, { component: "img", image: "/v1/svg/dots-editor.svg", alt: "Options", sx: { width: '20px', height: '20px' } }) })] }) }, preset.id))), _jsx(Box, { sx: { px: '16px', my: '8px' }, children: _jsx(Button, { fullWidth: true, variant: "outlined", sx: { ...typography.labelMedium, height: '40px', color: colors.onBackground, backgroundColor: colors.surface, borderRadius: '100px', borderColor: colors.surface, textTransform: 'none', '&:hover': { backgroundColor: '#e0e0e0', borderColor: colors.surface } }, onClick: props.onOpenPresetModal, disabled: props.isPresetCreatedSet, children: "Create Preset" }) })] }) }) })] }) }) }));
43
42
  }
@@ -8,8 +8,8 @@ interface Props {
8
8
  presets: Preset[];
9
9
  selectedPresetBulk: string;
10
10
  onOpenPresetModalBulk: () => void;
11
- onSelectPresetBulk: (event: SelectChangeEvent<string>) => void;
12
- onPresetMenuClickBulk: (event: React.MouseEvent<HTMLElement>, presetId: string) => void;
11
+ onSelectPreset: (event: SelectChangeEvent<string>) => void;
12
+ onPresetMenuClick: (event: React.MouseEvent<HTMLElement>, presetId: string) => void;
13
13
  }
14
14
  export default function HBulkPresetMobile(props: Props): import("react/jsx-runtime").JSX.Element;
15
15
  export {};