@fpkit/acss 0.5.11 → 0.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.
- package/README.md +514 -18
- package/libs/chunk-23ANBDCR.js +8 -0
- package/libs/chunk-23ANBDCR.js.map +1 -0
- package/libs/chunk-2LTJ7HHX.cjs +18 -0
- package/libs/chunk-2LTJ7HHX.cjs.map +1 -0
- package/libs/chunk-2Y7W75TT.js +9 -0
- package/libs/chunk-2Y7W75TT.js.map +1 -0
- package/libs/chunk-3MKLDCKQ.cjs +31 -0
- package/libs/chunk-3MKLDCKQ.cjs.map +1 -0
- package/libs/chunk-5M57K4SW.js +8 -0
- package/libs/chunk-5M57K4SW.js.map +1 -0
- package/libs/chunk-5S4ORA4C.cjs +15 -0
- package/libs/chunk-5S4ORA4C.cjs.map +1 -0
- package/libs/chunk-772NRB75.js +9 -0
- package/libs/chunk-772NRB75.js.map +1 -0
- package/libs/chunk-AHDJGCG5.cjs +15 -0
- package/libs/chunk-AHDJGCG5.cjs.map +1 -0
- package/libs/chunk-B7F5FS6D.cjs +16 -0
- package/libs/chunk-B7F5FS6D.cjs.map +1 -0
- package/libs/chunk-BHRQBJRY.js +8 -0
- package/libs/chunk-BHRQBJRY.js.map +1 -0
- package/libs/chunk-D4YLRWAO.cjs +18 -0
- package/libs/chunk-D4YLRWAO.cjs.map +1 -0
- package/libs/chunk-ETFLFC2S.js +10 -0
- package/libs/chunk-ETFLFC2S.js.map +1 -0
- package/libs/chunk-G55UJ53G.cjs +16 -0
- package/libs/chunk-G55UJ53G.cjs.map +1 -0
- package/libs/chunk-GZ4QFPRY.js +9 -0
- package/libs/chunk-GZ4QFPRY.js.map +1 -0
- package/libs/chunk-IYUN2EW3.cjs +15 -0
- package/libs/chunk-IYUN2EW3.cjs.map +1 -0
- package/libs/chunk-J32EZPYD.cjs +15 -0
- package/libs/chunk-J32EZPYD.cjs.map +1 -0
- package/libs/chunk-JJ43O4Y5.js +8 -0
- package/libs/chunk-JJ43O4Y5.js.map +1 -0
- package/libs/chunk-KUKIVRC2.js +7 -0
- package/libs/chunk-KUKIVRC2.js.map +1 -0
- package/libs/chunk-L75OQKEI.cjs +13 -0
- package/libs/chunk-L75OQKEI.cjs.map +1 -0
- package/libs/chunk-LT5KZ2QW.cjs +22 -0
- package/libs/chunk-LT5KZ2QW.cjs.map +1 -0
- package/libs/chunk-M5RRNTVX.cjs +15 -0
- package/libs/chunk-M5RRNTVX.cjs.map +1 -0
- package/libs/chunk-NGTJDDFO.js +8 -0
- package/libs/chunk-NGTJDDFO.js.map +1 -0
- package/libs/chunk-OK5QEIMD.cjs +17 -0
- package/libs/chunk-OK5QEIMD.cjs.map +1 -0
- package/libs/chunk-P2DC76ZZ.cjs +18 -0
- package/libs/chunk-P2DC76ZZ.cjs.map +1 -0
- package/libs/chunk-P7TTEYCD.js +7 -0
- package/libs/chunk-P7TTEYCD.js.map +1 -0
- package/libs/chunk-PQ2K3BM6.cjs +17 -0
- package/libs/chunk-PQ2K3BM6.cjs.map +1 -0
- package/libs/chunk-QLZWHAMK.js +8 -0
- package/libs/chunk-QLZWHAMK.js.map +1 -0
- package/libs/chunk-RIVUMPOG.js +8 -0
- package/libs/chunk-RIVUMPOG.js.map +1 -0
- package/libs/chunk-ROZI23GS.cjs +15 -0
- package/libs/chunk-ROZI23GS.cjs.map +1 -0
- package/libs/chunk-S7BABR7Z.cjs +13 -0
- package/libs/chunk-S7BABR7Z.cjs.map +1 -0
- package/libs/chunk-SMYRLO3E.js +8 -0
- package/libs/chunk-SMYRLO3E.js.map +1 -0
- package/libs/chunk-TYRCEX2L.js +8 -0
- package/libs/chunk-TYRCEX2L.js.map +1 -0
- package/libs/chunk-VUH3FXGJ.js +11 -0
- package/libs/chunk-VUH3FXGJ.js.map +1 -0
- package/libs/chunk-XBA562WW.js +8 -0
- package/libs/chunk-XBA562WW.js.map +1 -0
- package/libs/chunk-XTQKWY7W.cjs +32 -0
- package/libs/chunk-XTQKWY7W.cjs.map +1 -0
- package/libs/chunk-ZANSFMTD.js +9 -0
- package/libs/chunk-ZANSFMTD.js.map +1 -0
- package/libs/component-props-a8a2f97e.d.ts +38 -0
- package/libs/components/alert/alert.css +1 -1
- package/libs/components/alert/alert.css.map +1 -1
- package/libs/components/alert/alert.min.css +2 -2
- package/libs/components/badge/badge.css +1 -1
- package/libs/components/badge/badge.css.map +1 -1
- package/libs/components/badge/badge.min.css +2 -2
- package/libs/components/breadcrumbs/breadcrumb.cjs +24 -0
- package/libs/components/breadcrumbs/breadcrumb.cjs.map +1 -0
- package/libs/components/breadcrumbs/breadcrumb.d.cts +290 -0
- package/libs/components/breadcrumbs/breadcrumb.d.ts +290 -0
- package/libs/components/breadcrumbs/breadcrumb.js +5 -0
- package/libs/components/breadcrumbs/breadcrumb.js.map +1 -0
- package/libs/components/button.cjs +19 -0
- package/libs/components/button.cjs.map +1 -0
- package/libs/components/button.d.cts +16 -0
- package/libs/components/button.d.ts +16 -0
- package/libs/components/button.js +4 -0
- package/libs/components/button.js.map +1 -0
- package/libs/components/buttons/button.css +1 -1
- package/libs/components/buttons/button.css.map +1 -1
- package/libs/components/buttons/button.min.css +2 -2
- package/libs/components/card.cjs +31 -0
- package/libs/components/card.cjs.map +1 -0
- package/libs/components/card.d.cts +302 -0
- package/libs/components/card.d.ts +302 -0
- package/libs/components/card.js +4 -0
- package/libs/components/card.js.map +1 -0
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/details/details.css +1 -1
- package/libs/components/details/details.css.map +1 -1
- package/libs/components/details/details.min.css +2 -2
- package/libs/components/dialog/dialog.cjs +22 -0
- package/libs/components/dialog/dialog.cjs.map +1 -0
- package/libs/components/dialog/dialog.css +1 -1
- package/libs/components/dialog/dialog.css.map +1 -1
- package/libs/components/dialog/dialog.d.cts +105 -0
- package/libs/components/dialog/dialog.d.ts +105 -0
- package/libs/components/dialog/dialog.js +7 -0
- package/libs/components/dialog/dialog.js.map +1 -0
- package/libs/components/dialog/dialog.min.css +2 -2
- package/libs/components/form/fields.cjs +19 -0
- package/libs/components/form/fields.cjs.map +1 -0
- package/libs/components/form/fields.d.cts +24 -0
- package/libs/components/form/fields.d.ts +24 -0
- package/libs/components/form/fields.js +4 -0
- package/libs/components/form/fields.js.map +1 -0
- package/libs/components/form/inputs.cjs +19 -0
- package/libs/components/form/inputs.cjs.map +1 -0
- package/libs/components/form/inputs.d.cts +2 -0
- package/libs/components/form/inputs.d.ts +2 -0
- package/libs/components/form/inputs.js +4 -0
- package/libs/components/form/inputs.js.map +1 -0
- package/libs/components/form/textarea.cjs +19 -0
- package/libs/components/form/textarea.cjs.map +1 -0
- package/libs/components/form/textarea.d.cts +29 -0
- package/libs/components/form/textarea.d.ts +29 -0
- package/libs/components/form/textarea.js +4 -0
- package/libs/components/form/textarea.js.map +1 -0
- package/libs/components/heading/heading.cjs +10 -0
- package/libs/components/heading/heading.cjs.map +1 -0
- package/libs/components/heading/heading.d.cts +3 -0
- package/libs/components/heading/heading.d.ts +3 -0
- package/libs/components/heading/heading.js +4 -0
- package/libs/components/heading/heading.js.map +1 -0
- package/libs/components/icons/icon.cjs +19 -0
- package/libs/components/icons/icon.cjs.map +1 -0
- package/libs/{icons-31ace3de.d.ts → components/icons/icon.d.cts} +151 -61
- package/libs/components/icons/icon.d.ts +445 -0
- package/libs/components/icons/icon.js +4 -0
- package/libs/components/icons/icon.js.map +1 -0
- package/libs/components/images/img.css +1 -1
- package/libs/components/images/img.css.map +1 -1
- package/libs/components/images/img.min.css +2 -2
- package/libs/components/link/link.cjs +19 -0
- package/libs/components/link/link.cjs.map +1 -0
- package/libs/components/link/link.d.cts +19 -0
- package/libs/components/link/link.d.ts +19 -0
- package/libs/components/link/link.js +4 -0
- package/libs/components/link/link.js.map +1 -0
- package/libs/components/list/list.cjs +23 -0
- package/libs/components/list/list.cjs.map +1 -0
- package/libs/components/list/list.d.cts +39 -0
- package/libs/components/list/list.d.ts +39 -0
- package/libs/components/list/list.js +4 -0
- package/libs/components/list/list.js.map +1 -0
- package/libs/components/modal.cjs +14 -0
- package/libs/components/modal.cjs.map +1 -0
- package/libs/components/modal.d.cts +35 -0
- package/libs/components/modal.d.ts +35 -0
- package/libs/components/modal.js +5 -0
- package/libs/components/modal.js.map +1 -0
- package/libs/components/nav/nav.cjs +28 -0
- package/libs/components/nav/nav.cjs.map +1 -0
- package/libs/components/nav/nav.d.cts +44 -0
- package/libs/components/nav/nav.d.ts +44 -0
- package/libs/components/nav/nav.js +5 -0
- package/libs/components/nav/nav.js.map +1 -0
- package/libs/components/popover/popover.cjs +23 -0
- package/libs/components/popover/popover.cjs.map +1 -0
- package/libs/components/popover/popover.d.cts +40 -0
- package/libs/components/popover/popover.d.ts +40 -0
- package/libs/components/popover/popover.js +4 -0
- package/libs/components/popover/popover.js.map +1 -0
- package/libs/components/tables/table.cjs +21 -0
- package/libs/components/tables/table.cjs.map +1 -0
- package/libs/components/tables/table.d.cts +36 -0
- package/libs/components/tables/table.d.ts +36 -0
- package/libs/components/tables/table.js +4 -0
- package/libs/components/tables/table.js.map +1 -0
- package/libs/components/text/text.cjs +23 -0
- package/libs/components/text/text.cjs.map +1 -0
- package/libs/components/text/text.d.cts +30 -0
- package/libs/components/text/text.d.ts +30 -0
- package/libs/components/text/text.js +4 -0
- package/libs/components/text/text.js.map +1 -0
- package/libs/heading-3648c538.d.ts +250 -0
- package/libs/hooks.cjs +7 -0
- package/libs/hooks.d.cts +5 -0
- package/libs/hooks.d.ts +5 -0
- package/libs/hooks.js +3 -0
- package/libs/icons.cjs +3 -2
- package/libs/icons.d.cts +3 -1
- package/libs/icons.d.ts +3 -1
- package/libs/icons.js +2 -1
- package/libs/index.cjs +174 -62
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +529 -446
- package/libs/index.d.ts +529 -446
- package/libs/index.js +36 -7
- package/libs/index.js.map +1 -1
- package/libs/inputs-f3a216db.d.ts +45 -0
- package/libs/ui-645f95b5.d.ts +285 -0
- package/package.json +2 -2
- package/src/components/README-UI.mdx +416 -0
- package/src/components/alert/ACCESSIBILITY.md +319 -0
- package/src/components/alert/README.mdx +475 -19
- package/src/components/alert/alert.scss +113 -6
- package/src/components/alert/alert.stories.tsx +372 -0
- package/src/components/alert/alert.test.tsx +762 -0
- package/src/components/alert/alert.tsx +331 -66
- package/src/components/alert/views/alert-actions.tsx +13 -0
- package/src/components/alert/views/alert-content.tsx +17 -0
- package/src/components/alert/views/alert-icon.tsx +53 -0
- package/src/components/alert/views/alert-screen-reader-text.tsx +30 -0
- package/src/components/alert/views/alert-title.tsx +23 -0
- package/src/components/alert/views/alert-view.tsx +158 -0
- package/src/components/alert/views/index.ts +12 -0
- package/src/components/badge/badge.mdx +186 -49
- package/src/components/badge/badge.scss +20 -2
- package/src/components/badge/badge.stories.tsx +160 -14
- package/src/components/badge/badge.test.tsx +179 -0
- package/src/components/badge/badge.tsx +97 -4
- package/src/components/breadcrumbs/README.mdx +364 -45
- package/src/components/breadcrumbs/__snapshots__/breadcrumb.test.tsx.snap +152 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +7 -3
- package/src/components/breadcrumbs/breadcrumb.test.tsx +490 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +427 -170
- package/src/components/button.ts +2 -0
- package/src/components/buttons/button.scss +34 -31
- package/src/components/buttons/button.stories.tsx +35 -0
- package/src/components/card.ts +2 -0
- package/src/components/cards/README.mdx +657 -0
- package/src/components/cards/card.scss +22 -0
- package/src/components/cards/card.stories.tsx +167 -5
- package/src/components/cards/card.test.tsx +360 -20
- package/src/components/cards/card.tsx +200 -79
- package/src/components/cards/card.types.ts +135 -0
- package/src/components/cards/card.utils.ts +79 -0
- package/src/components/details/ACCESSIBILITY-REVIEW-LIVE.md +1050 -0
- package/src/components/details/ACCESSIBILITY-REVIEW.md +502 -0
- package/src/components/details/README.mdx +437 -69
- package/src/components/details/details.scss +16 -0
- package/src/components/details/details.test.tsx +385 -0
- package/src/components/details/details.tsx +101 -69
- package/src/components/details/details.types.ts +76 -0
- package/src/components/dialog/README.mdx +513 -110
- package/src/components/dialog/dialog-modal.tsx +79 -56
- package/src/components/dialog/dialog.scss +53 -3
- package/src/components/dialog/dialog.stories.tsx +10 -7
- package/src/components/dialog/dialog.test.tsx +450 -0
- package/src/components/dialog/dialog.tsx +69 -59
- package/src/components/dialog/dialog.types.ts +133 -0
- package/src/components/dialog/views/dialog-footer.tsx +54 -11
- package/src/components/dialog/views/dialog-header.tsx +20 -15
- package/src/components/heading/heading.stories.tsx +44 -4
- package/src/components/heading/heading.tsx +89 -23
- package/src/components/icons/README.mdx +332 -0
- package/src/components/icons/icon.stories.tsx +74 -1
- package/src/components/icons/icon.tsx +89 -1
- package/src/components/icons/types.ts +47 -0
- package/src/components/images/README.mdx +340 -24
- package/src/components/images/img.scss +19 -3
- package/src/components/images/img.stories.tsx +424 -15
- package/src/components/images/img.test.tsx +354 -25
- package/src/components/images/img.tsx +186 -63
- package/src/components/images/img.types.ts +211 -0
- package/src/components/modal.ts +1 -0
- package/src/components/title/MIGRATION.md +199 -0
- package/src/components/title/README.md +326 -0
- package/src/components/title/README.mdx +452 -0
- package/src/components/title/title.stories.tsx +393 -0
- package/src/components/title/title.test.tsx +251 -0
- package/src/components/title/title.tsx +219 -0
- package/src/components/ui.stories.tsx +894 -0
- package/src/components/ui.test.tsx +559 -0
- package/src/components/ui.tsx +266 -15
- package/src/components/word-count/README.md +240 -0
- package/src/hooks.ts +1 -0
- package/src/index.ts +51 -19
- package/src/sass/_properties.scss +1 -0
- package/src/styles/alert/alert.css +94 -4
- package/src/styles/alert/alert.css.map +1 -1
- package/src/styles/badge/badge.css +20 -2
- package/src/styles/badge/badge.css.map +1 -1
- package/src/styles/buttons/button.css +31 -31
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/cards/card.css +16 -0
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/details/details.css +19 -0
- package/src/styles/details/details.css.map +1 -1
- package/src/styles/dialog/dialog.css +43 -2
- package/src/styles/dialog/dialog.css.map +1 -1
- package/src/styles/images/img.css +15 -3
- package/src/styles/images/img.css.map +1 -1
- package/src/styles/index.css +240 -43
- package/src/styles/index.css.map +1 -1
- package/src/test/setup.d.ts +9 -0
- package/src/test/setup.ts +53 -1
- package/libs/chunk-PWVRDQ3R.js +0 -8
- package/libs/chunk-PWVRDQ3R.js.map +0 -1
- package/libs/chunk-SVS4MX3U.cjs +0 -31
- package/libs/chunk-SVS4MX3U.cjs.map +0 -1
- package/src/components/cards/README.md +0 -80
- package/src/components/dialog/hooks/useClickOutside.ts +0 -33
|
@@ -1,43 +1,359 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Image Components
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Modern, accessible, and performant React image components with built-in support for responsive images, lazy loading, and WCAG 2.1 AA compliance.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Overview
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
This directory contains:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **`<Img />`** - Type-safe image component with responsive image support and error handling
|
|
12
|
+
- **`<Figure />`** - Semantic figure component with image and caption
|
|
13
|
+
- **CSS custom properties** - Flexible theming system using SCSS
|
|
14
|
+
- **Comprehensive tests** - 25+ tests covering accessibility, performance, and edge cases
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
---
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## Quick Start
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
```tsx
|
|
21
|
+
import { Img } from '@fpkit/acss'
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
// Basic usage
|
|
24
|
+
<Img src="/photo.jpg" alt="Beautiful landscape" width={800} />
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
// Decorative image
|
|
27
|
+
<Img src="/border.png" alt="" />
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
// Responsive image
|
|
30
|
+
<Img
|
|
31
|
+
src="/photo.jpg"
|
|
32
|
+
srcSet="/photo-320w.jpg 320w, /photo-640w.jpg 640w, /photo-1024w.jpg 1024w"
|
|
33
|
+
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px"
|
|
34
|
+
alt="Team photo"
|
|
35
|
+
/>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Accessibility (WCAG 2.1 AA)
|
|
41
|
+
|
|
42
|
+
### Decorative Images
|
|
43
|
+
|
|
44
|
+
Images that are purely visual decoration should use an empty `alt` attribute:
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// ✅ GOOD: Decorative border
|
|
48
|
+
<Img src="/decorative-border.png" alt="" />
|
|
49
|
+
|
|
50
|
+
// ✅ GOOD: Background pattern
|
|
51
|
+
<Img src="/pattern.svg" alt="" />
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Semantic Images
|
|
55
|
+
|
|
56
|
+
Images that convey meaning must have descriptive alt text:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
// ✅ GOOD: Informative chart
|
|
60
|
+
<Img
|
|
61
|
+
src="/sales-chart.png"
|
|
62
|
+
alt="Sales chart showing 30% revenue growth in Q4 2024"
|
|
63
|
+
/>
|
|
64
|
+
|
|
65
|
+
// ✅ GOOD: Product photo
|
|
66
|
+
<Img
|
|
67
|
+
src="/laptop.jpg"
|
|
68
|
+
alt="Silver MacBook Pro 14-inch on wooden desk"
|
|
69
|
+
/>
|
|
70
|
+
|
|
71
|
+
// ❌ BAD: Generic or missing alt text
|
|
72
|
+
<Img src="/chart.png" alt="chart" />
|
|
73
|
+
<Img src="/photo.jpg" />
|
|
74
|
+
```
|
|
24
75
|
|
|
25
|
-
|
|
76
|
+
---
|
|
26
77
|
|
|
27
|
-
|
|
78
|
+
## Performance Optimization
|
|
79
|
+
|
|
80
|
+
### Lazy Loading (Default)
|
|
81
|
+
|
|
82
|
+
By default, images use lazy loading to improve page load performance:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// Lazy loaded automatically
|
|
86
|
+
<Img src="/photo.jpg" alt="Photo" />
|
|
87
|
+
|
|
88
|
+
// Explicit lazy loading
|
|
89
|
+
<Img src="/photo.jpg" alt="Photo" loading="lazy" />
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Eager Loading for Hero Images
|
|
93
|
+
|
|
94
|
+
Use eager loading for above-the-fold images:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<Img
|
|
98
|
+
src="/hero.jpg"
|
|
99
|
+
alt="Hero banner"
|
|
100
|
+
loading="eager"
|
|
101
|
+
fetchpriority="high"
|
|
102
|
+
/>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Responsive Images
|
|
106
|
+
|
|
107
|
+
Use `srcSet` and `sizes` for responsive images:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<Img
|
|
111
|
+
src="/photo.jpg"
|
|
112
|
+
srcSet="
|
|
113
|
+
/photo-320w.jpg 320w,
|
|
114
|
+
/photo-640w.jpg 640w,
|
|
115
|
+
/photo-1024w.jpg 1024w
|
|
116
|
+
"
|
|
117
|
+
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px"
|
|
118
|
+
alt="Responsive image adapts to viewport"
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
28
121
|
|
|
29
|
-
|
|
30
|
-
import Img from './components/images/img';
|
|
31
|
-
import Figure from './components/images/figure';
|
|
122
|
+
### Async Decoding
|
|
32
123
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<Img src="/
|
|
37
|
-
|
|
124
|
+
Prevent blocking the main thread during image decoding:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
<Img src="/large-photo.jpg" alt="Large photo" decoding="async" />
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Error Handling
|
|
133
|
+
|
|
134
|
+
### Default Placeholder
|
|
135
|
+
|
|
136
|
+
The component automatically falls back to a placeholder on error:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<Img src="/might-fail.jpg" alt="Photo" />
|
|
140
|
+
// Falls back to default placeholder if image fails
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Custom Placeholder
|
|
144
|
+
|
|
145
|
+
Provide a custom fallback image:
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<Img
|
|
149
|
+
src="/photo.jpg"
|
|
150
|
+
placeholder="/fallback.png"
|
|
151
|
+
alt="Profile photo"
|
|
152
|
+
/>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Custom Error Handler
|
|
156
|
+
|
|
157
|
+
Handle errors with custom logic:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
<Img
|
|
161
|
+
src="/photo.jpg"
|
|
162
|
+
alt="Photo"
|
|
163
|
+
onError={(e) => {
|
|
164
|
+
console.error('Image failed:', e.currentTarget.src)
|
|
165
|
+
// Log to analytics, show notification, etc.
|
|
166
|
+
}}
|
|
167
|
+
/>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Common Use Cases
|
|
173
|
+
|
|
174
|
+
### Profile/Avatar Images
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<Img
|
|
178
|
+
src="/avatar.jpg"
|
|
179
|
+
alt="User profile photo"
|
|
180
|
+
width={150}
|
|
181
|
+
height={150}
|
|
182
|
+
loading="eager"
|
|
183
|
+
styles={{ borderRadius: '50%' }}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Gallery Images
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '1rem' }}>
|
|
191
|
+
<Img src="/photo1.jpg" alt="Gallery image 1" width={400} />
|
|
192
|
+
<Img src="/photo2.jpg" alt="Gallery image 2" width={400} />
|
|
193
|
+
<Img src="/photo3.jpg" alt="Gallery image 3" width={400} />
|
|
38
194
|
</div>
|
|
39
|
-
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Figure with Caption
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
import { Figure } from '@fpkit/acss'
|
|
201
|
+
|
|
202
|
+
<Figure
|
|
203
|
+
src="/chart.jpg"
|
|
204
|
+
alt="Q4 sales performance chart"
|
|
205
|
+
caption="Sales increased by 30% in Q4 2024"
|
|
206
|
+
/>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## API Reference
|
|
212
|
+
|
|
213
|
+
### Img Props
|
|
214
|
+
|
|
215
|
+
| Prop | Type | Default | Description |
|
|
216
|
+
|------|------|---------|-------------|
|
|
217
|
+
| `src` | `string` | `"//"` | Image source URL |
|
|
218
|
+
| `alt` | `string` | `undefined` | Alternative text (empty for decorative, descriptive for semantic) |
|
|
219
|
+
| `width` | `number \| string` | `480` | Image width |
|
|
220
|
+
| `height` | `number \| string` | `"auto"` | Image height |
|
|
221
|
+
| `loading` | `"lazy" \| "eager"` | `"lazy"` | Loading strategy |
|
|
222
|
+
| `srcSet` | `string` | `undefined` | Responsive image sources |
|
|
223
|
+
| `sizes` | `string` | `undefined` | Media conditions for responsive images |
|
|
224
|
+
| `placeholder` | `string` | Auto-generated | Fallback image URL |
|
|
225
|
+
| `fetchpriority` | `"low" \| "high" \| "auto"` | `"low"` | Fetch priority hint |
|
|
226
|
+
| `decoding` | `"sync" \| "async" \| "auto"` | `"auto"` | Decoding hint |
|
|
227
|
+
| `onError` | `function` | `undefined` | Error event handler |
|
|
228
|
+
| `onLoad` | `function` | `undefined` | Load event handler |
|
|
229
|
+
| `styles` | `CSSProperties` | `undefined` | Inline styles |
|
|
230
|
+
|
|
231
|
+
All native `<img>` attributes are supported via spread props.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Styling with CSS Custom Properties
|
|
236
|
+
|
|
237
|
+
The component uses CSS custom properties for theming:
|
|
238
|
+
|
|
239
|
+
```scss
|
|
240
|
+
img[alt] {
|
|
241
|
+
/* Override these in your CSS */
|
|
242
|
+
--img-max-width: 100%;
|
|
243
|
+
--img-height: auto;
|
|
244
|
+
--img-object-fit: cover;
|
|
245
|
+
--img-object-position: center;
|
|
246
|
+
--img-aspect-ratio: auto 2/3;
|
|
247
|
+
--img-display: inline-block;
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Example customization:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
<Img
|
|
255
|
+
src="/photo.jpg"
|
|
256
|
+
alt="Photo"
|
|
257
|
+
styles={{
|
|
258
|
+
'--img-object-fit': 'contain',
|
|
259
|
+
'--img-aspect-ratio': '16/9',
|
|
260
|
+
}}
|
|
261
|
+
/>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Migration from v1.x
|
|
267
|
+
|
|
268
|
+
### Breaking Changes
|
|
269
|
+
|
|
270
|
+
**Event handler props renamed:**
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
// ❌ Old API (v1.x)
|
|
274
|
+
<Img imgError={handleError} imgLoaded={handleLoad} />
|
|
275
|
+
|
|
276
|
+
// ✅ New API (v2.x)
|
|
277
|
+
<Img onError={handleError} onLoad={handleLoad} />
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Type export renamed:**
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
// ❌ Old import
|
|
284
|
+
import { ImageProps } from '@fpkit/acss'
|
|
285
|
+
|
|
286
|
+
// ✅ New import
|
|
287
|
+
import type { ImgProps } from '@fpkit/acss'
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Files in This Directory
|
|
293
|
+
|
|
294
|
+
### Component Files
|
|
295
|
+
|
|
296
|
+
- **`img.tsx`** - Main Img component with responsive image support
|
|
297
|
+
- **`img.types.ts`** - TypeScript type definitions and interfaces
|
|
298
|
+
- **`figure.tsx`** - Figure component for images with captions
|
|
299
|
+
|
|
300
|
+
### Styling
|
|
301
|
+
|
|
302
|
+
- **`img.scss`** - SCSS source with CSS custom properties
|
|
303
|
+
- Compiled to `libs/components/images/img.css` during build
|
|
304
|
+
|
|
305
|
+
### Testing & Documentation
|
|
306
|
+
|
|
307
|
+
- **`img.test.tsx`** - 25 comprehensive unit tests
|
|
308
|
+
- **`img.stories.tsx`** - 11 Storybook stories with examples
|
|
309
|
+
- **`figure.stories.tsx`** - Figure component stories
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## TypeScript Support
|
|
314
|
+
|
|
315
|
+
Full TypeScript support with comprehensive type definitions:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { Img, type ImgProps } from '@fpkit/acss'
|
|
319
|
+
|
|
320
|
+
// Custom component extending Img
|
|
321
|
+
interface CustomImgProps extends ImgProps {
|
|
322
|
+
caption?: string
|
|
40
323
|
}
|
|
324
|
+
|
|
325
|
+
const CustomImg: React.FC<CustomImgProps> = ({ caption, ...props }) => (
|
|
326
|
+
<figure>
|
|
327
|
+
<Img {...props} />
|
|
328
|
+
{caption && <figcaption>{caption}</figcaption>}
|
|
329
|
+
</figure>
|
|
330
|
+
)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Testing
|
|
336
|
+
|
|
337
|
+
Run tests for the Img component:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
npm test -- img.test.tsx
|
|
41
341
|
```
|
|
42
342
|
|
|
43
|
-
|
|
343
|
+
All 25 tests should pass ✅
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Related Components
|
|
348
|
+
|
|
349
|
+
- **`<Figure />`** - Semantic figure with caption support
|
|
350
|
+
- **`<UI />`** - Base polymorphic component used internally
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Resources
|
|
355
|
+
|
|
356
|
+
- [WCAG 2.1 Non-text Content Guidelines](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html)
|
|
357
|
+
- [MDN: Responsive Images](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)
|
|
358
|
+
- [MDN: Image loading attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#loading)
|
|
359
|
+
- [Component Storybook](../../stories) - View all examples in Storybook
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image component styles
|
|
3
|
+
*
|
|
4
|
+
* Applies to all images with alt attribute (both decorative alt="" and semantic).
|
|
5
|
+
* Uses CSS custom properties for flexible theming and responsive behavior.
|
|
6
|
+
*/
|
|
1
7
|
img[alt] {
|
|
8
|
+
/* CSS Custom Properties - Override these for customization */
|
|
2
9
|
--img-max-width: 100%;
|
|
3
10
|
--img-height: auto;
|
|
4
11
|
--img-object-fit: cover;
|
|
@@ -6,17 +13,26 @@ img[alt] {
|
|
|
6
13
|
--img-aspect-ratio: auto 2/3;
|
|
7
14
|
--img-display: inline-block;
|
|
8
15
|
|
|
16
|
+
/* Layout - Responsive by default */
|
|
9
17
|
max-width: var(--img-max-width);
|
|
10
|
-
max-inline-size: var(--img-max-width);
|
|
18
|
+
max-inline-size: var(--img-max-width); /* Logical property for i18n */
|
|
11
19
|
block-size: var(--img-height);
|
|
20
|
+
display: var(--img-display);
|
|
21
|
+
vertical-align: middle;
|
|
22
|
+
|
|
23
|
+
/* Object fitting for responsive images */
|
|
12
24
|
object-fit: var(--img-object-fit);
|
|
13
25
|
object-position: var(--img-object-position);
|
|
14
26
|
aspect-ratio: var(--img-aspect-ratio);
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
|
|
28
|
+
/* Accessibility - Italic font for broken image alt text */
|
|
17
29
|
font-style: italic;
|
|
30
|
+
|
|
31
|
+
/* Background for loading state */
|
|
18
32
|
background-size: cover;
|
|
19
33
|
background-repeat: no-repeat;
|
|
34
|
+
|
|
35
|
+
/* Shape margin for text wrapping */
|
|
20
36
|
shape-margin: var(--spc-3);
|
|
21
37
|
}
|
|
22
38
|
|