@mgonza02/goal-image-gallery 1.0.2 → 1.0.5
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/DOCUMENTATION_UPDATE_SUMMARY.md +311 -0
- package/IMPLEMENTATION_GUIDE.md +1392 -0
- package/PACKAGE_CLEANUP_SUMMARY.md +146 -0
- package/QUICK_REFERENCE.md +46 -0
- package/README.md +850 -85
- package/lib/GoalImageGallery.js +200 -40
- package/lib/components/ImageGalleryEmptyState.js +3 -8
- package/lib/components/ImageGalleryGrid.js +7 -16
- package/lib/components/ImageGalleryItem.js +5 -12
- package/lib/components/ImageGalleryModal.js +0 -3
- package/lib/examples.js +192 -1
- package/lib/index.d.ts +6 -0
- package/lib/styles/styled-components.js +2 -2
- package/package.json +7 -20
package/lib/GoalImageGallery.js
CHANGED
|
@@ -8,46 +8,206 @@ import { useImageGallery, useImageZoom, useClipboard, useKeyboardNavigation } fr
|
|
|
8
8
|
import { downloadImage } from "./utils/image-utils";
|
|
9
9
|
|
|
10
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
|
-
* -
|
|
11
|
+
* GoalImageGallery - Advanced React Image Gallery Component
|
|
12
|
+
*
|
|
13
|
+
* A comprehensive, feature-rich image gallery component designed for modern React applications.
|
|
14
|
+
* Provides advanced upload capabilities, responsive design, accessibility features, and extensive customization options.
|
|
15
|
+
*
|
|
16
|
+
* @component
|
|
17
|
+
* @version 1.0.3
|
|
18
|
+
* @author Goal Team
|
|
19
|
+
* @since 2023
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Basic read-only gallery
|
|
23
|
+
* <GoalImageGallery imageCodes={['img1', 'img2']} canEdit={false} />
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Full-featured editable gallery
|
|
27
|
+
* <GoalImageGallery
|
|
28
|
+
* imageCodes={productImages}
|
|
29
|
+
* canEdit={true}
|
|
30
|
+
* ownerEntity={{ id: 'product-123', type: 'product' }}
|
|
31
|
+
* imageHandlerApi={handleUpload}
|
|
32
|
+
* afterUpload={refreshData}
|
|
33
|
+
* multiple={true}
|
|
34
|
+
* showImageInfo={true}
|
|
35
|
+
* allowDownload={true}
|
|
36
|
+
* />
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // With custom image selector
|
|
40
|
+
* <GoalImageGallery
|
|
41
|
+
* imageCodes={images}
|
|
42
|
+
* canEdit={true}
|
|
43
|
+
* slot={{ selector: CustomImageSelector }}
|
|
44
|
+
* slotProps={{ selector: { maxFileSize: 10485760 } }}
|
|
45
|
+
* />
|
|
46
|
+
*
|
|
47
|
+
* ## Key Features
|
|
48
|
+
*
|
|
49
|
+
* ### 🖼️ Multi-Method Upload
|
|
50
|
+
* - **File Upload**: Drag & drop, file selection dialog
|
|
51
|
+
* - **Clipboard Paste**: Ctrl+V to paste images from clipboard
|
|
52
|
+
* - **URL Loading**: Load images from remote URLs
|
|
53
|
+
* - **Batch Upload**: Multiple files simultaneously
|
|
54
|
+
*
|
|
55
|
+
* ### 🎨 Modern UI/UX
|
|
56
|
+
* - **Responsive Design**: Adapts to all screen sizes
|
|
57
|
+
* - **Material Design 3**: Latest Material-UI styling
|
|
58
|
+
* - **Smooth Animations**: Hover effects, transitions
|
|
59
|
+
* - **Dark/Light Theme**: Automatic theme support
|
|
60
|
+
* - **Loading States**: Progress indicators and skeletons
|
|
61
|
+
*
|
|
62
|
+
* ### 🔍 Advanced Viewer
|
|
63
|
+
* - **Full-Screen Modal**: Immersive viewing experience
|
|
64
|
+
* - **Zoom Controls**: 0.5x to 3x zoom with smooth transitions
|
|
65
|
+
* - **Navigation**: Previous/next with keyboard shortcuts
|
|
66
|
+
* - **Download Support**: Direct image download
|
|
67
|
+
* - **Image Info**: Metadata display
|
|
68
|
+
*
|
|
69
|
+
* ### ♿ Accessibility
|
|
70
|
+
* - **WCAG 2.1 AA**: Compliant with accessibility standards
|
|
71
|
+
* - **Keyboard Navigation**: Full keyboard support
|
|
72
|
+
* - **Screen Reader**: Optimized for screen readers
|
|
73
|
+
* - **Focus Management**: Proper focus handling
|
|
74
|
+
* - **High Contrast**: Support for high contrast mode
|
|
75
|
+
*
|
|
76
|
+
* ### 🛠️ Customization
|
|
77
|
+
* - **Slot System**: Replace components with custom implementations
|
|
78
|
+
* - **Flexible Props**: Extensive configuration options
|
|
79
|
+
* - **TypeScript**: Full type definitions
|
|
80
|
+
* - **Hook Architecture**: Reusable custom hooks
|
|
81
|
+
*
|
|
82
|
+
* ### 📱 Mobile Support
|
|
83
|
+
* - **Touch Gestures**: Swipe, pinch-to-zoom
|
|
84
|
+
* - **Responsive**: Optimized for mobile devices
|
|
85
|
+
* - **Performance**: Lazy loading, efficient rendering
|
|
86
|
+
* - **Camera Integration**: Mobile camera access
|
|
87
|
+
*
|
|
88
|
+
* ## Upload Methods
|
|
89
|
+
*
|
|
90
|
+
* ### 1. File Upload
|
|
91
|
+
* Traditional file selection with modern enhancements:
|
|
92
|
+
* - Click to select files
|
|
93
|
+
* - Drag and drop support
|
|
94
|
+
* - Multiple file selection
|
|
95
|
+
* - File type validation
|
|
96
|
+
* - Size limit enforcement
|
|
97
|
+
* - Progress indication
|
|
98
|
+
*
|
|
99
|
+
* ### 2. Clipboard Paste
|
|
100
|
+
* Revolutionary clipboard image support:
|
|
101
|
+
* - Copy from any source (screenshots, browsers, etc.)
|
|
102
|
+
* - Press Ctrl+V anywhere in the gallery
|
|
103
|
+
* - Automatic processing and optimization
|
|
104
|
+
* - Cross-platform support
|
|
105
|
+
*
|
|
106
|
+
* ### 3. URL Loading
|
|
107
|
+
* Load images from external sources:
|
|
108
|
+
* - Enter direct image URLs
|
|
109
|
+
* - Validation and error handling
|
|
110
|
+
* - CORS support
|
|
111
|
+
* - Format detection
|
|
112
|
+
*
|
|
113
|
+
* ## Keyboard Shortcuts
|
|
114
|
+
*
|
|
115
|
+
* ### Image Viewer
|
|
116
|
+
* - `←` / `→`: Navigate between images
|
|
117
|
+
* - `+` / `=`: Zoom in
|
|
118
|
+
* - `-`: Zoom out
|
|
119
|
+
* - `Escape`: Close viewer
|
|
120
|
+
* - `Space`: Toggle fullscreen
|
|
121
|
+
*
|
|
122
|
+
* ### Gallery Navigation
|
|
123
|
+
* - `Tab`: Navigate elements
|
|
124
|
+
* - `Enter` / `Space`: Activate buttons
|
|
125
|
+
* - `Ctrl+V`: Paste from clipboard
|
|
126
|
+
* - `Delete`: Remove selected image
|
|
127
|
+
*
|
|
128
|
+
* ## Props Reference
|
|
129
|
+
*
|
|
130
|
+
* @param {Object} props - Component props
|
|
131
|
+
* @param {boolean} [props.canEdit=false] - Enable editing capabilities (upload, delete)
|
|
132
|
+
* @param {Object} [props.ownerEntity] - Entity that owns the images (required for editing)
|
|
133
|
+
* @param {Function} [props.imageHandlerApi] - API function for image operations (required for editing)
|
|
134
|
+
* @param {Function} [props.afterUpload] - Callback function called after successful upload
|
|
135
|
+
* @param {string|string[]} [props.imageCodes] - Image codes to display in the gallery
|
|
136
|
+
* @param {boolean} [props.multiple=false] - Allow multiple image selection and upload
|
|
137
|
+
* @param {string} [props.permission] - Required permission string for editing
|
|
138
|
+
* @param {string} [props.emptyMessage="No hay imágenes para mostrar"] - Message when no images
|
|
139
|
+
* @param {boolean} [props.showImageInfo=false] - Show image information overlay
|
|
140
|
+
* @param {boolean} [props.allowDownload=false] - Enable download functionality
|
|
141
|
+
* @param {Function} [props.getImageUrl] - Function to get image URL from code
|
|
142
|
+
* @param {string} [props.noImageUrl="/images/no-image.png"] - Fallback image URL
|
|
143
|
+
* @param {Function} [props.showError] - Function to show error messages
|
|
144
|
+
* @param {Function} [props.hasPermission] - Function to check user permissions
|
|
145
|
+
* @param {string} [props.currentCompany="default"] - Current company identifier
|
|
146
|
+
* @param {Object} [props.slot={}] - Slot components for customization
|
|
147
|
+
* @param {Object} [props.slotProps={}] - Props for slot components
|
|
148
|
+
*
|
|
149
|
+
* ## API Integration
|
|
150
|
+
*
|
|
151
|
+
* The `imageHandlerApi` function should handle image operations:
|
|
152
|
+
*
|
|
153
|
+
* ```javascript
|
|
154
|
+
* const handleImageUpload = async (imageData) => {
|
|
155
|
+
* try {
|
|
156
|
+
* const response = await api.uploadImages({
|
|
157
|
+
* files: imageData.files,
|
|
158
|
+
* companyId: imageData.metadata.companyId,
|
|
159
|
+
* entityId: imageData.metadata.entityId,
|
|
160
|
+
* entityType: imageData.metadata.entityType
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* return {
|
|
164
|
+
* success: true,
|
|
165
|
+
* data: response.data,
|
|
166
|
+
* message: 'Upload successful'
|
|
167
|
+
* };
|
|
168
|
+
* } catch (error) {
|
|
169
|
+
* return {
|
|
170
|
+
* success: false,
|
|
171
|
+
* message: error.message
|
|
172
|
+
* };
|
|
173
|
+
* }
|
|
174
|
+
* };
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* ## Performance Considerations
|
|
178
|
+
*
|
|
179
|
+
* - **Image Optimization**: Automatic thumbnail generation
|
|
180
|
+
* - **Lazy Loading**: Images loaded on demand
|
|
181
|
+
* - **Memory Management**: Proper cleanup of object URLs
|
|
182
|
+
* - **Debounced Operations**: Prevents excessive API calls
|
|
183
|
+
* - **Virtual Scrolling**: For large image sets
|
|
184
|
+
*
|
|
185
|
+
* ## Browser Support
|
|
186
|
+
*
|
|
187
|
+
* - ✅ Chrome/Edge (full support)
|
|
188
|
+
* - ✅ Firefox (full support)
|
|
189
|
+
* - ✅ Safari (full support)
|
|
190
|
+
* - ⚠️ IE11 (limited support, no clipboard paste)
|
|
191
|
+
* - ✅ Mobile browsers (optimized experience)
|
|
192
|
+
*
|
|
193
|
+
* ## Troubleshooting
|
|
194
|
+
*
|
|
195
|
+
* **Images not loading?**
|
|
196
|
+
* - Check image URLs and permissions
|
|
197
|
+
* - Verify network connectivity
|
|
198
|
+
* - Check CORS settings
|
|
199
|
+
*
|
|
200
|
+
* **Upload not working?**
|
|
201
|
+
* - Verify `imageHandlerApi` is properly configured
|
|
202
|
+
* - Check file size limits and formats
|
|
203
|
+
* - Verify user permissions
|
|
204
|
+
*
|
|
205
|
+
* **Clipboard paste not working?**
|
|
206
|
+
* - Ensure HTTPS connection
|
|
207
|
+
* - Check browser compatibility
|
|
208
|
+
* - Verify clipboard permissions
|
|
209
|
+
*
|
|
210
|
+
* @returns {React.ReactElement} The GoalImageGallery component
|
|
51
211
|
*/
|
|
52
212
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
53
213
|
const GoalImageGallery = _ref => {
|
|
@@ -11,9 +11,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
11
11
|
const ImageGalleryEmptyState = _ref => {
|
|
12
12
|
let {
|
|
13
13
|
emptyMessage,
|
|
14
|
-
updatable,
|
|
15
|
-
clipboardSupported,
|
|
16
|
-
onAddImage
|
|
14
|
+
updatable = false,
|
|
15
|
+
clipboardSupported = false,
|
|
16
|
+
onAddImage = () => {}
|
|
17
17
|
} = _ref;
|
|
18
18
|
return /*#__PURE__*/_jsx(StyledEmptyStateContainer, {
|
|
19
19
|
children: /*#__PURE__*/_jsxs(Stack, {
|
|
@@ -79,9 +79,4 @@ ImageGalleryEmptyState.propTypes = {
|
|
|
79
79
|
clipboardSupported: PropTypes.bool,
|
|
80
80
|
onAddImage: PropTypes.func
|
|
81
81
|
};
|
|
82
|
-
ImageGalleryEmptyState.defaultProps = {
|
|
83
|
-
updatable: false,
|
|
84
|
-
clipboardSupported: false,
|
|
85
|
-
onAddImage: () => {}
|
|
86
|
-
};
|
|
87
82
|
export default ImageGalleryEmptyState;
|
|
@@ -15,13 +15,13 @@ const ImageGalleryGrid = _ref => {
|
|
|
15
15
|
let {
|
|
16
16
|
imageList,
|
|
17
17
|
emptyMessage,
|
|
18
|
-
multiple,
|
|
19
|
-
updatable,
|
|
20
|
-
removable,
|
|
21
|
-
allowDownload,
|
|
22
|
-
showImageInfo,
|
|
23
|
-
loading,
|
|
24
|
-
clipboardSupported,
|
|
18
|
+
multiple = false,
|
|
19
|
+
updatable = false,
|
|
20
|
+
removable = false,
|
|
21
|
+
allowDownload = false,
|
|
22
|
+
showImageInfo = false,
|
|
23
|
+
loading = false,
|
|
24
|
+
clipboardSupported = false,
|
|
25
25
|
getImageUrl,
|
|
26
26
|
noImageUrl,
|
|
27
27
|
onImageClick,
|
|
@@ -96,13 +96,4 @@ ImageGalleryGrid.propTypes = {
|
|
|
96
96
|
onRemoveImage: PropTypes.func.isRequired,
|
|
97
97
|
onDownloadImage: PropTypes.func.isRequired
|
|
98
98
|
};
|
|
99
|
-
ImageGalleryGrid.defaultProps = {
|
|
100
|
-
multiple: false,
|
|
101
|
-
updatable: false,
|
|
102
|
-
removable: false,
|
|
103
|
-
allowDownload: false,
|
|
104
|
-
showImageInfo: false,
|
|
105
|
-
loading: false,
|
|
106
|
-
clipboardSupported: false
|
|
107
|
-
};
|
|
108
99
|
export default ImageGalleryGrid;
|
|
@@ -16,11 +16,11 @@ const ImageGalleryItem = _ref => {
|
|
|
16
16
|
index,
|
|
17
17
|
getImageUrl,
|
|
18
18
|
noImageUrl,
|
|
19
|
-
loading,
|
|
20
|
-
updatable,
|
|
21
|
-
removable,
|
|
22
|
-
allowDownload,
|
|
23
|
-
showImageInfo,
|
|
19
|
+
loading = false,
|
|
20
|
+
updatable = false,
|
|
21
|
+
removable = false,
|
|
22
|
+
allowDownload = false,
|
|
23
|
+
showImageInfo = false,
|
|
24
24
|
onImageClick,
|
|
25
25
|
onImageSelect,
|
|
26
26
|
onRemoveImage,
|
|
@@ -165,11 +165,4 @@ ImageGalleryItem.propTypes = {
|
|
|
165
165
|
onRemoveImage: PropTypes.func.isRequired,
|
|
166
166
|
onDownloadImage: PropTypes.func.isRequired
|
|
167
167
|
};
|
|
168
|
-
ImageGalleryItem.defaultProps = {
|
|
169
|
-
loading: false,
|
|
170
|
-
updatable: false,
|
|
171
|
-
removable: false,
|
|
172
|
-
allowDownload: false,
|
|
173
|
-
showImageInfo: false
|
|
174
|
-
};
|
|
175
168
|
export default ImageGalleryItem;
|
package/lib/examples.js
CHANGED
|
@@ -459,6 +459,193 @@ export const FullExampleWithStateManagement = () => {
|
|
|
459
459
|
});
|
|
460
460
|
};
|
|
461
461
|
|
|
462
|
+
// Example: Custom Image Selector with Slots
|
|
463
|
+
export const CustomSelectorExample = () => {
|
|
464
|
+
const [images, setImages] = useState(['custom1', 'custom2']);
|
|
465
|
+
|
|
466
|
+
// Custom Image Selector Component
|
|
467
|
+
const CustomImageSelector = _ref => {
|
|
468
|
+
let {
|
|
469
|
+
afterUpload,
|
|
470
|
+
activate,
|
|
471
|
+
onCancel,
|
|
472
|
+
multiple,
|
|
473
|
+
title,
|
|
474
|
+
uploadMessage,
|
|
475
|
+
maxFileSize,
|
|
476
|
+
customStyles,
|
|
477
|
+
theme = 'blue'
|
|
478
|
+
} = _ref;
|
|
479
|
+
const [dragOver, setDragOver] = useState(false);
|
|
480
|
+
const handleFileSelect = async files => {
|
|
481
|
+
const fileArray = Array.from(files);
|
|
482
|
+
|
|
483
|
+
// Simulate upload process
|
|
484
|
+
for (const file of fileArray) {
|
|
485
|
+
if (file.size > maxFileSize) {
|
|
486
|
+
alert(`File ${file.name} is too large. Maximum size: ${maxFileSize / 1024 / 1024}MB`);
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Simulate API call
|
|
491
|
+
const result = {
|
|
492
|
+
success: true,
|
|
493
|
+
data: {
|
|
494
|
+
code: `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
|
495
|
+
},
|
|
496
|
+
message: 'Image uploaded successfully'
|
|
497
|
+
};
|
|
498
|
+
afterUpload(result);
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
const themeColors = {
|
|
502
|
+
blue: {
|
|
503
|
+
primary: '#007bff',
|
|
504
|
+
secondary: '#e3f2fd'
|
|
505
|
+
},
|
|
506
|
+
green: {
|
|
507
|
+
primary: '#28a745',
|
|
508
|
+
secondary: '#e8f5e8'
|
|
509
|
+
},
|
|
510
|
+
purple: {
|
|
511
|
+
primary: '#6f42c1',
|
|
512
|
+
secondary: '#f3e5f5'
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
const currentTheme = themeColors[theme] || themeColors.blue;
|
|
516
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
517
|
+
sx: {
|
|
518
|
+
...customStyles,
|
|
519
|
+
border: `2px dashed ${dragOver ? currentTheme.primary : '#ccc'}`,
|
|
520
|
+
borderRadius: '12px',
|
|
521
|
+
padding: '40px',
|
|
522
|
+
textAlign: 'center',
|
|
523
|
+
backgroundColor: dragOver ? currentTheme.secondary : '#f8f9fa',
|
|
524
|
+
transition: 'all 0.3s ease',
|
|
525
|
+
cursor: 'pointer',
|
|
526
|
+
position: 'relative'
|
|
527
|
+
},
|
|
528
|
+
onDragOver: e => {
|
|
529
|
+
e.preventDefault();
|
|
530
|
+
setDragOver(true);
|
|
531
|
+
},
|
|
532
|
+
onDragLeave: () => setDragOver(false),
|
|
533
|
+
onDrop: e => {
|
|
534
|
+
e.preventDefault();
|
|
535
|
+
setDragOver(false);
|
|
536
|
+
handleFileSelect(e.dataTransfer.files);
|
|
537
|
+
},
|
|
538
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
539
|
+
variant: "h5",
|
|
540
|
+
gutterBottom: true,
|
|
541
|
+
color: currentTheme.primary,
|
|
542
|
+
children: title
|
|
543
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
544
|
+
variant: "body1",
|
|
545
|
+
color: "text.secondary",
|
|
546
|
+
paragraph: true,
|
|
547
|
+
children: uploadMessage
|
|
548
|
+
}), /*#__PURE__*/_jsxs(Typography, {
|
|
549
|
+
variant: "caption",
|
|
550
|
+
display: "block",
|
|
551
|
+
color: "text.secondary",
|
|
552
|
+
sx: {
|
|
553
|
+
mb: 2
|
|
554
|
+
},
|
|
555
|
+
children: ["Maximum file size: ", maxFileSize / 1024 / 1024, "MB | Theme: ", theme]
|
|
556
|
+
}), /*#__PURE__*/_jsx("input", {
|
|
557
|
+
type: "file",
|
|
558
|
+
multiple: multiple,
|
|
559
|
+
accept: "image/*",
|
|
560
|
+
onChange: e => handleFileSelect(e.target.files),
|
|
561
|
+
style: {
|
|
562
|
+
position: 'absolute',
|
|
563
|
+
top: 0,
|
|
564
|
+
left: 0,
|
|
565
|
+
width: '100%',
|
|
566
|
+
height: '100%',
|
|
567
|
+
opacity: 0,
|
|
568
|
+
cursor: 'pointer'
|
|
569
|
+
}
|
|
570
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
571
|
+
variant: "contained",
|
|
572
|
+
sx: {
|
|
573
|
+
mr: 2,
|
|
574
|
+
backgroundColor: currentTheme.primary,
|
|
575
|
+
'&:hover': {
|
|
576
|
+
backgroundColor: currentTheme.primary,
|
|
577
|
+
opacity: 0.8
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
children: "Choose Files"
|
|
581
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
582
|
+
variant: "outlined",
|
|
583
|
+
onClick: onCancel,
|
|
584
|
+
children: "Cancel"
|
|
585
|
+
})]
|
|
586
|
+
});
|
|
587
|
+
};
|
|
588
|
+
const handleCustomUpload = useCallback(async imageData => {
|
|
589
|
+
console.log('Custom upload data:', imageData);
|
|
590
|
+
|
|
591
|
+
// Simulate API response
|
|
592
|
+
return new Promise(resolve => {
|
|
593
|
+
setTimeout(() => {
|
|
594
|
+
resolve({
|
|
595
|
+
success: true,
|
|
596
|
+
data: imageData.data,
|
|
597
|
+
message: 'Custom upload successful'
|
|
598
|
+
});
|
|
599
|
+
}, 500);
|
|
600
|
+
});
|
|
601
|
+
}, []);
|
|
602
|
+
const refreshCustomGallery = useCallback(result => {
|
|
603
|
+
setImages(prev => [...prev, result.data.code]);
|
|
604
|
+
}, []);
|
|
605
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
606
|
+
sx: {
|
|
607
|
+
p: 2
|
|
608
|
+
},
|
|
609
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
610
|
+
variant: "h6",
|
|
611
|
+
gutterBottom: true,
|
|
612
|
+
children: "Custom Image Selector with Slots"
|
|
613
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
614
|
+
variant: "body2",
|
|
615
|
+
color: "text.secondary",
|
|
616
|
+
paragraph: true,
|
|
617
|
+
children: "This example demonstrates how to use the slot system to provide a custom image selector with enhanced UI and functionality."
|
|
618
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
619
|
+
imageCodes: images,
|
|
620
|
+
canEdit: true,
|
|
621
|
+
ownerEntity: {
|
|
622
|
+
id: 'custom-selector-gallery',
|
|
623
|
+
type: 'gallery'
|
|
624
|
+
},
|
|
625
|
+
imageHandlerApi: handleCustomUpload,
|
|
626
|
+
afterUpload: refreshCustomGallery,
|
|
627
|
+
multiple: true,
|
|
628
|
+
emptyMessage: "Custom selector gallery - upload with style!",
|
|
629
|
+
showImageInfo: true,
|
|
630
|
+
allowDownload: true,
|
|
631
|
+
slot: {
|
|
632
|
+
selector: CustomImageSelector
|
|
633
|
+
},
|
|
634
|
+
slotProps: {
|
|
635
|
+
selector: {
|
|
636
|
+
maxFileSize: 5 * 1024 * 1024,
|
|
637
|
+
// 5MB
|
|
638
|
+
theme: 'blue',
|
|
639
|
+
customStyles: {
|
|
640
|
+
minHeight: '200px',
|
|
641
|
+
margin: '20px 0'
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
})]
|
|
646
|
+
});
|
|
647
|
+
};
|
|
648
|
+
|
|
462
649
|
// Complete Demo Component
|
|
463
650
|
export const GoalImageGalleryExamples = () => {
|
|
464
651
|
return /*#__PURE__*/_jsxs(Box, {
|
|
@@ -497,7 +684,11 @@ export const GoalImageGalleryExamples = () => {
|
|
|
497
684
|
sx: {
|
|
498
685
|
my: 3
|
|
499
686
|
}
|
|
500
|
-
}), /*#__PURE__*/_jsx(FullExampleWithStateManagement, {})
|
|
687
|
+
}), /*#__PURE__*/_jsx(FullExampleWithStateManagement, {}), /*#__PURE__*/_jsx(Divider, {
|
|
688
|
+
sx: {
|
|
689
|
+
my: 3
|
|
690
|
+
}
|
|
691
|
+
}), /*#__PURE__*/_jsx(CustomSelectorExample, {})]
|
|
501
692
|
});
|
|
502
693
|
};
|
|
503
694
|
export default GoalImageGalleryExamples;
|
package/lib/index.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export interface GoalImageGalleryProps {
|
|
|
17
17
|
showError?: (message: string) => void;
|
|
18
18
|
hasPermission?: (permission: string) => boolean;
|
|
19
19
|
currentCompany?: string;
|
|
20
|
+
slot?: {
|
|
21
|
+
selector?: React.ComponentType<any>;
|
|
22
|
+
};
|
|
23
|
+
slotProps?: {
|
|
24
|
+
selector?: object;
|
|
25
|
+
};
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
// Image item interface
|
|
@@ -70,9 +70,9 @@ export const StyledModalContainer = styled(Box)(_ref3 => {
|
|
|
70
70
|
isMobile
|
|
71
71
|
} = _ref3;
|
|
72
72
|
return {
|
|
73
|
+
top: isMobile ? '1vh' : '3vh',
|
|
74
|
+
left: isMobile ? '0' : '2vw',
|
|
73
75
|
position: 'absolute',
|
|
74
|
-
top: '50%',
|
|
75
|
-
left: '50%',
|
|
76
76
|
transform: 'translate(-50%, -50%)',
|
|
77
77
|
width: isMobile ? '95vw' : '90vw',
|
|
78
78
|
maxWidth: 1200,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mgonza02/goal-image-gallery",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Advanced, accessible, and highly customizable React image gallery component with multi-method upload, responsive design, and extensive TypeScript support",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -35,7 +35,10 @@
|
|
|
35
35
|
"README.md",
|
|
36
36
|
"QUICK_REFERENCE.md",
|
|
37
37
|
"MIGRATION.md",
|
|
38
|
+
"IMPLEMENTATION_GUIDE.md",
|
|
38
39
|
"IMPLEMENTATION_SUMMARY.md",
|
|
40
|
+
"DOCUMENTATION_UPDATE_SUMMARY.md",
|
|
41
|
+
"PACKAGE_CLEANUP_SUMMARY.md",
|
|
39
42
|
"LICENSE"
|
|
40
43
|
],
|
|
41
44
|
"peerDependencies": {
|
|
@@ -54,13 +57,10 @@
|
|
|
54
57
|
"build:js": "babel src --out-dir lib --copy-files --ignore '**/*.test.js'",
|
|
55
58
|
"build:types": "cp src/index.d.ts lib/index.d.ts",
|
|
56
59
|
"prepublishOnly": "npm run build",
|
|
57
|
-
"test": "jest",
|
|
58
|
-
"lint": "echo 'Linting skipped for now'",
|
|
59
|
-
"lint:check": "echo 'Lint check skipped for now'",
|
|
60
60
|
"format": "prettier --write src/**/*.js",
|
|
61
61
|
"format:check": "prettier --check src/**/*.js",
|
|
62
62
|
"clean": "rm -rf lib",
|
|
63
|
-
"validate": "npm run
|
|
63
|
+
"validate": "npm run format:check",
|
|
64
64
|
"dev": "npm run build -- --watch",
|
|
65
65
|
"prepack": "npm run validate && npm run build"
|
|
66
66
|
},
|
|
@@ -69,20 +69,7 @@
|
|
|
69
69
|
"@babel/core": "^7.20.0",
|
|
70
70
|
"@babel/preset-env": "^7.20.0",
|
|
71
71
|
"@babel/preset-react": "^7.18.0",
|
|
72
|
-
"
|
|
73
|
-
"eslint-plugin-react-hooks": "^4.6.0",
|
|
74
|
-
"jest": "^29.0.0",
|
|
75
|
-
"@babel/eslint-parser": "^7.25.9",
|
|
76
|
-
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
|
77
|
-
"@testing-library/jest-dom": "^6.6.3",
|
|
78
|
-
"babel-preset-react-app": "^10.0.1",
|
|
79
|
-
"eslint": "^9.16.0",
|
|
80
|
-
"eslint-config-prettier": "^9.1.0",
|
|
81
|
-
"eslint-plugin-prettier": "^5.2.1",
|
|
82
|
-
"http-proxy-middleware": "^3.0.3",
|
|
83
|
-
"prettier": "^3.4.2",
|
|
84
|
-
"typescript": "^5.7.2",
|
|
85
|
-
"web-vitals": "^4.2.4"
|
|
72
|
+
"prettier": "^3.4.2"
|
|
86
73
|
},
|
|
87
74
|
"browserslist": {
|
|
88
75
|
"production": [
|