@qwickapps/react-framework 1.5.11 → 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 (41) 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.css +1 -1
  9. package/dist/index.esm.css +1 -1
  10. package/dist/index.esm.js +1192 -265
  11. package/dist/index.js +1194 -263
  12. package/dist/palettes/manifest.json +19 -19
  13. package/dist/schemas/ImageGallerySchema.d.ts +27 -0
  14. package/dist/schemas/ImageGallerySchema.d.ts.map +1 -0
  15. package/dist/schemas/OptionSelectorSchema.d.ts +34 -0
  16. package/dist/schemas/OptionSelectorSchema.d.ts.map +1 -0
  17. package/dist/schemas/index.d.ts +2 -0
  18. package/dist/schemas/index.d.ts.map +1 -1
  19. package/package.json +1 -1
  20. package/src/components/QwickApp.css +8 -0
  21. package/src/components/blocks/Article.tsx +1 -1
  22. package/src/components/blocks/ImageGallery.tsx +464 -0
  23. package/src/components/blocks/OptionSelector.tsx +459 -0
  24. package/src/components/blocks/index.ts +4 -0
  25. package/src/schemas/ImageGallerySchema.ts +148 -0
  26. package/src/schemas/OptionSelectorSchema.ts +216 -0
  27. package/src/schemas/index.ts +2 -0
  28. package/src/stories/ImageGallery.stories.tsx +497 -0
  29. package/src/stories/OptionSelector.stories.tsx +506 -0
  30. /package/dist/palettes/{palette-autumn.1.5.11.css → palette-autumn.1.5.13.css} +0 -0
  31. /package/dist/palettes/{palette-autumn.1.5.11.min.css → palette-autumn.1.5.13.min.css} +0 -0
  32. /package/dist/palettes/{palette-cosmic.1.5.11.css → palette-cosmic.1.5.13.css} +0 -0
  33. /package/dist/palettes/{palette-cosmic.1.5.11.min.css → palette-cosmic.1.5.13.min.css} +0 -0
  34. /package/dist/palettes/{palette-default.1.5.11.css → palette-default.1.5.13.css} +0 -0
  35. /package/dist/palettes/{palette-default.1.5.11.min.css → palette-default.1.5.13.min.css} +0 -0
  36. /package/dist/palettes/{palette-ocean.1.5.11.css → palette-ocean.1.5.13.css} +0 -0
  37. /package/dist/palettes/{palette-ocean.1.5.11.min.css → palette-ocean.1.5.13.min.css} +0 -0
  38. /package/dist/palettes/{palette-spring.1.5.11.css → palette-spring.1.5.13.css} +0 -0
  39. /package/dist/palettes/{palette-spring.1.5.11.min.css → palette-spring.1.5.13.min.css} +0 -0
  40. /package/dist/palettes/{palette-winter.1.5.11.css → palette-winter.1.5.13.css} +0 -0
  41. /package/dist/palettes/{palette-winter.1.5.11.min.css → palette-winter.1.5.13.min.css} +0 -0
@@ -0,0 +1,506 @@
1
+ /**
2
+ * Storybook Stories for OptionSelector Component
3
+ *
4
+ * Demonstrates universal option selection with three display modes:
5
+ * - Text: Buttons with labels (sizes, quantities)
6
+ * - Color: Circular color swatches with hex backgrounds
7
+ * - Image: Rounded rectangle image swatches (patterns, textures)
8
+ *
9
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
10
+ */
11
+
12
+ import type { Meta, StoryObj } from '@storybook/react';
13
+ import React from 'react';
14
+ import { Box } from '@mui/material';
15
+ import OptionSelector from '../components/blocks/OptionSelector';
16
+ import { SelectOption } from '../components/blocks/OptionSelector';
17
+
18
+ const meta = {
19
+ title: 'Blocks/OptionSelector',
20
+ component: OptionSelector,
21
+ parameters: {
22
+ layout: 'centered',
23
+ docs: {
24
+ description: {
25
+ component: 'Universal option selector supporting text, color swatches, and image patterns. Used for product variants, color selection, and pattern choices.',
26
+ },
27
+ },
28
+ },
29
+ tags: ['autodocs'],
30
+ argTypes: {
31
+ displayMode: {
32
+ control: 'select',
33
+ options: ['text', 'color', 'image'],
34
+ description: 'Visual display mode for options',
35
+ },
36
+ variant: {
37
+ control: 'select',
38
+ options: ['buttons', 'dropdown', 'grid'],
39
+ description: 'Display variant',
40
+ },
41
+ layout: {
42
+ control: 'select',
43
+ options: ['horizontal', 'vertical', 'wrap'],
44
+ description: 'Layout direction for buttons/grid',
45
+ },
46
+ visualSize: {
47
+ control: 'select',
48
+ options: ['small', 'medium', 'large'],
49
+ description: 'Size for color/image modes',
50
+ },
51
+ showLabel: {
52
+ control: 'boolean',
53
+ description: 'Show label below visual swatches',
54
+ },
55
+ disabled: {
56
+ control: 'boolean',
57
+ description: 'Disable all selections',
58
+ },
59
+ },
60
+ } satisfies Meta<typeof OptionSelector>;
61
+
62
+ export default meta;
63
+ type Story = StoryObj<typeof meta>;
64
+
65
+ // Size options for text mode
66
+ const sizeOptions: SelectOption[] = [
67
+ { id: 'xs', label: 'XS', available: true },
68
+ { id: 's', label: 'S', available: true },
69
+ { id: 'm', label: 'M', available: true },
70
+ { id: 'l', label: 'L', available: true },
71
+ { id: 'xl', label: 'XL', available: true },
72
+ { id: 'xxl', label: 'XXL', available: false },
73
+ ];
74
+
75
+ // Color options for color mode
76
+ const colorOptions: SelectOption[] = [
77
+ { id: 'red', label: 'Red', hexValue: '#FF0000', available: true },
78
+ { id: 'blue', label: 'Blue', hexValue: '#0000FF', available: true },
79
+ { id: 'green', label: 'Green', hexValue: '#00FF00', available: true },
80
+ { id: 'yellow', label: 'Yellow', hexValue: '#FFFF00', available: false },
81
+ { id: 'purple', label: 'Purple', hexValue: '#9C27B0', available: true },
82
+ { id: 'orange', label: 'Orange', hexValue: '#FF9800', available: true },
83
+ { id: 'pink', label: 'Pink', hexValue: '#E91E63', available: true },
84
+ { id: 'teal', label: 'Teal', hexValue: '#009688', available: false },
85
+ ];
86
+
87
+ // Pattern options for image mode (using placeholder images)
88
+ const patternOptions: SelectOption[] = [
89
+ {
90
+ id: 'stripes',
91
+ label: 'Stripes',
92
+ imageUrl: 'https://via.placeholder.com/100/4A90E2/FFFFFF?text=Stripes',
93
+ available: true
94
+ },
95
+ {
96
+ id: 'dots',
97
+ label: 'Polka Dots',
98
+ imageUrl: 'https://via.placeholder.com/100/E24A90/FFFFFF?text=Dots',
99
+ available: true
100
+ },
101
+ {
102
+ id: 'plaid',
103
+ label: 'Plaid',
104
+ imageUrl: 'https://via.placeholder.com/100/90E24A/FFFFFF?text=Plaid',
105
+ available: false
106
+ },
107
+ {
108
+ id: 'floral',
109
+ label: 'Floral',
110
+ imageUrl: 'https://via.placeholder.com/100/E2904A/FFFFFF?text=Floral',
111
+ available: true
112
+ },
113
+ ];
114
+
115
+ // ==================== TEXT MODE STORIES ====================
116
+
117
+ export const TextModeGrid: Story = {
118
+ args: {
119
+ options: sizeOptions,
120
+ selectedOption: 'm',
121
+ displayMode: 'text',
122
+ variant: 'grid',
123
+ label: 'Select Size',
124
+ onOptionSelect: (optionId) => console.log('Selected:', optionId),
125
+ },
126
+ };
127
+
128
+ export const TextModeHorizontal: Story = {
129
+ args: {
130
+ options: sizeOptions,
131
+ selectedOption: 's',
132
+ displayMode: 'text',
133
+ variant: 'buttons',
134
+ layout: 'horizontal',
135
+ label: 'Select Size',
136
+ },
137
+ };
138
+
139
+ export const TextModeDropdown: Story = {
140
+ args: {
141
+ options: sizeOptions,
142
+ selectedOption: 'l',
143
+ displayMode: 'text',
144
+ variant: 'dropdown',
145
+ label: 'Select Size',
146
+ },
147
+ decorators: [
148
+ (Story) => (
149
+ <Box sx={{ width: 300 }}>
150
+ <Story />
151
+ </Box>
152
+ ),
153
+ ],
154
+ };
155
+
156
+ // ==================== COLOR MODE STORIES ====================
157
+
158
+ export const ColorModeGrid: Story = {
159
+ args: {
160
+ options: colorOptions,
161
+ selectedOption: 'blue',
162
+ displayMode: 'color',
163
+ variant: 'grid',
164
+ visualSize: 'medium',
165
+ showLabel: false,
166
+ label: 'Select Color',
167
+ },
168
+ };
169
+
170
+ export const ColorModeWithLabels: Story = {
171
+ args: {
172
+ options: colorOptions,
173
+ selectedOption: 'red',
174
+ displayMode: 'color',
175
+ variant: 'grid',
176
+ visualSize: 'medium',
177
+ showLabel: true,
178
+ label: 'Select Color',
179
+ },
180
+ };
181
+
182
+ export const ColorModeSmall: Story = {
183
+ args: {
184
+ options: colorOptions,
185
+ selectedOption: 'purple',
186
+ displayMode: 'color',
187
+ variant: 'grid',
188
+ visualSize: 'small',
189
+ showLabel: false,
190
+ label: 'Select Color',
191
+ },
192
+ };
193
+
194
+ export const ColorModeLarge: Story = {
195
+ args: {
196
+ options: colorOptions,
197
+ selectedOption: 'orange',
198
+ displayMode: 'color',
199
+ variant: 'grid',
200
+ visualSize: 'large',
201
+ showLabel: true,
202
+ label: 'Select Color',
203
+ },
204
+ };
205
+
206
+ export const ColorModeHorizontal: Story = {
207
+ args: {
208
+ options: colorOptions.slice(0, 4),
209
+ selectedOption: 'green',
210
+ displayMode: 'color',
211
+ variant: 'buttons',
212
+ layout: 'horizontal',
213
+ visualSize: 'medium',
214
+ showLabel: true,
215
+ label: 'Select Color',
216
+ },
217
+ decorators: [
218
+ (Story) => (
219
+ <Box sx={{ width: 600 }}>
220
+ <Story />
221
+ </Box>
222
+ ),
223
+ ],
224
+ };
225
+
226
+ // ==================== IMAGE MODE STORIES ====================
227
+
228
+ export const ImageModeGrid: Story = {
229
+ args: {
230
+ options: patternOptions,
231
+ selectedOption: 'stripes',
232
+ displayMode: 'image',
233
+ variant: 'grid',
234
+ visualSize: 'medium',
235
+ showLabel: false,
236
+ label: 'Select Pattern',
237
+ },
238
+ };
239
+
240
+ export const ImageModeWithLabels: Story = {
241
+ args: {
242
+ options: patternOptions,
243
+ selectedOption: 'floral',
244
+ displayMode: 'image',
245
+ variant: 'grid',
246
+ visualSize: 'large',
247
+ showLabel: true,
248
+ label: 'Select Pattern',
249
+ },
250
+ };
251
+
252
+ export const ImageModeSmall: Story = {
253
+ args: {
254
+ options: patternOptions,
255
+ selectedOption: 'dots',
256
+ displayMode: 'image',
257
+ variant: 'grid',
258
+ visualSize: 'small',
259
+ showLabel: false,
260
+ label: 'Select Pattern',
261
+ },
262
+ };
263
+
264
+ // ==================== SPECIAL USE CASES ====================
265
+
266
+ export const WithPriceAdjustments: Story = {
267
+ args: {
268
+ options: [
269
+ { id: 's', label: 'S', available: true, price: 0 },
270
+ { id: 'm', label: 'M', available: true, price: 0 },
271
+ { id: 'l', label: 'L', available: true, price: 500 },
272
+ { id: 'xl', label: 'XL', available: true, price: 1000 },
273
+ { id: 'xxl', label: 'XXL', available: false, price: 1500 },
274
+ ],
275
+ selectedOption: 'l',
276
+ displayMode: 'text',
277
+ variant: 'dropdown',
278
+ label: 'Select Size',
279
+ },
280
+ decorators: [
281
+ (Story) => (
282
+ <Box sx={{ width: 300 }}>
283
+ <Story />
284
+ </Box>
285
+ ),
286
+ ],
287
+ };
288
+
289
+ export const AllDisabled: Story = {
290
+ args: {
291
+ options: sizeOptions,
292
+ selectedOption: 'm',
293
+ displayMode: 'text',
294
+ variant: 'grid',
295
+ label: 'Select Size',
296
+ disabled: true,
297
+ },
298
+ };
299
+
300
+ export const SomeUnavailable: Story = {
301
+ args: {
302
+ options: colorOptions,
303
+ selectedOption: 'blue',
304
+ displayMode: 'color',
305
+ variant: 'grid',
306
+ visualSize: 'medium',
307
+ showLabel: true,
308
+ label: 'Select Color (some unavailable)',
309
+ },
310
+ };
311
+
312
+ // ==================== REAL-WORLD EXAMPLES ====================
313
+
314
+ export const EcommerceProductSizes: Story = {
315
+ name: 'E-commerce: Product Sizes',
316
+ render: () => {
317
+ const [selectedSize, setSelectedSize] = React.useState('m');
318
+
319
+ return (
320
+ <Box sx={{ maxWidth: 400, p: 3, bgcolor: 'var(--theme-background)', borderRadius: 2 }}>
321
+ <OptionSelector
322
+ options={sizeOptions}
323
+ selectedOption={selectedSize}
324
+ onOptionSelect={setSelectedSize}
325
+ displayMode="text"
326
+ variant="grid"
327
+ label="Size"
328
+ />
329
+ </Box>
330
+ );
331
+ },
332
+ };
333
+
334
+ export const EcommerceProductColors: Story = {
335
+ name: 'E-commerce: Product Colors',
336
+ render: () => {
337
+ const [selectedColor, setSelectedColor] = React.useState('red');
338
+
339
+ return (
340
+ <Box sx={{ maxWidth: 400, p: 3, bgcolor: 'var(--theme-background)', borderRadius: 2 }}>
341
+ <OptionSelector
342
+ options={colorOptions}
343
+ selectedOption={selectedColor}
344
+ onOptionSelect={setSelectedColor}
345
+ displayMode="color"
346
+ variant="grid"
347
+ visualSize="large"
348
+ showLabel={true}
349
+ label="Color"
350
+ />
351
+ </Box>
352
+ );
353
+ },
354
+ };
355
+
356
+ export const EcommerceProductPatterns: Story = {
357
+ name: 'E-commerce: Product Patterns',
358
+ render: () => {
359
+ const [selectedPattern, setSelectedPattern] = React.useState('stripes');
360
+
361
+ return (
362
+ <Box sx={{ maxWidth: 400, p: 3, bgcolor: 'var(--theme-background)', borderRadius: 2 }}>
363
+ <OptionSelector
364
+ options={patternOptions}
365
+ selectedOption={selectedPattern}
366
+ onOptionSelect={setSelectedPattern}
367
+ displayMode="image"
368
+ variant="grid"
369
+ visualSize="large"
370
+ showLabel={true}
371
+ label="Pattern"
372
+ />
373
+ </Box>
374
+ );
375
+ },
376
+ };
377
+
378
+ export const CompleteProductVariantSelector: Story = {
379
+ name: 'Complete: Product Variant Selector',
380
+ render: () => {
381
+ const [selectedSize, setSelectedSize] = React.useState('m');
382
+ const [selectedColor, setSelectedColor] = React.useState('blue');
383
+ const [selectedPattern, setSelectedPattern] = React.useState('stripes');
384
+
385
+ return (
386
+ <Box sx={{ maxWidth: 600, p: 3, bgcolor: 'var(--theme-background)', borderRadius: 2 }}>
387
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
388
+ {/* Size Selection */}
389
+ <OptionSelector
390
+ options={sizeOptions}
391
+ selectedOption={selectedSize}
392
+ onOptionSelect={setSelectedSize}
393
+ displayMode="text"
394
+ variant="grid"
395
+ label="Size"
396
+ />
397
+
398
+ {/* Color Selection */}
399
+ <OptionSelector
400
+ options={colorOptions}
401
+ selectedOption={selectedColor}
402
+ onOptionSelect={setSelectedColor}
403
+ displayMode="color"
404
+ variant="grid"
405
+ visualSize="medium"
406
+ showLabel={true}
407
+ label="Color"
408
+ />
409
+
410
+ {/* Pattern Selection */}
411
+ <OptionSelector
412
+ options={patternOptions}
413
+ selectedOption={selectedPattern}
414
+ onOptionSelect={setSelectedPattern}
415
+ displayMode="image"
416
+ variant="grid"
417
+ visualSize="medium"
418
+ showLabel={true}
419
+ label="Pattern"
420
+ />
421
+
422
+ {/* Summary */}
423
+ <Box
424
+ sx={{
425
+ mt: 2,
426
+ p: 2,
427
+ bgcolor: 'var(--theme-surface)',
428
+ borderRadius: 1,
429
+ border: '1px solid var(--theme-border-main)'
430
+ }}
431
+ >
432
+ <strong>Selected:</strong> Size {selectedSize.toUpperCase()}, {selectedColor} color, {selectedPattern} pattern
433
+ </Box>
434
+ </Box>
435
+ </Box>
436
+ );
437
+ },
438
+ };
439
+
440
+ // ==================== THEME COMPLIANCE ====================
441
+
442
+ export const ThemeCompliance: Story = {
443
+ name: 'Theme Compliance Test',
444
+ render: () => {
445
+ const [mode, setMode] = React.useState<'light' | 'dark'>('light');
446
+
447
+ return (
448
+ <Box>
449
+ <Box sx={{ mb: 3 }}>
450
+ <button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>
451
+ Toggle to {mode === 'light' ? 'Dark' : 'Light'} Mode
452
+ </button>
453
+ </Box>
454
+
455
+ <Box
456
+ sx={{
457
+ p: 3,
458
+ bgcolor: mode === 'dark' ? '#1a1a1a' : '#ffffff',
459
+ '--theme-primary': mode === 'dark' ? '#90caf9' : '#1976d2',
460
+ '--theme-surface': mode === 'dark' ? '#2d2d2d' : '#f5f5f5',
461
+ '--theme-background': mode === 'dark' ? '#121212' : '#fafafa',
462
+ '--theme-text-primary': mode === 'dark' ? '#ffffff' : '#000000',
463
+ '--theme-text-secondary': mode === 'dark' ? '#b0b0b0' : '#666666',
464
+ '--theme-border-main': mode === 'dark' ? '#404040' : '#e0e0e0',
465
+ '--theme-border-emphasis': mode === 'dark' ? '#606060' : '#bdbdbd',
466
+ '--theme-elevation-1': mode === 'dark'
467
+ ? '0 2px 4px rgba(0,0,0,0.5)'
468
+ : '0 2px 4px rgba(0,0,0,0.1)',
469
+ '--theme-border-radius': '8px',
470
+ borderRadius: 2,
471
+ }}
472
+ >
473
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
474
+ <OptionSelector
475
+ options={sizeOptions}
476
+ selectedOption="m"
477
+ displayMode="text"
478
+ variant="grid"
479
+ label="Text Mode (Sizes)"
480
+ />
481
+
482
+ <OptionSelector
483
+ options={colorOptions}
484
+ selectedOption="blue"
485
+ displayMode="color"
486
+ variant="grid"
487
+ visualSize="medium"
488
+ showLabel={true}
489
+ label="Color Mode (Swatches)"
490
+ />
491
+
492
+ <OptionSelector
493
+ options={patternOptions}
494
+ selectedOption="stripes"
495
+ displayMode="image"
496
+ variant="grid"
497
+ visualSize="medium"
498
+ showLabel={true}
499
+ label="Image Mode (Patterns)"
500
+ />
501
+ </Box>
502
+ </Box>
503
+ </Box>
504
+ );
505
+ },
506
+ };