@repobit/dex-system-design 0.22.11 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/package.json +4 -3
  3. package/src/components/Button/button.stories.js +292 -120
  4. package/src/components/accordion/accordion-bg.css.js +7 -2
  5. package/src/components/accordion/accordion-bg.stories.js +268 -449
  6. package/src/components/accordion/accordion.stories.js +259 -265
  7. package/src/components/anchor/anchor.stories.js +160 -159
  8. package/src/components/awards/awards-icon.js +44 -0
  9. package/src/components/awards/awards.css.js +328 -0
  10. package/src/components/awards/awards.js +224 -0
  11. package/src/components/awards/awards.stories.js +447 -0
  12. package/src/components/back/back.stories.js +100 -375
  13. package/src/components/badge/badge.stories.js +241 -129
  14. package/src/components/breadcrumb/breadcrumb.stories.js +218 -219
  15. package/src/components/cards/card.stories.js +174 -622
  16. package/src/components/carousel/carousel.stories.js +196 -225
  17. package/src/components/checkbox/checkbox.stories.js +136 -51
  18. package/src/components/compare/compare.css.js +237 -0
  19. package/src/components/compare/compare.js +253 -0
  20. package/src/components/compare/compare.stories.js +372 -0
  21. package/src/components/display/display.stories.js +91 -297
  22. package/src/components/divider/divider.stories.js +160 -342
  23. package/src/components/footer/footer.stories.js +177 -402
  24. package/src/components/header/header.stories.js +130 -338
  25. package/src/components/heading/heading.js +8 -5
  26. package/src/components/heading/heading.stories.js +162 -471
  27. package/src/components/highlight/highlight.stories.js +153 -38
  28. package/src/components/image/image.stories.js +135 -563
  29. package/src/components/input/custom-form.stories.js +761 -224
  30. package/src/components/link/link.js +29 -12
  31. package/src/components/link/link.stories.js +130 -468
  32. package/src/components/modal/modal.stories.js +174 -28
  33. package/src/components/paragraph/paragraph.css.js +10 -1
  34. package/src/components/paragraph/paragraph.stories.js +85 -410
  35. package/src/components/picture/picture.stories.js +147 -561
  36. package/src/components/radio/radio.stories.js +230 -81
  37. package/src/components/tabs/tabs.stories.js +126 -10
  38. package/src/components/termsOfUse/terms.stories.js +223 -8
  39. package/src/tokens/tokens.js +1 -0
@@ -1,620 +1,206 @@
1
1
  import { html } from 'lit';
2
- import '../heading/heading.js';
3
- import '../paragraph/paragraph.js';
4
2
  import './picture.js';
5
3
 
6
4
  export default {
7
- title : 'Atoms/Picture',
8
- component: 'bd-picture',
9
- tags : ['autodocs'],
10
- argTypes : {
11
- sources: {
12
- control : 'object',
13
- description: 'Array of source objects for responsive images with media queries and format options',
14
- table : {
15
- type : { summary: 'Array<SourceObject>' },
16
- defaultValue: { summary: '[]' }
5
+ title : 'Components/Picture',
6
+ tags : ['autodocs'],
7
+ parameters: {
8
+ docs: {
9
+ description: {
10
+ component: `
11
+ **BdPicture** is a Lit responsive picture component that wraps \`<picture>\` with multiple \`<source>\` elements and a fallback \`<img>\`.
12
+
13
+ ### Usage
14
+ \`\`\`html
15
+ <bd-picture
16
+ fallback-src="/assets/product.png"
17
+ alt="Product screenshot"
18
+ width="800"
19
+ height="600"
20
+ fit="cover"
21
+ radius="md"
22
+ loading="lazy"
23
+ .sources="${[
24
+ { type: 'image/webp', srcset: '/assets/product.webp', media: '(min-width: 600px)' },
25
+ { type: 'image/png', srcset: '/assets/product.png' }
26
+ ]}"
27
+ ></bd-picture>
28
+ \`\`\`
29
+
30
+ ### Sources Array
31
+ Each source object supports:
32
+ - \`type\` — MIME type (e.g. \`"image/webp"\`)
33
+ - \`srcset\` — srcset value
34
+ - \`media\` — optional media query
35
+ - \`sizes\` — optional sizes attribute
36
+
37
+ ### CSS Classes Applied
38
+ | Prop | Class Pattern |
39
+ |---|---|
40
+ | \`fit\` | \`fit-{value}\` |
41
+ | \`radius\` | \`radius-{value}\` |
42
+ `
17
43
  }
44
+ }
45
+ },
46
+ argTypes: {
47
+ fallbackSrc: {
48
+ control : 'text',
49
+ description: 'Fallback `<img>` src used when no `<source>` matches',
50
+ table : { type: { summary: 'string' }, defaultValue: { summary: '' }, category: 'Content' }
18
51
  },
19
52
  alt: {
20
53
  control : 'text',
21
- description: 'Alternative text for accessibility and SEO',
22
- table : {
23
- type : { summary: 'string' },
24
- defaultValue: { summary: '' }
25
- }
54
+ description: 'Alt text for the fallback `<img>`',
55
+ table : { type: { summary: 'string' }, defaultValue: { summary: '' }, category: 'Content' }
26
56
  },
27
- fallbackSrc: {
28
- control : 'text',
29
- description: 'Fallback image source for browsers that don\'t support picture element or specific formats',
30
- table : {
31
- type : { summary: 'string' },
32
- defaultValue: { summary: '' }
33
- }
57
+ sources: {
58
+ control : 'object',
59
+ description: 'Array of source objects: `{ type, srcset, media?, sizes? }`',
60
+ table : { type: { summary: 'Array<{type, srcset, media?, sizes?}>' }, defaultValue: { summary: '[]' }, category: 'Content' }
34
61
  },
35
62
  width: {
36
63
  control : 'number',
37
- description: 'Image width in pixels for layout stability',
38
- table : {
39
- type : { summary: 'number' },
40
- defaultValue: { summary: 'null' }
41
- }
64
+ description: 'Intrinsic width of the fallback image',
65
+ table : { type: { summary: 'number' }, defaultValue: { summary: 'null' }, category: 'Dimensions' }
42
66
  },
43
67
  height: {
44
68
  control : 'number',
45
- description: 'Image height in pixels for layout stability',
46
- table : {
47
- type : { summary: 'number' },
48
- defaultValue: { summary: 'null' }
49
- }
69
+ description: 'Intrinsic height of the fallback image',
70
+ table : { type: { summary: 'number' }, defaultValue: { summary: 'null' }, category: 'Dimensions' }
50
71
  },
51
72
  loading: {
52
73
  control : { type: 'select' },
53
74
  options : ['lazy', 'eager'],
54
- description: 'Image loading strategy for performance optimization',
55
- table : {
56
- type : { summary: 'string' },
57
- defaultValue: { summary: 'lazy' }
58
- }
75
+ description: 'Native browser loading strategy',
76
+ table : { type: { summary: "'lazy'|'eager'" }, defaultValue: { summary: 'lazy' }, category: 'Performance' }
59
77
  },
60
78
  fit: {
61
79
  control : { type: 'select' },
62
80
  options : ['cover', 'contain', 'fill', 'none', 'scale-down'],
63
- description: 'How the image should be resized to fit its container',
64
- table : {
65
- type : { summary: 'string' },
66
- defaultValue: { summary: 'cover' }
67
- }
81
+ description: 'Object-fit class applied as `fit-{value}`',
82
+ table : { type: { summary: 'string' }, defaultValue: { summary: 'cover' }, category: 'Appearance' }
68
83
  },
69
84
  radius: {
70
85
  control : { type: 'select' },
71
- options : ['none', 'sm', 'md', 'lg', 'full'],
72
- description: 'Border radius for rounded corners',
73
- table : {
74
- type : { summary: 'string' },
75
- defaultValue: { summary: 'none' }
76
- }
77
- }
78
- },
79
- parameters: {
80
- docs: {
81
- description: {
82
- component: 'A responsive picture component that supports multiple image formats, breakpoints, and modern web features. Provides optimal performance and accessibility with fallback support for older browsers.'
83
- }
86
+ options : ['none', 'sm', 'md', 'lg', 'xl', 'full'],
87
+ description: 'Border radius class applied as `radius-{value}`',
88
+ table : { type: { summary: 'string' }, defaultValue: { summary: 'none' }, category: 'Appearance' }
84
89
  }
85
90
  }
86
91
  };
87
92
 
88
- const Template = (args) => html`
93
+ const placeholder = 'https://via.placeholder.com/800x450';
94
+
95
+ const defaultSources = [
96
+ { type: 'image/webp', srcset: placeholder + '?format=webp', media: '(min-width: 600px)' },
97
+ { type: 'image/png', srcset: placeholder }
98
+ ];
99
+
100
+ const defaultArgs = {
101
+ fallbackSrc: placeholder, alt : 'Product image',
102
+ sources : defaultSources, width : 800, height : 450,
103
+ loading : 'lazy', fit : 'cover', radius : 'none'
104
+ };
105
+
106
+ const render = (args) => html`
89
107
  <bd-picture
90
- .sources="${args.sources}"
91
- alt="${args.alt}"
92
108
  fallback-src="${args.fallbackSrc}"
109
+ alt="${args.alt}"
93
110
  width="${args.width}"
94
111
  height="${args.height}"
95
112
  loading="${args.loading}"
96
113
  fit="${args.fit}"
97
114
  radius="${args.radius}"
115
+ .sources="${args.sources}"
98
116
  ></bd-picture>
99
117
  `;
100
118
 
101
- // ============ STORIES ============
102
-
103
- export const Default = Template.bind({});
104
- Default.args = {
105
- sources: [
106
- {
107
- type : 'image/webp',
108
- srcset: '/assets/bd-header-us-2000.webp',
109
- media : '(min-width: 1200px)'
110
- },
111
- {
112
- type : 'image/webp',
113
- srcset: '/assets/bd-header-us-1000.webp',
114
- media : '(min-width: 768px)'
115
- },
116
- {
117
- type : 'image/webp',
118
- srcset: '/assets/bd-header-us-750.webp'
119
- }
120
- ],
121
- alt : 'Bitdefender Security Illustration showing comprehensive protection features',
122
- fallbackSrc: '/assets/bd-header-us.jpg',
123
- width : 750,
124
- height : 500,
125
- loading : 'lazy',
126
- fit : 'cover',
127
- radius : 'none'
128
- };
129
- Default.parameters = {
130
- docs: {
131
- description: {
132
- story: 'Default picture component with responsive WebP sources and JPEG fallback. Optimized for performance with lazy loading and proper aspect ratio.'
133
- }
134
- }
135
- };
136
-
137
- export const AllSourceTypes = () => html`
138
- <div style="display: flex; flex-direction: column; gap: 3rem; max-width: 1000px; margin: 0 auto; padding: 2rem;">
139
- <bd-h as="h2" style="margin-bottom: 1rem;">Picture Source Types and Strategies</bd-h>
140
- <bd-p kind="regular" style="margin-bottom: 2rem;">
141
- The picture element supports multiple image formats and responsive breakpoints for optimal performance and visual quality across different devices and browsers.
142
- </bd-p>
143
-
144
- <div style="border: 2px solid #e2e8f0; padding: 2rem; border-radius: 8px;">
145
- <bd-h as="h3" style="color: #3b82f6; margin-bottom: 1rem;">WebP with JPEG Fallback</bd-h>
146
- <bd-picture
147
- .sources="${[
148
- {
149
- type : 'image/webp',
150
- srcset: '/assets/bd-header-us-2000.webp',
151
- media : '(min-width: 1200px)'
152
- },
153
- {
154
- type : 'image/webp',
155
- srcset: '/assets/bd-header-us-1000.webp',
156
- media : '(min-width: 768px)'
157
- },
158
- {
159
- type : 'image/webp',
160
- srcset: '/assets/bd-header-us-750.webp'
161
- },
162
- {
163
- type : 'image/jpeg',
164
- srcset: '/assets/bd-header-us-2000.jpg',
165
- media : '(min-width: 1200px)'
166
- },
167
- {
168
- type : 'image/jpeg',
169
- srcset: '/assets/bd-header-us-1000.jpg',
170
- media : '(min-width: 768px)'
171
- }
172
- ]}"
173
- alt="Bitdefender Security with WebP and JPEG fallback support"
174
- fallback-src="/assets/bd-header-us.jpg"
175
- width="800"
176
- height="500"
177
- loading="lazy"
178
- fit="cover"
179
- radius="md"
180
- ></bd-picture>
181
- <bd-p kind="regular" style="margin-top: 1.5rem;">
182
- <strong>Strategy:</strong> Modern WebP format for supported browsers with JPEG fallback for compatibility<br>
183
- <strong>Benefits:</strong> Better compression + wide browser support<br>
184
- <strong>Use case:</strong> Production websites requiring optimal performance
185
- </bd-p>
186
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
187
- 💡 <strong>Best practice:</strong> Always provide JPEG fallback for maximum browser compatibility
188
- </bd-p>
189
- </div>
190
-
191
- <div style="border: 2px solid #e2e8f0; padding: 2rem; border-radius: 8px;">
192
- <bd-h as="h3" style="color: #3b82f6; margin-bottom: 1rem;">Multiple Breakpoint Strategy</bd-h>
193
- <bd-picture
194
- .sources="${[
195
- {
196
- type : 'image/webp',
197
- srcset: '/assets/bd-header-us-2000.webp',
198
- media : '(min-width: 1440px)'
199
- },
200
- {
201
- type : 'image/webp',
202
- srcset: '/assets/bd-header-us-1200.webp',
203
- media : '(min-width: 1024px)'
204
- },
205
- {
206
- type : 'image/webp',
207
- srcset: '/assets/bd-header-us-800.webp',
208
- media : '(min-width: 768px)'
209
- },
210
- {
211
- type : 'image/webp',
212
- srcset: '/assets/bd-header-us-600.webp',
213
- media : '(min-width: 480px)'
214
- },
215
- {
216
- type : 'image/webp',
217
- srcset: '/assets/bd-header-us-400.webp'
218
- }
219
- ]}"
220
- alt="Bitdefender Security optimized for multiple screen sizes"
221
- fallback-src="/assets/bd-header-us.jpg"
222
- width="800"
223
- height="500"
224
- loading="lazy"
225
- fit="cover"
226
- radius="md"
227
- ></bd-picture>
228
- <bd-p kind="regular" style="margin-top: 1.5rem;">
229
- <strong>Breakpoints:</strong> 1440px+ (desktop), 1024px+ (laptop), 768px+ (tablet), 480px+ (large mobile), default (mobile)<br>
230
- <strong>Benefits:</strong> Optimal image size for each device, faster loading<br>
231
- <strong>Use case:</strong> High-traffic websites with diverse device usage
232
- </bd-p>
233
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
234
- 📱 <strong>Performance:</strong> Mobile users download smaller images, improving page speed
235
- </bd-p>
236
- </div>
237
-
238
- <div style="border: 2px solid #e2e8f0; padding: 2rem; border-radius: 8px;">
239
- <bd-h as="h3" style="color: #3b82f6; margin-bottom: 1rem;">Single Source Simplicity</bd-h>
240
- <bd-picture
241
- .sources="${[
242
- {
243
- type : 'image/jpeg',
244
- srcset: '/assets/bd-header-us.jpg'
245
- }
246
- ]}"
247
- alt="Simple Bitdefender Security image implementation"
248
- fallback-src="/assets/bd-header-us.jpg"
249
- width="600"
250
- height="400"
251
- loading="lazy"
252
- fit="cover"
253
- radius="lg"
254
- ></bd-picture>
255
- <bd-p kind="regular" style="margin-top: 1.5rem;">
256
- <strong>Strategy:</strong> Single image source without responsive variants<br>
257
- <strong>Benefits:</strong> Simpler implementation, fewer image files to manage<br>
258
- <strong>Use case:</strong> Internal applications, prototypes, simple websites
259
- </bd-p>
260
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
261
- ⚡ <strong>Quick setup:</strong> Perfect for MVPs and projects with limited image requirements
262
- </bd-p>
263
- </div>
264
- </div>
265
- `;
266
- AllSourceTypes.parameters = {
267
- docs: {
268
- description: {
269
- story: 'Comprehensive demonstration of different picture source strategies including WebP with JPEG fallback, multiple breakpoint optimization, and simple single-source implementations with detailed use case recommendations.'
270
- }
271
- }
272
- };
119
+ // ─── Stories ───────────────────────────────────────────────────────────────
273
120
 
274
- export const SimplePicture = Template.bind({});
275
- SimplePicture.args = {
276
- sources: [
277
- {
278
- type : 'image/jpeg',
279
- srcset: '/assets/bd-header-us.jpg'
280
- }
281
- ],
282
- alt : 'Simple Bitdefender Security Image showing protection interface',
283
- fallbackSrc: '/assets/bd-header-us.jpg',
284
- width : 600,
285
- height : 400,
286
- loading : 'eager',
287
- fit : 'cover',
288
- radius : 'none'
289
- };
290
- SimplePicture.parameters = {
291
- docs: {
292
- description: {
293
- story: 'Simple picture implementation with single JPEG source. Ideal for prototypes, internal applications, or situations where multiple image formats and breakpoints are not required.'
294
- }
295
- }
121
+ export const Default = {
122
+ name : 'Default',
123
+ render: () => html`
124
+ <bd-picture fallback-src="${placeholder}" alt="Product image" width="800" height="450" .sources="${defaultSources}"></bd-picture>
125
+ `,
126
+ parameters: { docs: { description: { story: 'Default picture with WebP and PNG sources and a PNG fallback.' } } }
296
127
  };
297
128
 
298
- export const AdvancedResponsive = Template.bind({});
299
- AdvancedResponsive.args = {
300
- sources: [
301
- {
302
- type : 'image/avif',
303
- srcset: '/assets/bd-header-us-2000.avif',
304
- media : '(min-width: 1440px)'
305
- },
306
- {
307
- type : 'image/webp',
308
- srcset: '/assets/bd-header-us-1200.webp',
309
- media : '(min-width: 1024px)'
310
- },
311
- {
312
- type : 'image/webp',
313
- srcset: '/assets/bd-header-us-800.webp',
314
- media : '(min-width: 768px)'
315
- },
316
- {
317
- type : 'image/webp',
318
- srcset: '/assets/bd-header-us-400.webp'
319
- }
320
- ],
321
- alt : 'Advanced Bitdefender Security with AVIF and WebP formats',
322
- fallbackSrc: '/assets/bd-header-us.jpg',
323
- width : 800,
324
- height : 500,
325
- loading : 'lazy',
326
- fit : 'cover',
327
- radius : 'md'
328
- };
329
- AdvancedResponsive.parameters = {
330
- docs: {
331
- description: {
332
- story: 'Advanced responsive picture with AVIF format for modern browsers, WebP for broader support, and multiple breakpoints for optimal performance across all device types.'
333
- }
334
- }
129
+ export const NoSources = {
130
+ name : 'No Sources (fallback only)',
131
+ render: () => html`
132
+ <bd-picture fallback-src="${placeholder}" alt="Fallback only" width="600" height="400" .sources="${[]}"></bd-picture>
133
+ `,
134
+ parameters: { docs: { description: { story: 'Empty `sources` array — only the fallback `<img>` is used.' } } }
335
135
  };
336
136
 
337
- export const ObjectFitOptions = () => html`
338
- <div style="display: flex; flex-direction: column; gap: 2rem; max-width: 1000px; margin: 0 auto; padding: 2rem;">
339
- <bd-h as="h2" style="margin-bottom: 1rem;">Object Fit Property Examples</bd-h>
340
- <bd-p kind="regular" style="margin-bottom: 2rem;">
341
- The object-fit property controls how the image content is resized to fit its container. Choose the appropriate option based on your layout requirements.
342
- </bd-p>
343
-
344
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem;">
345
- <div style="text-align: center;">
346
- <bd-h as="h4" style="margin-bottom: 1rem;">Cover</bd-h>
347
- <div style="width: 250px; height: 200px; margin: 0 auto; border: 2px solid #e2e8f0; border-radius: 8px; overflow: hidden;">
348
- <bd-picture
349
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
350
- alt="Cover fit example"
351
- fallback-src="/assets/bd-header-us.jpg"
352
- width="250"
353
- height="200"
354
- fit="cover"
355
- ></bd-picture>
356
- </div>
357
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
358
- <strong>Use case:</strong> Hero images, profile pictures<br>
359
- <strong>Behavior:</strong> Fills container, may crop edges
360
- </bd-p>
361
- </div>
362
-
363
- <div style="text-align: center;">
364
- <bd-h as="h4" style="margin-bottom: 1rem;">Contain</bd-h>
365
- <div style="width: 250px; height: 200px; margin: 0 auto; border: 2px solid #e2e8f0; border-radius: 8px; overflow: hidden; background: #f8fafc;">
366
- <bd-picture
367
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
368
- alt="Contain fit example"
369
- fallback-src="/assets/bd-header-us.jpg"
370
- width="250"
371
- height="200"
372
- fit="contain"
373
- ></bd-picture>
137
+ export const WithRadius = {
138
+ name : 'Radius Variants',
139
+ render: () => html`
140
+ <div style="display:flex; gap:16px; flex-wrap:wrap;">
141
+ ${['none', 'sm', 'md', 'lg', 'full'].map(r => html`
142
+ <div>
143
+ <p style="font-size:12px; margin-bottom:4px;">radius-${r}</p>
144
+ <bd-picture fallback-src="${placeholder}" alt="radius ${r}" width="180" height="180" radius="${r}" fit="cover" .sources="${[]}"></bd-picture>
374
145
  </div>
375
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
376
- <strong>Use case:</strong> Product images, logos<br>
377
- <strong>Behavior:</strong> Fits entirely, may have empty space
378
- </bd-p>
379
- </div>
380
-
381
- <div style="text-align: center;">
382
- <bd-h as="h4" style="margin-bottom: 1rem;">Fill</bd-h>
383
- <div style="width: 250px; height: 200px; margin: 0 auto; border: 2px solid #e2e8f0; border-radius: 8px; overflow: hidden;">
384
- <bd-picture
385
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
386
- alt="Fill fit example"
387
- fallback-src="/assets/bd-header-us.jpg"
388
- width="250"
389
- height="200"
390
- fit="fill"
391
- ></bd-picture>
392
- </div>
393
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
394
- <strong>Use case:</strong> Background patterns<br>
395
- <strong>Behavior:</strong> Stretches to fill, may distort
396
- </bd-p>
397
- </div>
146
+ `)}
398
147
  </div>
399
- </div>
400
- `;
401
- ObjectFitOptions.parameters = {
402
- docs: {
403
- description: {
404
- story: 'Demonstration of different object-fit properties (cover, contain, fill) with visual examples and recommendations for when to use each option based on layout requirements and image content.'
405
- }
406
- }
148
+ `,
149
+ parameters: { docs: { description: { story: 'Five radius values applied to equal-dimension images.' } } }
407
150
  };
408
151
 
409
- export const LoadingStrategies = () => html`
410
- <div style="display: flex; flex-direction: column; gap: 2rem; max-width: 800px; margin: 0 auto; padding: 2rem;">
411
- <bd-h as="h2" style="margin-bottom: 1rem;">Loading Strategy Comparison</bd-h>
412
-
413
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 2rem;">
414
- <div style="border: 2px solid #e2e8f0; padding: 2rem; border-radius: 12px;">
415
- <bd-h as="h3" style="color: #3b82f6; margin-bottom: 1rem;">Lazy Loading</bd-h>
416
- <bd-picture
417
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
418
- alt="Lazy loaded security image"
419
- fallback-src="/assets/bd-header-us.jpg"
420
- width="300"
421
- height="200"
422
- loading="lazy"
423
- fit="cover"
424
- radius="md"
425
- ></bd-picture>
426
- <bd-p kind="regular" style="margin-top: 1.5rem;">
427
- <strong>When to use:</strong> Images below the fold, gallery items, non-critical content<br>
428
- <strong>Performance:</strong> Improves initial page load time<br>
429
- <strong>User experience:</strong> Images load as user scrolls near them
430
- </bd-p>
431
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
432
- ✅ <strong>Best practice:</strong> Use for all non-essential images
433
- </bd-p>
434
- </div>
435
-
436
- <div style="border: 2px solid #e2e8f0; padding: 2rem; border-radius: 12px;">
437
- <bd-h as="h3" style="color: #3b82f6; margin-bottom: 1rem;">Eager Loading</bd-h>
438
- <bd-picture
439
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
440
- alt="Eager loaded security image"
441
- fallback-src="/assets/bd-header-us.jpg"
442
- width="300"
443
- height="200"
444
- loading="eager"
445
- fit="cover"
446
- radius="md"
447
- ></bd-picture>
448
- <bd-p kind="regular" style="margin-top: 1.5rem;">
449
- <strong>When to use:</strong> Hero images, above-the-fold content, LCP elements<br>
450
- <strong>Performance:</strong> Loads immediately, may impact initial load<br>
451
- <strong>User experience:</strong> Critical images ready when page renders
452
- </bd-p>
453
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
454
- ⚠️ <strong>Use sparingly:</strong> Only for images essential to initial rendering
455
- </bd-p>
456
- </div>
152
+ export const FitVariants = {
153
+ name : 'Fit Variants',
154
+ render: () => html`
155
+ <div style="display:flex; gap:16px; flex-wrap:wrap;">
156
+ ${['cover', 'contain', 'fill', 'none'].map(fit => html`
157
+ <div>
158
+ <p style="font-size:12px; margin-bottom:4px;">${fit}</p>
159
+ <bd-picture fallback-src="${placeholder}" alt="${fit}" width="200" height="150" fit="${fit}" .sources="${[]}"></bd-picture>
160
+ </div>
161
+ `)}
457
162
  </div>
458
- </div>
459
- `;
460
- LoadingStrategies.parameters = {
461
- docs: {
462
- description: {
463
- story: 'Comparison of lazy vs eager loading strategies with performance implications and guidelines for when to use each approach based on image importance and position in the page layout.'
464
- }
465
- }
163
+ `,
164
+ parameters: { docs: { description: { story: 'Fit variants: cover, contain, fill, none.' } } }
466
165
  };
467
166
 
468
- export const AccessibilityExamples = () => html`
469
- <div style="display: flex; flex-direction: column; gap: 2rem; max-width: 800px; margin: 0 auto; padding: 2rem;">
470
- <bd-h as="h2" style="margin-bottom: 1rem;">Accessibility Best Practices</bd-h>
471
-
472
- <div style="border: 2px solid #10b981; padding: 2rem; border-radius: 12px; background: #f0fdf4;">
473
- <bd-h as="h3" style="color: #059669; margin-bottom: 1rem;">✅ Good Alt Text Examples</bd-h>
474
-
475
- <bd-picture
476
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
477
- alt="Bitdefender security software dashboard showing real-time threat protection, firewall status, and privacy tools with green status indicators"
478
- fallback-src="/assets/bd-header-us.jpg"
479
- width="600"
480
- height="400"
481
- loading="lazy"
482
- fit="cover"
483
- radius="md"
484
- ></bd-picture>
485
-
486
- <bd-p kind="regular" style="margin-top: 1.5rem;">
487
- <strong>Descriptive:</strong> Clearly describes the image content and context<br>
488
- <strong>Concise:</strong> Meaningful but not overly verbose<br>
489
- <strong>Relevant:</strong> Relates to the surrounding content and purpose
490
- </bd-p>
491
- <bd-p kind="small" style="color: #059669; margin-top: 1rem;">
492
- ✅ Screen readers will provide meaningful context about the image content
493
- </bd-p>
494
- </div>
495
-
496
- <div style="border: 2px solid #ef4444; padding: 2rem; border-radius: 12px; background: #fef2f2;">
497
- <bd-h as="h3" style="color: #dc2626; margin-bottom: 1rem;">❌ Poor Alt Text Examples</bd-h>
498
-
499
- <bd-picture
500
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
501
- alt="image123.jpg"
502
- fallback-src="/assets/bd-header-us.jpg"
503
- width="600"
504
- height="400"
505
- loading="lazy"
506
- fit="cover"
507
- radius="md"
508
- ></bd-picture>
509
-
510
- <bd-p kind="regular" style="margin-top: 1.5rem;">
511
- <strong>Avoid:</strong> File names, placeholder text, or generic descriptions<br>
512
- <strong>Don't:</strong> Start with "image of" or "picture of"<br>
513
- <strong>Never:</strong> Leave alt text empty for meaningful images
514
- </bd-p>
515
- <bd-p kind="small" style="color: #dc2626; margin-top: 1rem;">
516
- ❌ Screen readers will announce meaningless file names to users
517
- </bd-p>
518
- </div>
519
-
520
- <div style="border: 2px solid #e2e8f0; padding: 2rem; border-radius: 12px;">
521
- <bd-h as="h3" style="color: #3b82f6; margin-bottom: 1rem;">Decorative Images</bd-h>
522
- <bd-p kind="regular" style="margin-bottom: 1.5rem;">
523
- For purely decorative images that don't convey meaningful content, use empty alt text to prevent screen readers from announcing them.
524
- </bd-p>
525
- <bd-picture
526
- .sources="${[{ type: 'image/jpeg', srcset: '/assets/bd-header-us.jpg' }]}"
527
- alt=""
528
- fallback-src="/assets/bd-header-us.jpg"
529
- width="400"
530
- height="200"
531
- loading="lazy"
532
- fit="cover"
533
- radius="md"
534
- ></bd-picture>
535
- <bd-p kind="small" style="color: #64748b; margin-top: 1rem;">
536
- ✅ Empty alt attribute: <code>alt=""</code> - Screen readers will skip this image entirely
537
- </bd-p>
538
- </div>
539
- </div>
540
- `;
541
- AccessibilityExamples.parameters = {
542
- docs: {
543
- description: {
544
- story: 'Accessibility guidelines and examples showing proper alt text usage, common mistakes to avoid, and how to handle decorative images. Essential for creating inclusive experiences for screen reader users.'
545
- }
546
- }
167
+ export const ResponsiveSources = {
168
+ name : 'Responsive Sources (media queries)',
169
+ render: () => html`
170
+ <bd-picture
171
+ fallback-src="${placeholder}"
172
+ alt="Responsive product image"
173
+ width="800" height="450"
174
+ .sources="${[
175
+ { type: 'image/webp', srcset: placeholder + '?w=800', media: '(min-width: 600px)' },
176
+ { type: 'image/webp', srcset: placeholder + '?w=400', media: '' },
177
+ { type: 'image/png', srcset: placeholder }
178
+ ]}"
179
+ ></bd-picture>
180
+ `,
181
+ parameters: { docs: { description: { story: 'Three sources: large WebP for desktop, small WebP for mobile, PNG fallback.' } } }
547
182
  };
548
183
 
549
- export const HeaderImageExample = () => html`
550
- <div style="max-width: 1000px; margin: 0 auto; padding: 2rem;">
551
- <bd-h as="h2" style="margin-bottom: 2rem; text-align: center;">Bitdefender Ultimate Security</bd-h>
552
-
553
- <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 3rem; border-radius: 12px; color: white;">
554
- <bd-picture
555
- .sources="${[
556
- {
557
- type : 'image/webp',
558
- srcset: '/assets/bd-header-us-2000.webp',
559
- media : '(min-width: 1200px)'
560
- },
561
- {
562
- type : 'image/webp',
563
- srcset: '/assets/bd-header-us-1000.webp',
564
- media : '(min-width: 768px)'
565
- },
566
- {
567
- type : 'image/webp',
568
- srcset: '/assets/bd-header-us-750.webp'
569
- }
570
- ]}"
571
- alt="Bitdefender Security Suite dashboard showing comprehensive protection features including antivirus, firewall, and privacy tools"
572
- fallback-src="/assets/bd-header-us.jpg"
573
- width="800"
574
- height="400"
575
- loading="eager"
576
- fit="cover"
577
- radius="lg"
578
- ></bd-picture>
579
-
580
- <div style="margin-top: 2rem; text-align: center;">
581
- <bd-h as="h3" style="color: white; margin-bottom: 1rem;">Complete Digital Protection</bd-h>
582
- <bd-p kind="lead" style="color: white; opacity: 0.9;">
583
- Enterprise-grade security solutions for home and business users.
584
- Real-time threat detection, advanced firewall, and privacy protection in one package.
585
- </bd-p>
184
+ export const LazyVsEager = {
185
+ name : 'Lazy vs Eager Loading',
186
+ render: () => html`
187
+ <div style="display:flex; gap:16px; flex-wrap:wrap;">
188
+ <div>
189
+ <p style="font-size:12px; margin-bottom:4px;">loading="lazy"</p>
190
+ <bd-picture fallback-src="${placeholder}" alt="Lazy" width="300" height="200" loading="lazy" .sources="${[]}"></bd-picture>
191
+ </div>
192
+ <div>
193
+ <p style="font-size:12px; margin-bottom:4px;">loading="eager"</p>
194
+ <bd-picture fallback-src="${placeholder}" alt="Eager" width="300" height="200" loading="eager" .sources="${[]}"></bd-picture>
586
195
  </div>
587
196
  </div>
588
- </div>
589
- `;
590
- HeaderImageExample.parameters = {
591
- docs: {
592
- description: {
593
- story: 'Real-world example of a hero section using the picture component with responsive images, eager loading for above-the-fold content, and proper accessibility attributes in a marketing context.'
594
- }
595
- }
197
+ `,
198
+ parameters: { docs: { description: { story: 'Comparison of `loading="lazy"` and `loading="eager"` side by side.' } } }
596
199
  };
597
200
 
598
- export const InteractivePlayground = Template.bind({});
599
- InteractivePlayground.args = {
600
- sources: [
601
- {
602
- type : 'image/jpeg',
603
- srcset: '/assets/bd-header-us.jpg'
604
- }
605
- ],
606
- alt : 'Customizable picture component example',
607
- fallbackSrc: '/assets/bd-header-us.jpg',
608
- width : 400,
609
- height : 300,
610
- loading : 'lazy',
611
- fit : 'cover',
612
- radius : 'none'
613
- };
614
- InteractivePlayground.parameters = {
615
- docs: {
616
- description: {
617
- story: 'Interactive playground where you can test all picture properties in real-time. Use the controls panel to modify the image sources, dimensions, loading strategy, fit behavior, and styling options.'
618
- }
619
- }
201
+ export const Playground = {
202
+ name : '🛝 Playground',
203
+ args : { ...defaultArgs },
204
+ render,
205
+ parameters: { docs: { description: { story: 'Interactive playground. Adjust all props via Controls.' } } }
620
206
  };