@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.
@@ -8,46 +8,206 @@ import { useImageGallery, useImageZoom, useClipboard, useKeyboardNavigation } fr
8
8
  import { downloadImage } from "./utils/image-utils";
9
9
 
10
10
  /**
11
- * Enhanced GoalImageGallery Component
12
- *
13
- * This component provides a modern, accessible image gallery with advanced upload capabilities.
14
- *
15
- * Key Features:
16
- * - Multi-method image upload (file selection, clipboard paste, URL loading)
17
- * - Responsive grid layout with hover effects
18
- * - Full-screen image viewer with zoom controls
19
- * - Keyboard navigation support
20
- * - Drag and drop functionality
21
- * - Mobile-friendly interface
22
- * - Accessibility features (ARIA labels, keyboard navigation)
23
- * - Loading states and error handling
24
- *
25
- * Upload Methods:
26
- * 1. File Upload: Click to select or drag and drop image files
27
- * 2. Clipboard Paste: Use Ctrl+V to paste images from clipboard
28
- * 3. URL Loading: Enter image URLs to load remote images
29
- *
30
- * Keyboard Shortcuts (when image is open):
31
- * - Arrow Left/Right: Navigate between images
32
- * - +/=: Zoom in
33
- * - -: Zoom out
34
- * - Escape: Close image viewer
35
- *
36
- * Props:
37
- * - canEdit: Enable editing capabilities
38
- * - ownerEntity: Entity that owns the images
39
- * - imageHandlerApi: API function for image operations
40
- * - afterUpload: Callback after successful upload
41
- * - imageCodes: Array or string of image codes
42
- * - multiple: Allow multiple image selection
43
- * - permission: Required permission for editing
44
- * - emptyMessage: Message shown when no images
45
- * - showImageInfo: Show image information overlay
46
- * - allowDownload: Enable download functionality
47
- * - getImageUrl: Function to get image URL from code
48
- * - noImageUrl: Fallback image URL
49
- * - showError: Function to show error messages
50
- * - hasPermission: Function to check user permissions
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;
@@ -143,7 +143,4 @@ ImageGalleryModal.propTypes = {
143
143
  onPreviousImage: PropTypes.func.isRequired,
144
144
  onNextImage: PropTypes.func.isRequired
145
145
  };
146
- ImageGalleryModal.defaultProps = {
147
- imageUrl: null
148
- };
149
146
  export default ImageGalleryModal;
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.2",
4
- "description": "Enhanced, modular image gallery component for React applications",
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 lint:check && npm run format:check",
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
- "eslint-plugin-react": "^7.31.0",
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": [