@qwickapps/react-framework 1.5.12 → 1.5.13

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 (38) hide show
  1. package/README.md +23 -0
  2. package/dist/components/blocks/ImageGallery.d.ts +30 -0
  3. package/dist/components/blocks/ImageGallery.d.ts.map +1 -0
  4. package/dist/components/blocks/OptionSelector.d.ts +45 -0
  5. package/dist/components/blocks/OptionSelector.d.ts.map +1 -0
  6. package/dist/components/blocks/index.d.ts +4 -0
  7. package/dist/components/blocks/index.d.ts.map +1 -1
  8. package/dist/index.esm.js +1192 -265
  9. package/dist/index.js +1194 -263
  10. package/dist/palettes/manifest.json +19 -19
  11. package/dist/schemas/ImageGallerySchema.d.ts +27 -0
  12. package/dist/schemas/ImageGallerySchema.d.ts.map +1 -0
  13. package/dist/schemas/OptionSelectorSchema.d.ts +34 -0
  14. package/dist/schemas/OptionSelectorSchema.d.ts.map +1 -0
  15. package/dist/schemas/index.d.ts +2 -0
  16. package/dist/schemas/index.d.ts.map +1 -1
  17. package/package.json +1 -1
  18. package/src/components/blocks/Article.tsx +1 -1
  19. package/src/components/blocks/ImageGallery.tsx +464 -0
  20. package/src/components/blocks/OptionSelector.tsx +459 -0
  21. package/src/components/blocks/index.ts +4 -0
  22. package/src/schemas/ImageGallerySchema.ts +148 -0
  23. package/src/schemas/OptionSelectorSchema.ts +216 -0
  24. package/src/schemas/index.ts +2 -0
  25. package/src/stories/ImageGallery.stories.tsx +497 -0
  26. package/src/stories/OptionSelector.stories.tsx +506 -0
  27. /package/dist/palettes/{palette-autumn.1.5.12.css → palette-autumn.1.5.13.css} +0 -0
  28. /package/dist/palettes/{palette-autumn.1.5.12.min.css → palette-autumn.1.5.13.min.css} +0 -0
  29. /package/dist/palettes/{palette-cosmic.1.5.12.css → palette-cosmic.1.5.13.css} +0 -0
  30. /package/dist/palettes/{palette-cosmic.1.5.12.min.css → palette-cosmic.1.5.13.min.css} +0 -0
  31. /package/dist/palettes/{palette-default.1.5.12.css → palette-default.1.5.13.css} +0 -0
  32. /package/dist/palettes/{palette-default.1.5.12.min.css → palette-default.1.5.13.min.css} +0 -0
  33. /package/dist/palettes/{palette-ocean.1.5.12.css → palette-ocean.1.5.13.css} +0 -0
  34. /package/dist/palettes/{palette-ocean.1.5.12.min.css → palette-ocean.1.5.13.min.css} +0 -0
  35. /package/dist/palettes/{palette-spring.1.5.12.css → palette-spring.1.5.13.css} +0 -0
  36. /package/dist/palettes/{palette-spring.1.5.12.min.css → palette-spring.1.5.13.min.css} +0 -0
  37. /package/dist/palettes/{palette-winter.1.5.12.css → palette-winter.1.5.13.css} +0 -0
  38. /package/dist/palettes/{palette-winter.1.5.12.min.css → palette-winter.1.5.13.min.css} +0 -0
package/dist/index.js CHANGED
@@ -108,6 +108,9 @@ var Warning$3 = require('@mui/icons-material/Warning');
108
108
  var classValidator = require('class-validator');
109
109
  var classTransformer = require('class-transformer');
110
110
  require('reflect-metadata');
111
+ var ZoomInIcon = require('@mui/icons-material/ZoomIn');
112
+ var ChevronLeftIcon = require('@mui/icons-material/ChevronLeft');
113
+ var ChevronRightIcon = require('@mui/icons-material/ChevronRight');
111
114
  var reactRouterDom = require('react-router-dom');
112
115
 
113
116
  /**
@@ -18949,281 +18952,283 @@ function ArticleView({
18949
18952
  ...htmlProps,
18950
18953
  ...otherProps,
18951
18954
  ...styleProps,
18952
- // Modern article layout
18953
- maxWidth: '900px',
18954
- mx: 'auto',
18955
- px: {
18956
- xs: 2,
18957
- sm: 3,
18958
- md: 4
18959
- },
18960
- py: {
18961
- xs: 3,
18962
- md: 5
18963
- },
18964
- // Typography - Modern, readable hierarchy
18965
- '& h1, & h2, & h3, & h4, & h5, & h6': {
18966
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
18967
- fontWeight: 700,
18968
- letterSpacing: '-0.02em',
18969
- color: 'var(--theme-text)',
18970
- scrollMarginTop: '100px',
18971
- // For anchor links
18972
- '&:first-of-type': {
18973
- mt: 0
18974
- }
18975
- },
18976
- '& h1': {
18977
- fontSize: {
18978
- xs: '2rem',
18979
- md: '2.75rem'
18955
+ sx: {
18956
+ // Modern article layout
18957
+ maxWidth: '900px',
18958
+ mx: 'auto',
18959
+ px: {
18960
+ xs: 2,
18961
+ sm: 3,
18962
+ md: 4
18980
18963
  },
18981
- lineHeight: 1.15,
18982
- mb: 3,
18983
- mt: 5
18984
- },
18985
- '& h2': {
18986
- fontSize: {
18987
- xs: '1.5rem',
18988
- md: '2rem'
18964
+ py: {
18965
+ xs: 3,
18966
+ md: 5
18989
18967
  },
18990
- lineHeight: 1.25,
18991
- mb: 2.5,
18992
- mt: 5,
18993
- pb: 1.5,
18994
- borderBottom: '1px solid var(--theme-border-lighter)'
18995
- },
18996
- '& h3': {
18997
- fontSize: {
18998
- xs: '1.25rem',
18999
- md: '1.5rem'
18968
+ // Typography - Modern, readable hierarchy
18969
+ '& h1, & h2, & h3, & h4, & h5, & h6': {
18970
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
18971
+ fontWeight: 700,
18972
+ letterSpacing: '-0.02em',
18973
+ color: 'var(--theme-text)',
18974
+ scrollMarginTop: '100px',
18975
+ // For anchor links
18976
+ '&:first-of-type': {
18977
+ mt: 0
18978
+ }
19000
18979
  },
19001
- lineHeight: 1.3,
19002
- mb: 2,
19003
- mt: 4
19004
- },
19005
- '& h4': {
19006
- fontSize: {
19007
- xs: '1.1rem',
19008
- md: '1.25rem'
18980
+ '& h1': {
18981
+ fontSize: {
18982
+ xs: '2rem',
18983
+ md: '2.75rem'
18984
+ },
18985
+ lineHeight: 1.15,
18986
+ mb: 3,
18987
+ mt: 5
19009
18988
  },
19010
- lineHeight: 1.4,
19011
- mb: 1.5,
19012
- mt: 3,
19013
- color: 'var(--theme-text)',
19014
- fontWeight: 600
19015
- },
19016
- // Body text - Optimized for reading
19017
- '& p': {
19018
- fontSize: {
19019
- xs: '1rem',
19020
- md: '1.0625rem'
18989
+ '& h2': {
18990
+ fontSize: {
18991
+ xs: '1.5rem',
18992
+ md: '2rem'
18993
+ },
18994
+ lineHeight: 1.25,
18995
+ mb: 2.5,
18996
+ mt: 5,
18997
+ pb: 1.5,
18998
+ borderBottom: '1px solid var(--theme-border-lighter)'
19021
18999
  },
19022
- lineHeight: 1.75,
19023
- mb: 2,
19024
- color: 'var(--theme-text)',
19025
- fontFamily: 'Georgia, "Times New Roman", serif',
19026
- '&:last-child': {
19027
- mb: 0
19028
- }
19029
- },
19030
- // Lists - Better visual hierarchy
19031
- '& ul, & ol': {
19032
- mb: 3,
19033
- pl: {
19034
- xs: 3,
19035
- md: 4
19000
+ '& h3': {
19001
+ fontSize: {
19002
+ xs: '1.25rem',
19003
+ md: '1.5rem'
19004
+ },
19005
+ lineHeight: 1.3,
19006
+ mb: 2,
19007
+ mt: 4
19036
19008
  },
19037
- '& li': {
19038
- mb: 1.25,
19039
- lineHeight: 1.7,
19009
+ '& h4': {
19010
+ fontSize: {
19011
+ xs: '1.1rem',
19012
+ md: '1.25rem'
19013
+ },
19014
+ lineHeight: 1.4,
19015
+ mb: 1.5,
19016
+ mt: 3,
19017
+ color: 'var(--theme-text)',
19018
+ fontWeight: 600
19019
+ },
19020
+ // Body text - Optimized for reading
19021
+ '& p': {
19040
19022
  fontSize: {
19041
19023
  xs: '1rem',
19042
19024
  md: '1.0625rem'
19043
19025
  },
19026
+ lineHeight: 1.75,
19027
+ mb: 2,
19044
19028
  color: 'var(--theme-text)',
19045
19029
  fontFamily: 'Georgia, "Times New Roman", serif',
19046
- '&::marker': {
19047
- color: 'var(--theme-primary)',
19048
- fontWeight: 600
19049
- },
19050
- '& p': {
19051
- mb: 0.5
19030
+ '&:last-child': {
19031
+ mb: 0
19052
19032
  }
19053
19033
  },
19034
+ // Lists - Better visual hierarchy
19054
19035
  '& ul, & ol': {
19055
- mt: 1,
19056
- mb: 0
19057
- }
19058
- },
19059
- // Code blocks - Modern syntax highlighting style
19060
- '& pre': {
19061
- backgroundColor: 'var(--theme-surface-elevated)',
19062
- color: 'var(--theme-text)',
19063
- borderRadius: 'var(--theme-border-radius)',
19064
- p: {
19065
- xs: 2,
19066
- md: 3
19067
- },
19068
- mb: 3,
19069
- overflow: 'auto',
19070
- fontSize: '0.9rem',
19071
- lineHeight: 1.6,
19072
- fontFamily: '"Fira Code", "Cascadia Code", "SF Mono", Monaco, Consolas, monospace',
19073
- border: '1px solid var(--theme-border-light)',
19074
- boxShadow: 'var(--theme-elevation-2)',
19075
- '& code': {
19076
- backgroundColor: 'transparent',
19077
- color: 'inherit',
19078
- padding: 0,
19079
- fontSize: 'inherit',
19080
- fontFamily: 'inherit'
19081
- }
19082
- },
19083
- // Inline code - Subtle highlight
19084
- '& code': {
19085
- backgroundColor: 'var(--theme-code-bg)',
19086
- color: 'var(--theme-error)',
19087
- padding: '0.2em 0.4em',
19088
- borderRadius: 'var(--theme-border-radius-small)',
19089
- fontSize: '0.9em',
19090
- fontFamily: '"Fira Code", "Cascadia Code", "SF Mono", Monaco, Consolas, monospace',
19091
- fontWeight: 500
19092
- },
19093
- // Blockquotes - Elegant callouts
19094
- '& blockquote': {
19095
- borderLeft: '4px solid var(--theme-primary)',
19096
- backgroundColor: 'var(--theme-surface-variant)',
19097
- borderRadius: `0 var(--theme-border-radius-small) var(--theme-border-radius-small) 0`,
19098
- pl: 3,
19099
- pr: 3,
19100
- py: 2.5,
19101
- my: 4,
19102
- ml: 0,
19103
- mr: 0,
19104
- '& p': {
19105
- fontSize: {
19106
- xs: '1.05rem',
19107
- md: '1.125rem'
19036
+ mb: 3,
19037
+ pl: {
19038
+ xs: 3,
19039
+ md: 4
19108
19040
  },
19109
- fontStyle: 'italic',
19110
- lineHeight: 1.6,
19111
- mb: 1.5,
19112
- color: 'var(--theme-text)',
19113
- '&:last-child': {
19041
+ '& li': {
19042
+ mb: 1.25,
19043
+ lineHeight: 1.7,
19044
+ fontSize: {
19045
+ xs: '1rem',
19046
+ md: '1.0625rem'
19047
+ },
19048
+ color: 'var(--theme-text)',
19049
+ fontFamily: 'Georgia, "Times New Roman", serif',
19050
+ '&::marker': {
19051
+ color: 'var(--theme-primary)',
19052
+ fontWeight: 600
19053
+ },
19054
+ '& p': {
19055
+ mb: 0.5
19056
+ }
19057
+ },
19058
+ '& ul, & ol': {
19059
+ mt: 1,
19114
19060
  mb: 0
19115
19061
  }
19116
19062
  },
19117
- '& cite': {
19118
- display: 'block',
19119
- fontSize: '0.9rem',
19120
- fontStyle: 'normal',
19121
- fontWeight: 500,
19063
+ // Code blocks - Modern syntax highlighting style
19064
+ '& pre': {
19065
+ backgroundColor: 'var(--theme-surface-elevated)',
19122
19066
  color: 'var(--theme-text)',
19123
- mt: 1,
19124
- '&::before': {
19125
- content: '"— "',
19126
- color: 'var(--theme-primary)'
19067
+ borderRadius: 'var(--theme-border-radius)',
19068
+ p: {
19069
+ xs: 2,
19070
+ md: 3
19071
+ },
19072
+ mb: 3,
19073
+ overflow: 'auto',
19074
+ fontSize: '0.9rem',
19075
+ lineHeight: 1.6,
19076
+ fontFamily: '"Fira Code", "Cascadia Code", "SF Mono", Monaco, Consolas, monospace',
19077
+ border: '1px solid var(--theme-border-light)',
19078
+ boxShadow: 'var(--theme-elevation-2)',
19079
+ '& code': {
19080
+ backgroundColor: 'transparent',
19081
+ color: 'inherit',
19082
+ padding: 0,
19083
+ fontSize: 'inherit',
19084
+ fontFamily: 'inherit'
19127
19085
  }
19128
- }
19129
- },
19130
- // Tables - Clean, modern design
19131
- '& table': {
19132
- width: '100%',
19133
- borderCollapse: 'separate',
19134
- borderSpacing: 0,
19135
- mb: 3,
19136
- fontSize: '0.95rem',
19137
- overflow: 'hidden',
19138
- borderRadius: 'var(--theme-border-radius-small)',
19139
- border: '1px solid var(--theme-border-light)',
19140
- '& thead': {
19086
+ },
19087
+ // Inline code - Subtle highlight
19088
+ '& code': {
19089
+ backgroundColor: 'var(--theme-code-bg)',
19090
+ color: 'var(--theme-error)',
19091
+ padding: '0.2em 0.4em',
19092
+ borderRadius: 'var(--theme-border-radius-small)',
19093
+ fontSize: '0.9em',
19094
+ fontFamily: '"Fira Code", "Cascadia Code", "SF Mono", Monaco, Consolas, monospace',
19095
+ fontWeight: 500
19096
+ },
19097
+ // Blockquotes - Elegant callouts
19098
+ '& blockquote': {
19099
+ borderLeft: '4px solid var(--theme-primary)',
19141
19100
  backgroundColor: 'var(--theme-surface-variant)',
19142
- '& th': {
19143
- padding: '12px 16px',
19144
- textAlign: 'left',
19145
- fontWeight: 600,
19101
+ borderRadius: `0 var(--theme-border-radius-small) var(--theme-border-radius-small) 0`,
19102
+ pl: 3,
19103
+ pr: 3,
19104
+ py: 2.5,
19105
+ my: 4,
19106
+ ml: 0,
19107
+ mr: 0,
19108
+ '& p': {
19109
+ fontSize: {
19110
+ xs: '1.05rem',
19111
+ md: '1.125rem'
19112
+ },
19113
+ fontStyle: 'italic',
19114
+ lineHeight: 1.6,
19115
+ mb: 1.5,
19146
19116
  color: 'var(--theme-text)',
19147
- borderBottom: '2px solid var(--theme-border-main)',
19148
- fontSize: '0.875rem',
19149
- textTransform: 'uppercase',
19150
- letterSpacing: '0.05em'
19117
+ '&:last-child': {
19118
+ mb: 0
19119
+ }
19120
+ },
19121
+ '& cite': {
19122
+ display: 'block',
19123
+ fontSize: '0.9rem',
19124
+ fontStyle: 'normal',
19125
+ fontWeight: 500,
19126
+ color: 'var(--theme-text)',
19127
+ mt: 1,
19128
+ '&::before': {
19129
+ content: '"— "',
19130
+ color: 'var(--theme-primary)'
19131
+ }
19151
19132
  }
19152
19133
  },
19153
- '& tbody': {
19154
- '& tr': {
19155
- borderBottom: '1px solid var(--theme-border-lighter)',
19156
- transition: 'background-color 0.2s ease',
19157
- '&:hover': {
19158
- backgroundColor: 'var(--theme-surface-variant)'
19134
+ // Tables - Clean, modern design
19135
+ '& table': {
19136
+ width: '100%',
19137
+ borderCollapse: 'separate',
19138
+ borderSpacing: 0,
19139
+ mb: 3,
19140
+ fontSize: '0.95rem',
19141
+ overflow: 'hidden',
19142
+ borderRadius: 'var(--theme-border-radius-small)',
19143
+ border: '1px solid var(--theme-border-light)',
19144
+ '& thead': {
19145
+ backgroundColor: 'var(--theme-surface-variant)',
19146
+ '& th': {
19147
+ padding: '12px 16px',
19148
+ textAlign: 'left',
19149
+ fontWeight: 600,
19150
+ color: 'var(--theme-text)',
19151
+ borderBottom: '2px solid var(--theme-border-main)',
19152
+ fontSize: '0.875rem',
19153
+ textTransform: 'uppercase',
19154
+ letterSpacing: '0.05em'
19155
+ }
19156
+ },
19157
+ '& tbody': {
19158
+ '& tr': {
19159
+ borderBottom: '1px solid var(--theme-border-lighter)',
19160
+ transition: 'background-color 0.2s ease',
19161
+ '&:hover': {
19162
+ backgroundColor: 'var(--theme-surface-variant)'
19163
+ },
19164
+ '&:last-child': {
19165
+ borderBottom: 'none'
19166
+ }
19159
19167
  },
19160
- '&:last-child': {
19161
- borderBottom: 'none'
19168
+ '& td': {
19169
+ padding: '12px 16px',
19170
+ color: 'var(--theme-text)',
19171
+ lineHeight: 1.6
19162
19172
  }
19173
+ }
19174
+ },
19175
+ // Text emphasis
19176
+ '& strong': {
19177
+ fontWeight: 700,
19178
+ color: 'var(--theme-text)'
19179
+ },
19180
+ '& em': {
19181
+ fontStyle: 'italic',
19182
+ color: 'var(--theme-text)'
19183
+ },
19184
+ // Links - Modern, accessible
19185
+ '& a': {
19186
+ color: 'var(--theme-primary)',
19187
+ textDecoration: 'none',
19188
+ fontWeight: 500,
19189
+ borderBottom: '1px solid transparent',
19190
+ transition: 'border-color 0.2s ease',
19191
+ '&:hover': {
19192
+ borderBottomColor: 'var(--theme-primary)'
19163
19193
  },
19164
- '& td': {
19165
- padding: '12px 16px',
19166
- color: 'var(--theme-text)',
19167
- lineHeight: 1.6
19194
+ '&:focus-visible': {
19195
+ outline: '2px solid var(--theme-primary)',
19196
+ outlineOffset: '2px',
19197
+ borderRadius: '2px'
19168
19198
  }
19169
- }
19170
- },
19171
- // Text emphasis
19172
- '& strong': {
19173
- fontWeight: 700,
19174
- color: 'var(--theme-text)'
19175
- },
19176
- '& em': {
19177
- fontStyle: 'italic',
19178
- color: 'var(--theme-text)'
19179
- },
19180
- // Links - Modern, accessible
19181
- '& a': {
19182
- color: 'var(--theme-primary)',
19183
- textDecoration: 'none',
19184
- fontWeight: 500,
19185
- borderBottom: '1px solid transparent',
19186
- transition: 'border-color 0.2s ease',
19187
- '&:hover': {
19188
- borderBottomColor: 'var(--theme-primary)'
19189
19199
  },
19190
- '&:focus-visible': {
19191
- outline: '2px solid var(--theme-primary)',
19192
- outlineOffset: '2px',
19193
- borderRadius: '2px'
19194
- }
19195
- },
19196
- // Images and figures
19197
- '& img': {
19198
- maxWidth: '100%',
19199
- height: 'auto',
19200
- borderRadius: 'var(--theme-border-radius-small)',
19201
- display: 'block',
19202
- my: 3
19203
- },
19204
- '& figure': {
19205
- margin: '3rem 0',
19200
+ // Images and figures
19206
19201
  '& img': {
19207
19202
  maxWidth: '100%',
19208
19203
  height: 'auto',
19209
19204
  borderRadius: 'var(--theme-border-radius-small)',
19210
- boxShadow: 'var(--theme-elevation-2)'
19205
+ display: 'block',
19206
+ my: 3
19211
19207
  },
19212
- '& figcaption': {
19213
- textAlign: 'center',
19214
- fontSize: '0.875rem',
19215
- color: 'var(--theme-text)',
19216
- mt: 1.5,
19217
- fontStyle: 'italic'
19218
- }
19219
- },
19220
- // Horizontal rules
19221
- '& hr': {
19222
- border: 'none',
19223
- borderTop: '1px solid var(--theme-border-light)',
19224
- my: 5
19208
+ '& figure': {
19209
+ margin: '3rem 0',
19210
+ '& img': {
19211
+ maxWidth: '100%',
19212
+ height: 'auto',
19213
+ borderRadius: 'var(--theme-border-radius-small)',
19214
+ boxShadow: 'var(--theme-elevation-2)'
19215
+ },
19216
+ '& figcaption': {
19217
+ textAlign: 'center',
19218
+ fontSize: '0.875rem',
19219
+ color: 'var(--theme-text)',
19220
+ mt: 1.5,
19221
+ fontStyle: 'italic'
19222
+ }
19223
+ },
19224
+ // Horizontal rules
19225
+ '& hr': {
19226
+ border: 'none',
19227
+ borderTop: '1px solid var(--theme-border-light)',
19228
+ my: 5
19229
+ },
19230
+ ...styleProps.sx
19225
19231
  },
19226
- ...styleProps.sx,
19227
19232
  children: html
19228
19233
  });
19229
19234
  }
@@ -21387,35 +21392,664 @@ function ProductCard(props) {
21387
21392
  technologies: ['Loading'],
21388
21393
  status: 'coming-soon'
21389
21394
  },
21390
- variant: restProps.variant || 'compact',
21391
- showImage: false
21395
+ variant: restProps.variant || 'compact',
21396
+ showImage: false
21397
+ });
21398
+ }
21399
+ if (error) {
21400
+ console.error('Error loading product card:', error);
21401
+ {
21402
+ return jsxRuntime.jsx(ProductCardView, {
21403
+ ...restProps,
21404
+ product: {
21405
+ id: 'error-product',
21406
+ name: 'Product Loading Error',
21407
+ category: 'Error',
21408
+ description: error.message,
21409
+ features: ['Unable to load product features'],
21410
+ technologies: ['N/A'],
21411
+ status: 'coming-soon'
21412
+ },
21413
+ variant: restProps.variant || 'compact',
21414
+ showImage: false
21415
+ });
21416
+ }
21417
+ }
21418
+ // Pass through data directly - let component handle missing properties
21419
+ const transformedProps = productProps;
21420
+ return jsxRuntime.jsx(ProductCardView, {
21421
+ ...transformedProps
21422
+ });
21423
+ }
21424
+
21425
+ // View component - handles the actual rendering
21426
+ function ImageGalleryView({
21427
+ images = [],
21428
+ productName,
21429
+ variant = 'thumbnails',
21430
+ thumbnailPosition = 'left',
21431
+ aspectRatio = '1',
21432
+ showZoom = true,
21433
+ maxImages,
21434
+ dataSource,
21435
+ bindingOptions,
21436
+ ...restProps
21437
+ }) {
21438
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
21439
+ const [zoomOpen, setZoomOpen] = React.useState(false);
21440
+ // Limit images if maxImages is specified
21441
+ const displayImages = maxImages ? images.slice(0, maxImages) : images;
21442
+ const handlePrevious = React.useCallback(() => {
21443
+ setSelectedIndex(prev => prev === 0 ? displayImages.length - 1 : prev - 1);
21444
+ }, [displayImages.length]);
21445
+ const handleNext = React.useCallback(() => {
21446
+ setSelectedIndex(prev => prev === displayImages.length - 1 ? 0 : prev + 1);
21447
+ }, [displayImages.length]);
21448
+ const handleThumbnailClick = React.useCallback(index => {
21449
+ setSelectedIndex(index);
21450
+ }, []);
21451
+ const handleZoomOpen = React.useCallback(() => {
21452
+ if (showZoom) {
21453
+ setZoomOpen(true);
21454
+ }
21455
+ }, [showZoom]);
21456
+ const handleZoomClose = React.useCallback(() => {
21457
+ setZoomOpen(false);
21458
+ }, []);
21459
+ // Handle empty images
21460
+ if (!displayImages || displayImages.length === 0) {
21461
+ return jsxRuntime.jsx(material.Box, {
21462
+ ...restProps,
21463
+ sx: {
21464
+ backgroundColor: 'var(--theme-surface-variant)',
21465
+ borderRadius: 'var(--theme-border-radius)',
21466
+ display: 'flex',
21467
+ alignItems: 'center',
21468
+ justifyContent: 'center',
21469
+ aspectRatio,
21470
+ minHeight: 400
21471
+ },
21472
+ children: jsxRuntime.jsx(material.Skeleton, {
21473
+ variant: "rectangular",
21474
+ width: "100%",
21475
+ height: "100%",
21476
+ sx: {
21477
+ borderRadius: 'var(--theme-border-radius)'
21478
+ }
21479
+ })
21480
+ });
21481
+ }
21482
+ const currentImage = displayImages[selectedIndex];
21483
+ // Render thumbnails
21484
+ const renderThumbnails = () => jsxRuntime.jsx(material.Box, {
21485
+ sx: {
21486
+ display: 'flex',
21487
+ flexDirection: thumbnailPosition === 'left' || thumbnailPosition === 'right' ? 'column' : 'row',
21488
+ gap: 1,
21489
+ overflow: 'auto',
21490
+ maxHeight: thumbnailPosition === 'left' || thumbnailPosition === 'right' ? 500 : 'auto',
21491
+ maxWidth: thumbnailPosition === 'bottom' ? '100%' : 'auto'
21492
+ },
21493
+ children: displayImages.map((image, index) => jsxRuntime.jsx(material.Box, {
21494
+ onClick: () => handleThumbnailClick(index),
21495
+ sx: {
21496
+ width: 80,
21497
+ height: 80,
21498
+ flexShrink: 0,
21499
+ cursor: 'pointer',
21500
+ border: '2px solid',
21501
+ borderColor: index === selectedIndex ? 'var(--theme-primary)' : 'var(--theme-border-main)',
21502
+ borderRadius: 'var(--theme-border-radius-small)',
21503
+ overflow: 'hidden',
21504
+ transition: 'all 0.2s ease-in-out',
21505
+ '&:hover': {
21506
+ borderColor: 'var(--theme-border-emphasis)'
21507
+ }
21508
+ },
21509
+ children: jsxRuntime.jsx("img", {
21510
+ src: image.thumbnail || image.url,
21511
+ alt: `${productName} thumbnail ${index + 1}`,
21512
+ style: {
21513
+ width: '100%',
21514
+ height: '100%',
21515
+ objectFit: 'cover'
21516
+ }
21517
+ })
21518
+ }, index))
21519
+ });
21520
+ // Render main image container
21521
+ const renderMainImage = () => jsxRuntime.jsxs(material.Box, {
21522
+ sx: {
21523
+ position: 'relative',
21524
+ width: '100%',
21525
+ backgroundColor: 'var(--theme-surface)',
21526
+ borderRadius: 'var(--theme-border-radius)',
21527
+ border: '1px solid var(--theme-border-main)',
21528
+ overflow: 'hidden',
21529
+ aspectRatio
21530
+ },
21531
+ children: [jsxRuntime.jsx("img", {
21532
+ src: currentImage.url,
21533
+ alt: currentImage.alt || `${productName} - Image ${selectedIndex + 1}`,
21534
+ style: {
21535
+ width: '100%',
21536
+ height: '100%',
21537
+ objectFit: 'contain',
21538
+ display: 'block'
21539
+ }
21540
+ }), showZoom && jsxRuntime.jsx(material.IconButton, {
21541
+ onClick: handleZoomOpen,
21542
+ sx: {
21543
+ position: 'absolute',
21544
+ top: 8,
21545
+ right: 8,
21546
+ backgroundColor: 'var(--theme-surface)',
21547
+ color: 'var(--theme-text-primary)',
21548
+ '&:hover': {
21549
+ backgroundColor: 'var(--theme-surface-variant)'
21550
+ }
21551
+ },
21552
+ "aria-label": "Zoom image",
21553
+ children: jsxRuntime.jsx(ZoomInIcon, {})
21554
+ }), variant === 'carousel' && displayImages.length > 1 && jsxRuntime.jsxs(jsxRuntime.Fragment, {
21555
+ children: [jsxRuntime.jsx(material.IconButton, {
21556
+ onClick: handlePrevious,
21557
+ sx: {
21558
+ position: 'absolute',
21559
+ left: 8,
21560
+ top: '50%',
21561
+ transform: 'translateY(-50%)',
21562
+ backgroundColor: 'var(--theme-surface)',
21563
+ color: 'var(--theme-text-primary)',
21564
+ '&:hover': {
21565
+ backgroundColor: 'var(--theme-surface-variant)'
21566
+ }
21567
+ },
21568
+ "aria-label": "Previous image",
21569
+ children: jsxRuntime.jsx(ChevronLeftIcon, {})
21570
+ }), jsxRuntime.jsx(material.IconButton, {
21571
+ onClick: handleNext,
21572
+ sx: {
21573
+ position: 'absolute',
21574
+ right: 8,
21575
+ top: '50%',
21576
+ transform: 'translateY(-50%)',
21577
+ backgroundColor: 'var(--theme-surface)',
21578
+ color: 'var(--theme-text-primary)',
21579
+ '&:hover': {
21580
+ backgroundColor: 'var(--theme-surface-variant)'
21581
+ }
21582
+ },
21583
+ "aria-label": "Next image",
21584
+ children: jsxRuntime.jsx(ChevronRightIcon, {})
21585
+ })]
21586
+ })]
21587
+ });
21588
+ // Render zoom modal
21589
+ const renderZoomModal = () => jsxRuntime.jsx(material.Modal, {
21590
+ open: zoomOpen,
21591
+ onClose: handleZoomClose,
21592
+ sx: {
21593
+ display: 'flex',
21594
+ alignItems: 'center',
21595
+ justifyContent: 'center',
21596
+ backgroundColor: 'rgba(0, 0, 0, 0.9)'
21597
+ },
21598
+ children: jsxRuntime.jsxs(material.Box, {
21599
+ sx: {
21600
+ position: 'relative',
21601
+ maxWidth: '90vw',
21602
+ maxHeight: '90vh',
21603
+ outline: 'none'
21604
+ },
21605
+ children: [jsxRuntime.jsx(material.IconButton, {
21606
+ onClick: handleZoomClose,
21607
+ sx: {
21608
+ position: 'absolute',
21609
+ top: -40,
21610
+ right: 0,
21611
+ color: 'white',
21612
+ '&:hover': {
21613
+ backgroundColor: 'rgba(255, 255, 255, 0.1)'
21614
+ }
21615
+ },
21616
+ "aria-label": "Close zoom",
21617
+ children: jsxRuntime.jsx(Close, {})
21618
+ }), jsxRuntime.jsx("img", {
21619
+ src: currentImage.url,
21620
+ alt: currentImage.alt || `${productName} - Zoomed view`,
21621
+ style: {
21622
+ maxWidth: '100%',
21623
+ maxHeight: '90vh',
21624
+ objectFit: 'contain'
21625
+ }
21626
+ })]
21627
+ })
21628
+ });
21629
+ // Render thumbnails variant
21630
+ if (variant === 'thumbnails') {
21631
+ return jsxRuntime.jsxs(material.Box, {
21632
+ ...restProps,
21633
+ children: [jsxRuntime.jsxs(material.Box, {
21634
+ sx: {
21635
+ display: 'flex',
21636
+ flexDirection: {
21637
+ xs: 'column',
21638
+ sm: thumbnailPosition === 'bottom' ? 'column' : 'row'
21639
+ },
21640
+ gap: 2
21641
+ },
21642
+ children: [thumbnailPosition === 'left' && jsxRuntime.jsx(material.Box, {
21643
+ sx: {
21644
+ order: {
21645
+ xs: 2,
21646
+ sm: 1
21647
+ }
21648
+ },
21649
+ children: renderThumbnails()
21650
+ }), jsxRuntime.jsx(material.Box, {
21651
+ sx: {
21652
+ flex: 1,
21653
+ order: {
21654
+ xs: 1,
21655
+ sm: thumbnailPosition === 'left' ? 2 : 1
21656
+ }
21657
+ },
21658
+ children: renderMainImage()
21659
+ }), thumbnailPosition === 'right' && jsxRuntime.jsx(material.Box, {
21660
+ sx: {
21661
+ order: {
21662
+ xs: 2,
21663
+ sm: 2
21664
+ }
21665
+ },
21666
+ children: renderThumbnails()
21667
+ }), thumbnailPosition === 'bottom' && jsxRuntime.jsx(material.Box, {
21668
+ sx: {
21669
+ order: 2
21670
+ },
21671
+ children: renderThumbnails()
21672
+ })]
21673
+ }), renderZoomModal()]
21674
+ });
21675
+ }
21676
+ // Render carousel variant
21677
+ if (variant === 'carousel') {
21678
+ return jsxRuntime.jsxs(material.Box, {
21679
+ ...restProps,
21680
+ children: [renderMainImage(), displayImages.length > 1 && jsxRuntime.jsx(material.Box, {
21681
+ sx: {
21682
+ display: 'flex',
21683
+ justifyContent: 'center',
21684
+ gap: 1,
21685
+ mt: 2
21686
+ },
21687
+ children: displayImages.map((_, index) => jsxRuntime.jsx(material.Box, {
21688
+ onClick: () => handleThumbnailClick(index),
21689
+ sx: {
21690
+ width: 10,
21691
+ height: 10,
21692
+ borderRadius: '50%',
21693
+ backgroundColor: index === selectedIndex ? 'var(--theme-primary)' : 'var(--theme-border-main)',
21694
+ cursor: 'pointer',
21695
+ transition: 'all 0.2s ease-in-out',
21696
+ '&:hover': {
21697
+ backgroundColor: index === selectedIndex ? 'var(--theme-primary)' : 'var(--theme-border-emphasis)'
21698
+ }
21699
+ }
21700
+ }, index))
21701
+ }), renderZoomModal()]
21702
+ });
21703
+ }
21704
+ // Render grid variant
21705
+ if (variant === 'grid') {
21706
+ return jsxRuntime.jsxs(material.Box, {
21707
+ ...restProps,
21708
+ children: [jsxRuntime.jsx(material.Grid, {
21709
+ container: true,
21710
+ spacing: 2,
21711
+ children: displayImages.map((image, index) => jsxRuntime.jsx(material.Grid, {
21712
+ item: true,
21713
+ xs: 6,
21714
+ sm: 4,
21715
+ md: 3,
21716
+ children: jsxRuntime.jsx(material.Box, {
21717
+ onClick: () => {
21718
+ setSelectedIndex(index);
21719
+ handleZoomOpen();
21720
+ },
21721
+ sx: {
21722
+ width: '100%',
21723
+ aspectRatio: '1',
21724
+ borderRadius: 'var(--theme-border-radius)',
21725
+ border: '1px solid var(--theme-border-main)',
21726
+ overflow: 'hidden',
21727
+ cursor: showZoom ? 'pointer' : 'default',
21728
+ transition: 'all 0.2s ease-in-out',
21729
+ '&:hover': {
21730
+ borderColor: 'var(--theme-border-emphasis)',
21731
+ boxShadow: 'var(--theme-elevation-1)'
21732
+ }
21733
+ },
21734
+ children: jsxRuntime.jsx("img", {
21735
+ src: image.url,
21736
+ alt: image.alt || `${productName} - Image ${index + 1}`,
21737
+ style: {
21738
+ width: '100%',
21739
+ height: '100%',
21740
+ objectFit: 'cover'
21741
+ }
21742
+ })
21743
+ })
21744
+ }, index))
21745
+ }), renderZoomModal()]
21746
+ });
21747
+ }
21748
+ return null;
21749
+ }
21750
+ // Create the serializable ImageGallery component using the factory
21751
+ const ImageGallery = createSerializableView({
21752
+ tagName: 'ImageGallery',
21753
+ version: '1.0.0',
21754
+ role: 'view',
21755
+ View: ImageGalleryView
21756
+ });
21757
+
21758
+ // View component
21759
+ function OptionSelectorView({
21760
+ options = [],
21761
+ selectedOption,
21762
+ onOptionSelect,
21763
+ displayMode = 'text',
21764
+ variant = 'grid',
21765
+ layout = 'wrap',
21766
+ visualSize = 'medium',
21767
+ showLabel = false,
21768
+ disabled = false,
21769
+ label = 'Select Option',
21770
+ dataSource,
21771
+ bindingOptions,
21772
+ ...restProps
21773
+ }) {
21774
+ const handleOptionClick = React.useCallback((optionId, available) => {
21775
+ if (!disabled && available && onOptionSelect) {
21776
+ onOptionSelect(optionId);
21777
+ }
21778
+ }, [disabled, onOptionSelect]);
21779
+ const handleDropdownChange = React.useCallback(event => {
21780
+ if (onOptionSelect) {
21781
+ onOptionSelect(event.target.value);
21782
+ }
21783
+ }, [onOptionSelect]);
21784
+ // Get visual size in pixels
21785
+ const getSizePixels = () => {
21786
+ if (displayMode === 'text') return 48;
21787
+ switch (visualSize) {
21788
+ case 'small':
21789
+ return 32;
21790
+ case 'large':
21791
+ return 56;
21792
+ case 'medium':
21793
+ default:
21794
+ return 44;
21795
+ }
21796
+ };
21797
+ const sizeInPx = getSizePixels();
21798
+ // Render nothing if no options
21799
+ if (!options || options.length === 0) {
21800
+ return null;
21801
+ }
21802
+ // Dropdown variant
21803
+ if (variant === 'dropdown') {
21804
+ return jsxRuntime.jsxs(material.FormControl, {
21805
+ fullWidth: true,
21806
+ disabled: disabled,
21807
+ ...restProps,
21808
+ sx: {
21809
+ '& .MuiOutlinedInput-root': {
21810
+ '& fieldset': {
21811
+ borderColor: 'var(--theme-border-main)'
21812
+ },
21813
+ '&:hover fieldset': {
21814
+ borderColor: 'var(--theme-border-emphasis)'
21815
+ },
21816
+ '&.Mui-focused fieldset': {
21817
+ borderColor: 'var(--theme-primary)'
21818
+ }
21819
+ },
21820
+ '& .MuiInputLabel-root': {
21821
+ color: 'var(--theme-text-secondary)',
21822
+ '&.Mui-focused': {
21823
+ color: 'var(--theme-primary)'
21824
+ }
21825
+ }
21826
+ },
21827
+ children: [jsxRuntime.jsx(material.InputLabel, {
21828
+ children: label
21829
+ }), jsxRuntime.jsx(material.Select, {
21830
+ value: selectedOption || '',
21831
+ onChange: handleDropdownChange,
21832
+ label: label,
21833
+ sx: {
21834
+ backgroundColor: 'var(--theme-surface)',
21835
+ color: 'var(--theme-text-primary)'
21836
+ },
21837
+ children: options.map(option => jsxRuntime.jsxs(material.MenuItem, {
21838
+ value: option.id,
21839
+ disabled: !option.available,
21840
+ sx: {
21841
+ color: option.available ? 'var(--theme-text-primary)' : 'var(--theme-text-disabled)'
21842
+ },
21843
+ children: [displayMode === 'color' && option.hexValue && jsxRuntime.jsx(material.Box, {
21844
+ sx: {
21845
+ width: 20,
21846
+ height: 20,
21847
+ mr: 1,
21848
+ borderRadius: '50%',
21849
+ backgroundColor: option.hexValue,
21850
+ border: '1px solid var(--theme-border-main)',
21851
+ backgroundImage: option.imageUrl ? `url(${option.imageUrl})` : undefined,
21852
+ backgroundSize: 'cover'
21853
+ }
21854
+ }), option.label, !option.available && ' (Out of stock)', option.price && option.price !== 0 && ` (+$${(option.price / 100).toFixed(2)})`]
21855
+ }, option.id))
21856
+ })]
21392
21857
  });
21393
21858
  }
21394
- if (error) {
21395
- console.error('Error loading product card:', error);
21396
- {
21397
- return jsxRuntime.jsx(ProductCardView, {
21398
- ...restProps,
21399
- product: {
21400
- id: 'error-product',
21401
- name: 'Product Loading Error',
21402
- category: 'Error',
21403
- description: error.message,
21404
- features: ['Unable to load product features'],
21405
- technologies: ['N/A'],
21406
- status: 'coming-soon'
21407
- },
21408
- variant: restProps.variant || 'compact',
21409
- showImage: false
21410
- });
21859
+ // Buttons/Grid variant with visual modes
21860
+ const getLayoutStyles = () => {
21861
+ if (variant === 'grid') {
21862
+ const minWidth = displayMode === 'text' ? 60 : sizeInPx + 16;
21863
+ return {
21864
+ display: 'grid',
21865
+ gridTemplateColumns: `repeat(auto-fill, minmax(${minWidth}px, 1fr))`,
21866
+ gap: displayMode === 'text' ? 1 : 2
21867
+ };
21411
21868
  }
21412
- }
21413
- // Pass through data directly - let component handle missing properties
21414
- const transformedProps = productProps;
21415
- return jsxRuntime.jsx(ProductCardView, {
21416
- ...transformedProps
21869
+ return {
21870
+ display: 'flex',
21871
+ flexDirection: layout === 'vertical' ? 'column' : 'row',
21872
+ flexWrap: layout === 'wrap' ? 'wrap' : 'nowrap',
21873
+ gap: 1
21874
+ };
21875
+ };
21876
+ return jsxRuntime.jsxs(material.Box, {
21877
+ ...restProps,
21878
+ children: [label && jsxRuntime.jsx(material.Box, {
21879
+ component: "label",
21880
+ sx: {
21881
+ display: 'block',
21882
+ mb: 1,
21883
+ fontSize: '0.875rem',
21884
+ fontWeight: 500,
21885
+ color: 'var(--theme-text-primary)'
21886
+ },
21887
+ children: label
21888
+ }), jsxRuntime.jsx(material.Box, {
21889
+ sx: getLayoutStyles(),
21890
+ children: options.map(option => {
21891
+ const isSelected = selectedOption === option.id;
21892
+ const isAvailable = option.available;
21893
+ // Text mode - render as buttons
21894
+ if (displayMode === 'text') {
21895
+ const button = jsxRuntime.jsx(material.Button, {
21896
+ onClick: () => handleOptionClick(option.id, isAvailable),
21897
+ disabled: disabled || !isAvailable,
21898
+ variant: isSelected ? 'contained' : 'outlined',
21899
+ sx: {
21900
+ minWidth: variant === 'grid' ? '60px' : '80px',
21901
+ height: `${sizeInPx}px`,
21902
+ borderRadius: 'var(--theme-border-radius-small)',
21903
+ textTransform: 'uppercase',
21904
+ fontWeight: 600,
21905
+ fontSize: '0.875rem',
21906
+ backgroundColor: isSelected ? 'var(--theme-primary)' : 'var(--theme-surface)',
21907
+ color: isSelected ? 'var(--theme-text-on-primary)' : 'var(--theme-text-primary)',
21908
+ borderColor: isSelected ? 'var(--theme-primary)' : 'var(--theme-border-main)',
21909
+ borderWidth: '2px',
21910
+ borderStyle: 'solid',
21911
+ '&.Mui-disabled': {
21912
+ backgroundColor: 'var(--theme-surface-variant)',
21913
+ color: 'var(--theme-text-disabled)',
21914
+ borderColor: 'var(--theme-border-light)',
21915
+ opacity: 0.5,
21916
+ textDecoration: 'line-through'
21917
+ },
21918
+ '&:hover:not(.Mui-disabled)': {
21919
+ backgroundColor: !isSelected ? 'var(--theme-surface-variant)' : undefined,
21920
+ borderColor: !isSelected ? 'var(--theme-border-emphasis)' : undefined,
21921
+ boxShadow: 'var(--theme-elevation-1)'
21922
+ },
21923
+ transition: 'all 0.2s ease-in-out'
21924
+ },
21925
+ children: option.label
21926
+ }, option.id);
21927
+ return !isAvailable ? jsxRuntime.jsx(material.Tooltip, {
21928
+ title: "Not available",
21929
+ arrow: true,
21930
+ sx: {
21931
+ '& .MuiTooltip-tooltip': {
21932
+ backgroundColor: 'var(--theme-surface)',
21933
+ color: 'var(--theme-text-primary)',
21934
+ border: '1px solid var(--theme-border-main)',
21935
+ boxShadow: 'var(--theme-elevation-2)'
21936
+ },
21937
+ '& .MuiTooltip-arrow': {
21938
+ color: 'var(--theme-surface)'
21939
+ }
21940
+ },
21941
+ children: jsxRuntime.jsx("span", {
21942
+ children: button
21943
+ })
21944
+ }, option.id) : button;
21945
+ }
21946
+ // Color/Image mode - render as visual swatches
21947
+ const swatchContent = jsxRuntime.jsxs(material.Box, {
21948
+ onClick: () => handleOptionClick(option.id, isAvailable),
21949
+ sx: {
21950
+ display: 'flex',
21951
+ flexDirection: 'column',
21952
+ alignItems: 'center',
21953
+ gap: 0.5,
21954
+ cursor: disabled || !isAvailable ? 'not-allowed' : 'pointer',
21955
+ opacity: disabled || !isAvailable ? 0.5 : 1
21956
+ },
21957
+ children: [jsxRuntime.jsx(material.Box, {
21958
+ sx: {
21959
+ position: 'relative',
21960
+ width: sizeInPx,
21961
+ height: sizeInPx,
21962
+ borderRadius: displayMode === 'color' ? '50%' : 'var(--theme-border-radius-small)',
21963
+ backgroundColor: option.hexValue || 'var(--theme-surface-variant)',
21964
+ backgroundImage: option.imageUrl ? `url(${option.imageUrl})` : undefined,
21965
+ backgroundSize: 'cover',
21966
+ backgroundPosition: 'center',
21967
+ border: '2px solid',
21968
+ borderColor: isSelected ? 'var(--theme-primary)' : 'var(--theme-border-main)',
21969
+ boxShadow: isSelected ? 'var(--theme-elevation-2)' : 'none',
21970
+ transition: 'all 0.2s ease-in-out',
21971
+ ...(isAvailable && !disabled && !isSelected && {
21972
+ '&:hover': {
21973
+ borderColor: 'var(--theme-border-emphasis)',
21974
+ boxShadow: 'var(--theme-elevation-1)',
21975
+ transform: 'scale(1.05)'
21976
+ }
21977
+ }),
21978
+ ...(!isAvailable && {
21979
+ '&::after': {
21980
+ content: '""',
21981
+ position: 'absolute',
21982
+ top: '50%',
21983
+ left: '10%',
21984
+ right: '10%',
21985
+ height: '2px',
21986
+ backgroundColor: 'var(--theme-border-emphasis)',
21987
+ transform: 'translateY(-50%) rotate(-45deg)'
21988
+ }
21989
+ })
21990
+ },
21991
+ children: isSelected && jsxRuntime.jsx(material.Box, {
21992
+ sx: {
21993
+ position: 'absolute',
21994
+ top: '50%',
21995
+ left: '50%',
21996
+ transform: 'translate(-50%, -50%)',
21997
+ display: 'flex',
21998
+ alignItems: 'center',
21999
+ justifyContent: 'center',
22000
+ width: '100%',
22001
+ height: '100%',
22002
+ borderRadius: 'inherit',
22003
+ backgroundColor: 'rgba(0, 0, 0, 0.3)'
22004
+ },
22005
+ children: jsxRuntime.jsx(Check, {
22006
+ sx: {
22007
+ color: 'white',
22008
+ fontSize: sizeInPx * 0.5,
22009
+ filter: 'drop-shadow(0 1px 2px rgba(0,0,0,0.5))'
22010
+ }
22011
+ })
22012
+ })
22013
+ }), showLabel && jsxRuntime.jsx(material.Box, {
22014
+ sx: {
22015
+ fontSize: '0.75rem',
22016
+ color: 'var(--theme-text-secondary)',
22017
+ textAlign: 'center',
22018
+ maxWidth: sizeInPx + 16,
22019
+ overflow: 'hidden',
22020
+ textOverflow: 'ellipsis',
22021
+ whiteSpace: 'nowrap'
22022
+ },
22023
+ children: option.label
22024
+ })]
22025
+ }, option.id);
22026
+ return jsxRuntime.jsx(material.Tooltip, {
22027
+ title: !isAvailable ? 'Not available' : option.label,
22028
+ arrow: true,
22029
+ sx: {
22030
+ '& .MuiTooltip-tooltip': {
22031
+ backgroundColor: 'var(--theme-surface)',
22032
+ color: 'var(--theme-text-primary)',
22033
+ border: '1px solid var(--theme-border-main)',
22034
+ boxShadow: 'var(--theme-elevation-2)'
22035
+ },
22036
+ '& .MuiTooltip-arrow': {
22037
+ color: 'var(--theme-surface)'
22038
+ }
22039
+ },
22040
+ children: swatchContent
22041
+ }, option.id);
22042
+ })
22043
+ })]
21417
22044
  });
21418
22045
  }
22046
+ // Create the serializable component
22047
+ const OptionSelector = createSerializableView({
22048
+ tagName: 'OptionSelector',
22049
+ version: '1.0.0',
22050
+ role: 'view',
22051
+ View: OptionSelectorView
22052
+ });
21419
22053
 
21420
22054
  // Default render function based on component type
21421
22055
  const getDefaultRenderItem = (renderComponent = 'ProductCard', itemProps = {}) => {
@@ -31436,6 +32070,299 @@ __decorate([schema.Field({
31436
32070
  }), classValidator.IsOptional(), classValidator.IsNumber(), classValidator.Min(1), classValidator.Max(10), __metadata("design:type", Number)], exports.ProductCardModel.prototype, "maxFeaturesCompact", void 0);
31437
32071
  exports.ProductCardModel = __decorate([schema.Schema('ProductCard', '1.0.0')], exports.ProductCardModel);
31438
32072
 
32073
+ /**
32074
+ * Schema for ImageGallery component - Image gallery with multiple view variants
32075
+ *
32076
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
32077
+ */
32078
+ // Product image interface
32079
+ class GalleryImageModel {}
32080
+ __decorate([schema.Field({
32081
+ dataType: schema.DataType.STRING
32082
+ }), classValidator.IsString(), __metadata("design:type", String)], GalleryImageModel.prototype, "url", void 0);
32083
+ __decorate([schema.Field({
32084
+ dataType: schema.DataType.STRING
32085
+ }), classValidator.IsString(), __metadata("design:type", String)], GalleryImageModel.prototype, "alt", void 0);
32086
+ __decorate([schema.Field({
32087
+ dataType: schema.DataType.STRING
32088
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], GalleryImageModel.prototype, "thumbnail", void 0);
32089
+ exports.ImageGalleryModel = class ImageGalleryModel extends exports.ViewSchema {};
32090
+ __decorate([schema.Field({
32091
+ dataType: schema.DataType.ARRAY
32092
+ }), schema.Editor({
32093
+ field_type: schema.FieldType.ARRAY,
32094
+ label: 'Product Images',
32095
+ description: 'Array of product images to display in the gallery'
32096
+ }), classValidator.IsArray(), classValidator.ValidateNested({
32097
+ each: true
32098
+ }), classTransformer.Type(() => GalleryImageModel), __metadata("design:type", Array)], exports.ImageGalleryModel.prototype, "images", void 0);
32099
+ __decorate([schema.Field({
32100
+ dataType: schema.DataType.STRING
32101
+ }), schema.Editor({
32102
+ field_type: schema.FieldType.TEXT,
32103
+ label: 'Product Name',
32104
+ description: 'Product name for accessibility',
32105
+ placeholder: 'Premium Cotton T-Shirt'
32106
+ }), classValidator.IsString(), __metadata("design:type", String)], exports.ImageGalleryModel.prototype, "productName", void 0);
32107
+ __decorate([schema.Field({
32108
+ defaultValue: 'thumbnails',
32109
+ dataType: schema.DataType.STRING
32110
+ }), schema.Editor({
32111
+ field_type: schema.FieldType.SELECT,
32112
+ label: 'Gallery Variant',
32113
+ description: 'Display variant for the gallery',
32114
+ validation: {
32115
+ options: [{
32116
+ label: 'Thumbnails',
32117
+ value: 'thumbnails'
32118
+ }, {
32119
+ label: 'Carousel',
32120
+ value: 'carousel'
32121
+ }, {
32122
+ label: 'Grid',
32123
+ value: 'grid'
32124
+ }]
32125
+ }
32126
+ }), classValidator.IsOptional(), classValidator.IsString(), classValidator.IsIn(['thumbnails', 'carousel', 'grid']), __metadata("design:type", String)], exports.ImageGalleryModel.prototype, "variant", void 0);
32127
+ __decorate([schema.Field({
32128
+ defaultValue: 'left',
32129
+ dataType: schema.DataType.STRING
32130
+ }), schema.Editor({
32131
+ field_type: schema.FieldType.SELECT,
32132
+ label: 'Thumbnail Position',
32133
+ description: 'Position of thumbnails (only for thumbnails variant)',
32134
+ validation: {
32135
+ options: [{
32136
+ label: 'Left',
32137
+ value: 'left'
32138
+ }, {
32139
+ label: 'Bottom',
32140
+ value: 'bottom'
32141
+ }, {
32142
+ label: 'Right',
32143
+ value: 'right'
32144
+ }]
32145
+ }
32146
+ }), classValidator.IsOptional(), classValidator.IsString(), classValidator.IsIn(['left', 'bottom', 'right']), __metadata("design:type", String)], exports.ImageGalleryModel.prototype, "thumbnailPosition", void 0);
32147
+ __decorate([schema.Field({
32148
+ defaultValue: '1',
32149
+ dataType: schema.DataType.STRING
32150
+ }), schema.Editor({
32151
+ field_type: schema.FieldType.TEXT,
32152
+ label: 'Aspect Ratio',
32153
+ description: 'Aspect ratio for main image (e.g., "1", "4/3", "16/9")',
32154
+ placeholder: '1'
32155
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], exports.ImageGalleryModel.prototype, "aspectRatio", void 0);
32156
+ __decorate([schema.Field({
32157
+ defaultValue: true,
32158
+ dataType: schema.DataType.BOOLEAN
32159
+ }), schema.Editor({
32160
+ field_type: schema.FieldType.BOOLEAN,
32161
+ label: 'Show Zoom',
32162
+ description: 'Enable zoom functionality for images'
32163
+ }), classValidator.IsOptional(), classValidator.IsBoolean(), __metadata("design:type", Boolean)], exports.ImageGalleryModel.prototype, "showZoom", void 0);
32164
+ __decorate([schema.Field({
32165
+ dataType: schema.DataType.NUMBER
32166
+ }), schema.Editor({
32167
+ field_type: schema.FieldType.NUMBER,
32168
+ label: 'Max Images',
32169
+ description: 'Maximum number of images to display (leave empty for all)',
32170
+ placeholder: '8'
32171
+ }), classValidator.IsOptional(), classValidator.IsNumber(), __metadata("design:type", Number)], exports.ImageGalleryModel.prototype, "maxImages", void 0);
32172
+ __decorate([schema.Field({
32173
+ dataType: schema.DataType.STRING
32174
+ }), schema.Editor({
32175
+ field_type: schema.FieldType.TEXT,
32176
+ label: 'Data Source',
32177
+ description: 'Data source for dynamic image loading',
32178
+ placeholder: 'product-images'
32179
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], exports.ImageGalleryModel.prototype, "dataSource", void 0);
32180
+ __decorate([schema.Field({
32181
+ dataType: schema.DataType.OBJECT
32182
+ }), schema.Editor({
32183
+ field_type: schema.FieldType.TEXTAREA,
32184
+ label: 'Binding Options',
32185
+ description: 'Data binding configuration (JSON format)',
32186
+ placeholder: '{ "filter": {}, "sort": {} }'
32187
+ }), classValidator.IsOptional(), __metadata("design:type", Object)], exports.ImageGalleryModel.prototype, "bindingOptions", void 0);
32188
+ exports.ImageGalleryModel = __decorate([schema.Schema('ImageGallery', '1.0.0')], exports.ImageGalleryModel);
32189
+
32190
+ /**
32191
+ * Schema for OptionSelector component - Universal option selection with visual modes
32192
+ *
32193
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
32194
+ */
32195
+ // Select option model
32196
+ class SelectOptionModel {}
32197
+ __decorate([schema.Field({
32198
+ dataType: schema.DataType.STRING
32199
+ }), classValidator.IsString(), __metadata("design:type", String)], SelectOptionModel.prototype, "id", void 0);
32200
+ __decorate([schema.Field({
32201
+ dataType: schema.DataType.STRING
32202
+ }), classValidator.IsString(), __metadata("design:type", String)], SelectOptionModel.prototype, "label", void 0);
32203
+ __decorate([schema.Field({
32204
+ dataType: schema.DataType.BOOLEAN
32205
+ }), classValidator.IsBoolean(), __metadata("design:type", Boolean)], SelectOptionModel.prototype, "available", void 0);
32206
+ __decorate([schema.Field({
32207
+ dataType: schema.DataType.NUMBER
32208
+ }), classValidator.IsOptional(), classValidator.IsNumber(), __metadata("design:type", Number)], SelectOptionModel.prototype, "price", void 0);
32209
+ __decorate([schema.Field({
32210
+ dataType: schema.DataType.STRING
32211
+ }), schema.Editor({
32212
+ field_type: schema.FieldType.TEXT,
32213
+ label: 'Hex Color Value',
32214
+ description: 'Hex color code for color swatches (e.g., #FF0000)',
32215
+ placeholder: '#FF0000'
32216
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], SelectOptionModel.prototype, "hexValue", void 0);
32217
+ __decorate([schema.Field({
32218
+ dataType: schema.DataType.STRING
32219
+ }), schema.Editor({
32220
+ field_type: schema.FieldType.TEXT,
32221
+ label: 'Image URL',
32222
+ description: 'Image URL for image/pattern display mode',
32223
+ placeholder: '/patterns/stripes.jpg'
32224
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], SelectOptionModel.prototype, "imageUrl", void 0);
32225
+ exports.OptionSelectorModel = class OptionSelectorModel extends exports.ViewSchema {};
32226
+ __decorate([schema.Field({
32227
+ dataType: schema.DataType.ARRAY
32228
+ }), schema.Editor({
32229
+ field_type: schema.FieldType.ARRAY,
32230
+ label: 'Available Options',
32231
+ description: 'Array of options to display'
32232
+ }), classValidator.IsArray(), classValidator.ValidateNested({
32233
+ each: true
32234
+ }), classTransformer.Type(() => SelectOptionModel), __metadata("design:type", Array)], exports.OptionSelectorModel.prototype, "options", void 0);
32235
+ __decorate([schema.Field({
32236
+ dataType: schema.DataType.STRING
32237
+ }), schema.Editor({
32238
+ field_type: schema.FieldType.TEXT,
32239
+ label: 'Selected Option',
32240
+ description: 'Currently selected option ID',
32241
+ placeholder: 'm'
32242
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "selectedOption", void 0);
32243
+ __decorate([schema.Field({
32244
+ defaultValue: 'text',
32245
+ dataType: schema.DataType.STRING
32246
+ }), schema.Editor({
32247
+ field_type: schema.FieldType.SELECT,
32248
+ label: 'Display Mode',
32249
+ description: 'Visual display mode for options',
32250
+ validation: {
32251
+ options: [{
32252
+ label: 'Text (buttons with labels)',
32253
+ value: 'text'
32254
+ }, {
32255
+ label: 'Color (swatches)',
32256
+ value: 'color'
32257
+ }, {
32258
+ label: 'Image (patterns/textures)',
32259
+ value: 'image'
32260
+ }]
32261
+ }
32262
+ }), classValidator.IsOptional(), classValidator.IsString(), classValidator.IsIn(['text', 'color', 'image']), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "displayMode", void 0);
32263
+ __decorate([schema.Field({
32264
+ defaultValue: 'grid',
32265
+ dataType: schema.DataType.STRING
32266
+ }), schema.Editor({
32267
+ field_type: schema.FieldType.SELECT,
32268
+ label: 'Display Variant',
32269
+ description: 'How to display the selector',
32270
+ validation: {
32271
+ options: [{
32272
+ label: 'Buttons',
32273
+ value: 'buttons'
32274
+ }, {
32275
+ label: 'Dropdown',
32276
+ value: 'dropdown'
32277
+ }, {
32278
+ label: 'Grid',
32279
+ value: 'grid'
32280
+ }]
32281
+ }
32282
+ }), classValidator.IsOptional(), classValidator.IsString(), classValidator.IsIn(['buttons', 'dropdown', 'grid']), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "variant", void 0);
32283
+ __decorate([schema.Field({
32284
+ defaultValue: 'wrap',
32285
+ dataType: schema.DataType.STRING
32286
+ }), schema.Editor({
32287
+ field_type: schema.FieldType.SELECT,
32288
+ label: 'Layout Direction',
32289
+ description: 'Layout direction for buttons/grid variant',
32290
+ validation: {
32291
+ options: [{
32292
+ label: 'Horizontal',
32293
+ value: 'horizontal'
32294
+ }, {
32295
+ label: 'Vertical',
32296
+ value: 'vertical'
32297
+ }, {
32298
+ label: 'Wrap',
32299
+ value: 'wrap'
32300
+ }]
32301
+ }
32302
+ }), classValidator.IsOptional(), classValidator.IsString(), classValidator.IsIn(['horizontal', 'vertical', 'wrap']), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "layout", void 0);
32303
+ __decorate([schema.Field({
32304
+ defaultValue: 'medium',
32305
+ dataType: schema.DataType.STRING
32306
+ }), schema.Editor({
32307
+ field_type: schema.FieldType.SELECT,
32308
+ label: 'Visual Size',
32309
+ description: 'Size for color/image display modes',
32310
+ validation: {
32311
+ options: [{
32312
+ label: 'Small (32px)',
32313
+ value: 'small'
32314
+ }, {
32315
+ label: 'Medium (44px)',
32316
+ value: 'medium'
32317
+ }, {
32318
+ label: 'Large (56px)',
32319
+ value: 'large'
32320
+ }]
32321
+ }
32322
+ }), classValidator.IsOptional(), classValidator.IsString(), classValidator.IsIn(['small', 'medium', 'large']), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "visualSize", void 0);
32323
+ __decorate([schema.Field({
32324
+ defaultValue: false,
32325
+ dataType: schema.DataType.BOOLEAN
32326
+ }), schema.Editor({
32327
+ field_type: schema.FieldType.BOOLEAN,
32328
+ label: 'Show Label',
32329
+ description: 'Show label below visual (for color/image modes)'
32330
+ }), classValidator.IsOptional(), classValidator.IsBoolean(), __metadata("design:type", Boolean)], exports.OptionSelectorModel.prototype, "showLabel", void 0);
32331
+ __decorate([schema.Field({
32332
+ defaultValue: false,
32333
+ dataType: schema.DataType.BOOLEAN
32334
+ }), schema.Editor({
32335
+ field_type: schema.FieldType.BOOLEAN,
32336
+ label: 'Disabled',
32337
+ description: 'Disable all option selections'
32338
+ }), classValidator.IsOptional(), classValidator.IsBoolean(), __metadata("design:type", Boolean)], exports.OptionSelectorModel.prototype, "disabled", void 0);
32339
+ __decorate([schema.Field({
32340
+ defaultValue: 'Select Option',
32341
+ dataType: schema.DataType.STRING
32342
+ }), schema.Editor({
32343
+ field_type: schema.FieldType.TEXT,
32344
+ label: 'Label',
32345
+ description: 'Label text for the selector',
32346
+ placeholder: 'Select Option'
32347
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "label", void 0);
32348
+ __decorate([schema.Field({
32349
+ dataType: schema.DataType.STRING
32350
+ }), schema.Editor({
32351
+ field_type: schema.FieldType.TEXT,
32352
+ label: 'Data Source',
32353
+ description: 'Data source for dynamic option loading',
32354
+ placeholder: 'product-options'
32355
+ }), classValidator.IsOptional(), classValidator.IsString(), __metadata("design:type", String)], exports.OptionSelectorModel.prototype, "dataSource", void 0);
32356
+ __decorate([schema.Field({
32357
+ dataType: schema.DataType.OBJECT
32358
+ }), schema.Editor({
32359
+ field_type: schema.FieldType.TEXTAREA,
32360
+ label: 'Binding Options',
32361
+ description: 'Data binding configuration (JSON format)',
32362
+ placeholder: '{ "filter": {}, "sort": {} }'
32363
+ }), classValidator.IsOptional(), __metadata("design:type", Object)], exports.OptionSelectorModel.prototype, "bindingOptions", void 0);
32364
+ exports.OptionSelectorModel = __decorate([schema.Schema('OptionSelector', '1.0.0')], exports.OptionSelectorModel);
32365
+
31439
32366
  /**
31440
32367
  * Schema for SafeSpan component - Safely renders HTML content with sanitization
31441
32368
  *
@@ -32350,16 +33277,19 @@ exports.FormCheckbox = FormCheckbox;
32350
33277
  exports.FormField = FormField;
32351
33278
  exports.FormPage = FormPage;
32352
33279
  exports.FormSelect = FormSelect;
33280
+ exports.GalleryImageModel = GalleryImageModel;
32353
33281
  exports.GridCell = GridCell;
32354
33282
  exports.GridLayout = GridLayout;
32355
33283
  exports.HeroBlock = HeroBlock;
32356
33284
  exports.Html = Html;
32357
33285
  exports.HtmlInputField = HtmlInputField;
32358
33286
  exports.Image = Image;
33287
+ exports.ImageGallery = ImageGallery;
32359
33288
  exports.Logo = Logo;
32360
33289
  exports.Markdown = Markdown;
32361
33290
  exports.ModelView = ModelView;
32362
33291
  exports.NavigationProvider = NavigationProvider;
33292
+ exports.OptionSelector = OptionSelector;
32363
33293
  exports.Page = Page;
32364
33294
  exports.PageBannerHeader = PageBannerHeader;
32365
33295
  exports.PaletteAutumn = PaletteAutumn;
@@ -32383,6 +33313,7 @@ exports.Scaffold = Scaffold;
32383
33313
  exports.SchemaFormRenderer = SchemaFormRenderer;
32384
33314
  exports.Section = Section;
32385
33315
  exports.SelectInputField = SelectInputField;
33316
+ exports.SelectOptionModel = SelectOptionModel;
32386
33317
  exports.StatCard = StatCard;
32387
33318
  exports.SwitchInputField = SwitchInputField;
32388
33319
  exports.T = T;