@fpkit/acss 3.1.1 → 3.2.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.
- package/libs/{chunk-2NRIP6RB.cjs → chunk-2C3YLBWP.cjs} +3 -3
- package/libs/{chunk-NWJDAHP6.cjs → chunk-2GJHKWEK.cjs} +3 -3
- package/libs/{chunk-FVROL3V5.js → chunk-2JCDEC32.js} +3 -3
- package/libs/{chunk-IRLFZ3OL.js → chunk-3XJC4XUG.js} +2 -2
- package/libs/{chunk-L6PRDL6F.cjs → chunk-5CJPTDK3.cjs} +3 -3
- package/libs/{chunk-E4OSROCA.cjs → chunk-5QSNJQVH.cjs} +3 -3
- package/libs/{chunk-O3JIHC5M.cjs → chunk-6BUJZ4DJ.cjs} +3 -3
- package/libs/{chunk-WXBFBWYF.cjs → chunk-AFINOD2L.cjs} +3 -3
- package/libs/{chunk-HRRHPLER.js → chunk-AWZLSWDO.js} +2 -2
- package/libs/chunk-DDSXKOUB.js +7 -0
- package/libs/chunk-DDSXKOUB.js.map +1 -0
- package/libs/{chunk-CWRNJA4P.js → chunk-DIJBIOFE.js} +3 -3
- package/libs/chunk-EJ6KYBFE.cjs +13 -0
- package/libs/chunk-EJ6KYBFE.cjs.map +1 -0
- package/libs/{chunk-GUJSMQ3V.cjs → chunk-EKJYOCLY.cjs} +3 -3
- package/libs/{chunk-X5RKCLDC.cjs → chunk-F64GE6RG.cjs} +4 -4
- package/libs/{chunk-5RAWNUVD.js → chunk-IBUTNPTQ.js} +2 -2
- package/libs/{chunk-ZFJ4U45S.js → chunk-KDMX3FAW.js} +2 -2
- package/libs/{chunk-DYFAUAB7.cjs → chunk-LXODKKA3.cjs} +4 -4
- package/libs/{chunk-MPTMPBFT.js → chunk-M7JLT62Q.js} +2 -2
- package/libs/{chunk-IQ76HGVP.js → chunk-MBWI67UT.js} +2 -2
- package/libs/{chunk-O5XAJ7BY.cjs → chunk-NCGVF2QS.cjs} +4 -4
- package/libs/{chunk-W2UIN7EV.cjs → chunk-NPWHQVYB.cjs} +3 -3
- package/libs/chunk-OU52NIKA.js +8 -0
- package/libs/chunk-OU52NIKA.js.map +1 -0
- package/libs/{chunk-43TK2ICH.js → chunk-PMWL5XZ4.js} +3 -3
- package/libs/{chunk-KVKQLRJG.js → chunk-TF3GQKOY.js} +2 -2
- package/libs/{chunk-IEB64SWY.js → chunk-U5VA34SU.js} +2 -2
- package/libs/{chunk-EE3ZWSBY.cjs → chunk-URBGDUFN.cjs} +6 -6
- package/libs/chunk-WWPLBWCQ.cjs +18 -0
- package/libs/chunk-WWPLBWCQ.cjs.map +1 -0
- package/libs/{chunk-TPIB3RQP.js → chunk-ZF6Y7W57.js} +5 -5
- package/libs/component-props-50e69975.d.ts +66 -0
- package/libs/components/box/box.css +1 -0
- package/libs/components/box/box.css.map +1 -0
- package/libs/components/box/box.min.css +3 -0
- package/libs/components/breadcrumbs/breadcrumb.cjs +6 -6
- package/libs/components/breadcrumbs/breadcrumb.js +3 -3
- package/libs/components/button.cjs +4 -4
- package/libs/components/button.d.cts +10 -3
- package/libs/components/button.d.ts +10 -3
- package/libs/components/button.js +2 -2
- package/libs/components/card.cjs +7 -7
- package/libs/components/card.d.cts +13 -85
- package/libs/components/card.d.ts +13 -85
- package/libs/components/card.js +2 -2
- 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/cluster/cluster.css +1 -0
- package/libs/components/cluster/cluster.css.map +1 -0
- package/libs/components/cluster/cluster.min.css +3 -0
- package/libs/components/dialog/dialog.cjs +7 -7
- package/libs/components/dialog/dialog.js +5 -5
- package/libs/components/form/fields.cjs +4 -4
- package/libs/components/form/fields.js +2 -2
- package/libs/components/form/textarea.cjs +4 -4
- package/libs/components/form/textarea.js +2 -2
- package/libs/components/grid/grid.css +1 -0
- package/libs/components/grid/grid.css.map +1 -0
- package/libs/components/grid/grid.min.css +3 -0
- package/libs/components/heading/heading.cjs +3 -3
- package/libs/components/heading/heading.js +2 -2
- package/libs/components/icons/icon.cjs +4 -4
- package/libs/components/icons/icon.d.cts +2 -2
- package/libs/components/icons/icon.d.ts +2 -2
- package/libs/components/icons/icon.js +2 -2
- package/libs/components/link/link.cjs +6 -6
- package/libs/components/link/link.js +2 -2
- package/libs/components/list/list.cjs +5 -5
- package/libs/components/list/list.js +2 -2
- package/libs/components/modal.cjs +4 -4
- package/libs/components/modal.d.cts +1 -1
- package/libs/components/modal.d.ts +1 -1
- package/libs/components/modal.js +3 -3
- package/libs/components/nav/nav.cjs +7 -7
- package/libs/components/nav/nav.js +3 -3
- package/libs/components/stack/stack.css +1 -0
- package/libs/components/stack/stack.css.map +1 -0
- package/libs/components/stack/stack.min.css +3 -0
- package/libs/components/tables/table.d.cts +1 -1
- package/libs/components/tables/table.d.ts +1 -1
- package/libs/components/text/text.cjs +5 -5
- package/libs/components/text/text.js +2 -2
- package/libs/hooks.cjs +4 -4
- package/libs/hooks.js +3 -3
- package/libs/{icons-287fce3a.d.ts → icons-df8e744f.d.ts} +1 -1
- package/libs/icons.cjs +3 -3
- package/libs/icons.d.cts +2 -2
- package/libs/icons.d.ts +2 -2
- package/libs/icons.js +2 -2
- package/libs/index.cjs +64 -63
- 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 +923 -4
- package/libs/index.d.ts +923 -4
- package/libs/index.js +28 -28
- package/libs/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/alert/STYLES.mdx +790 -0
- package/src/components/badge/STYLES.mdx +610 -0
- package/src/components/box/README.mdx +401 -0
- package/src/components/box/STYLES.mdx +360 -0
- package/src/components/box/box.scss +245 -0
- package/src/components/box/box.stories.tsx +395 -0
- package/src/components/box/box.test.tsx +425 -0
- package/src/components/box/box.tsx +170 -0
- package/src/components/box/box.types.ts +166 -0
- package/src/components/breadcrumbs/STYLES.mdx +99 -0
- package/src/components/buttons/STYLES.mdx +766 -0
- package/src/components/cards/STYLES.mdx +835 -0
- package/src/components/cards/card.scss +30 -21
- package/src/components/cards/card.stories.tsx +120 -80
- package/src/components/cards/card.tsx +14 -4
- package/src/components/cards/card.types.ts +13 -0
- package/src/components/cluster/README.mdx +595 -0
- package/src/components/cluster/STYLES.mdx +626 -0
- package/src/components/cluster/cluster.scss +86 -0
- package/src/components/cluster/cluster.stories.tsx +385 -0
- package/src/components/cluster/cluster.test.tsx +655 -0
- package/src/components/cluster/cluster.tsx +94 -0
- package/src/components/cluster/cluster.types.ts +75 -0
- package/src/components/details/STYLES.mdx +445 -0
- package/src/components/dialog/STYLES.mdx +888 -0
- package/src/components/flexbox/STYLES.mdx +1 -1
- package/src/components/form/STYLES.mdx +821 -0
- package/src/components/grid/README.mdx +709 -0
- package/src/components/grid/STYLES.mdx +785 -0
- package/src/components/grid/grid.scss +287 -0
- package/src/components/grid/grid.stories.tsx +486 -0
- package/src/components/grid/grid.test.tsx +981 -0
- package/src/components/grid/grid.tsx +222 -0
- package/src/components/grid/grid.types.ts +344 -0
- package/src/components/icons/STYLES.mdx +56 -0
- package/src/components/images/STYLES.mdx +75 -0
- package/src/components/layout/STYLES.mdx +556 -0
- package/src/components/link/STYLES.mdx +75 -0
- package/src/components/list/STYLES.mdx +631 -0
- package/src/components/nav/STYLES.mdx +460 -0
- package/src/components/progress/STYLES.mdx +64 -0
- package/src/components/stack/README.mdx +400 -0
- package/src/components/stack/STYLES.mdx +414 -0
- package/src/components/stack/stack.scss +109 -0
- package/src/components/stack/stack.stories.tsx +559 -0
- package/src/components/stack/stack.test.tsx +426 -0
- package/src/components/stack/stack.tsx +141 -0
- package/src/components/stack/stack.types.ts +133 -0
- package/src/components/tag/STYLES.mdx +105 -0
- package/src/components/text-to-speech/STYLES.mdx +80 -0
- package/src/components/ui.tsx +3 -3
- package/src/index.scss +7 -2
- package/src/index.ts +305 -12
- package/src/sass/GLOBALS-STYLES.md +631 -0
- package/src/sass/_globals.scss +45 -24
- package/src/sass/_styles.scss +2 -2
- package/src/styles/box/box.css +220 -0
- package/src/styles/box/box.css.map +1 -0
- package/src/styles/cards/card.css +23 -17
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/cluster/cluster.css +71 -0
- package/src/styles/cluster/cluster.css.map +1 -0
- package/src/styles/grid/grid.css +238 -0
- package/src/styles/grid/grid.css.map +1 -0
- package/src/styles/index.css +668 -49
- package/src/styles/index.css.map +1 -1
- package/src/styles/stack/stack.css +86 -0
- package/src/styles/stack/stack.css.map +1 -0
- package/src/types/component-props.ts +42 -14
- package/src/types/layout-primitives.ts +48 -0
- package/src/types/shared.ts +10 -26
- package/libs/chunk-ENTCUJ3A.cjs +0 -13
- package/libs/chunk-ENTCUJ3A.cjs.map +0 -1
- package/libs/chunk-HHLNOC5T.js +0 -7
- package/libs/chunk-HHLNOC5T.js.map +0 -1
- package/libs/chunk-KK47SYZI.js +0 -8
- package/libs/chunk-KK47SYZI.js.map +0 -1
- package/libs/chunk-W5TKWBFC.cjs +0 -18
- package/libs/chunk-W5TKWBFC.cjs.map +0 -1
- package/libs/component-props-67d978a2.d.ts +0 -38
- /package/libs/{chunk-2NRIP6RB.cjs.map → chunk-2C3YLBWP.cjs.map} +0 -0
- /package/libs/{chunk-NWJDAHP6.cjs.map → chunk-2GJHKWEK.cjs.map} +0 -0
- /package/libs/{chunk-FVROL3V5.js.map → chunk-2JCDEC32.js.map} +0 -0
- /package/libs/{chunk-IRLFZ3OL.js.map → chunk-3XJC4XUG.js.map} +0 -0
- /package/libs/{chunk-L6PRDL6F.cjs.map → chunk-5CJPTDK3.cjs.map} +0 -0
- /package/libs/{chunk-E4OSROCA.cjs.map → chunk-5QSNJQVH.cjs.map} +0 -0
- /package/libs/{chunk-O3JIHC5M.cjs.map → chunk-6BUJZ4DJ.cjs.map} +0 -0
- /package/libs/{chunk-WXBFBWYF.cjs.map → chunk-AFINOD2L.cjs.map} +0 -0
- /package/libs/{chunk-HRRHPLER.js.map → chunk-AWZLSWDO.js.map} +0 -0
- /package/libs/{chunk-CWRNJA4P.js.map → chunk-DIJBIOFE.js.map} +0 -0
- /package/libs/{chunk-GUJSMQ3V.cjs.map → chunk-EKJYOCLY.cjs.map} +0 -0
- /package/libs/{chunk-X5RKCLDC.cjs.map → chunk-F64GE6RG.cjs.map} +0 -0
- /package/libs/{chunk-5RAWNUVD.js.map → chunk-IBUTNPTQ.js.map} +0 -0
- /package/libs/{chunk-ZFJ4U45S.js.map → chunk-KDMX3FAW.js.map} +0 -0
- /package/libs/{chunk-DYFAUAB7.cjs.map → chunk-LXODKKA3.cjs.map} +0 -0
- /package/libs/{chunk-MPTMPBFT.js.map → chunk-M7JLT62Q.js.map} +0 -0
- /package/libs/{chunk-IQ76HGVP.js.map → chunk-MBWI67UT.js.map} +0 -0
- /package/libs/{chunk-O5XAJ7BY.cjs.map → chunk-NCGVF2QS.cjs.map} +0 -0
- /package/libs/{chunk-W2UIN7EV.cjs.map → chunk-NPWHQVYB.cjs.map} +0 -0
- /package/libs/{chunk-43TK2ICH.js.map → chunk-PMWL5XZ4.js.map} +0 -0
- /package/libs/{chunk-KVKQLRJG.js.map → chunk-TF3GQKOY.js.map} +0 -0
- /package/libs/{chunk-IEB64SWY.js.map → chunk-U5VA34SU.js.map} +0 -0
- /package/libs/{chunk-EE3ZWSBY.cjs.map → chunk-URBGDUFN.cjs.map} +0 -0
- /package/libs/{chunk-TPIB3RQP.js.map → chunk-ZF6Y7W57.js.map} +0 -0
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
// Base card properties
|
|
3
|
-
--card-padding:
|
|
4
|
-
--card-bg: #
|
|
3
|
+
--card-padding: 1.5rem;
|
|
4
|
+
--card-bg: var(--color-surface, #ffffff);
|
|
5
5
|
--card-radius: calc(var(--card-padding) / 4);
|
|
6
|
-
--card-position: relative;
|
|
7
|
-
--card-display: flex;
|
|
8
|
-
--card-direction: column;
|
|
9
6
|
--card-gap: 1rem;
|
|
10
7
|
|
|
11
8
|
// Element-specific variables (NEW - for complex card layouts)
|
|
12
9
|
--card-header-padding: 1rem 1.5rem;
|
|
13
|
-
--card-header-bg: #f8f9fa;
|
|
14
|
-
--card-header-border-bottom:
|
|
10
|
+
--card-header-bg: var(--color-surface-secondary, #f8f9fa);
|
|
11
|
+
--card-header-border-bottom-width: 0.0625rem;
|
|
12
|
+
--card-header-border-bottom-style: solid;
|
|
13
|
+
--card-header-border-bottom-color: var(--color-border, #dee2e6);
|
|
15
14
|
|
|
16
15
|
--card-body-padding: 1.5rem;
|
|
17
16
|
|
|
18
17
|
--card-footer-padding: 1rem 1.5rem;
|
|
19
|
-
--card-footer-bg: #f8f9fa;
|
|
20
|
-
--card-footer-border-top:
|
|
18
|
+
--card-footer-bg: var(--color-surface-secondary, #f8f9fa);
|
|
19
|
+
--card-footer-border-top-width: 0.0625rem;
|
|
20
|
+
--card-footer-border-top-style: solid;
|
|
21
|
+
--card-footer-border-top-color: var(--color-border, #dee2e6);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
[data-card],
|
|
24
|
-
[data-component~=
|
|
25
|
-
display:
|
|
26
|
-
flex-direction:
|
|
25
|
+
[data-component~="card"] {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
27
28
|
gap: var(--card-gap);
|
|
28
29
|
border-radius: var(--card-radius);
|
|
30
|
+
border: var(--card-border, 0.0625rem solid rgba(0, 0, 0, 0.08));
|
|
29
31
|
background-color: var(--card-bg);
|
|
30
32
|
text-align: var(--card-align, left);
|
|
31
|
-
|
|
33
|
+
|
|
32
34
|
h3,
|
|
33
35
|
h2 {
|
|
34
36
|
margin-block-end: 0;
|
|
@@ -47,10 +49,11 @@
|
|
|
47
49
|
padding-inline: var(--card-padding);
|
|
48
50
|
}
|
|
49
51
|
> *:last-child:not(img) {
|
|
50
|
-
// margin-block-end: 0;
|
|
51
52
|
padding-block-end: var(--card-padding);
|
|
52
53
|
}
|
|
53
54
|
> *:first-child:not(img) {
|
|
55
|
+
// Reduced top padding to account for heading's inherent spacing
|
|
56
|
+
// Prevents excessive whitespace above titles
|
|
54
57
|
padding-block-start: calc(var(--card-padding) - 0.5rem);
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -59,7 +62,7 @@
|
|
|
59
62
|
> [data-card-header] {
|
|
60
63
|
padding: var(--card-header-padding);
|
|
61
64
|
background-color: var(--card-header-bg);
|
|
62
|
-
border-bottom: var(--card-header-border-bottom);
|
|
65
|
+
border-bottom: var(--card-header-border-bottom-width) var(--card-header-border-bottom-style) var(--card-header-border-bottom-color);
|
|
63
66
|
border-radius: var(--card-radius) var(--card-radius) 0 0;
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -72,24 +75,31 @@
|
|
|
72
75
|
> [data-card-footer] {
|
|
73
76
|
padding: var(--card-footer-padding);
|
|
74
77
|
background-color: var(--card-footer-bg);
|
|
75
|
-
border-top: var(--card-footer-border-top);
|
|
78
|
+
border-top: var(--card-footer-border-top-width) var(--card-footer-border-top-style) var(--card-footer-border-top-color);
|
|
76
79
|
border-radius: 0 0 var(--card-radius) var(--card-radius);
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
// Interactive card styles - WCAG 2.4.7 compliant focus indicators
|
|
81
84
|
[data-card="interactive"] {
|
|
85
|
+
--card-transition-duration: 0.2s;
|
|
86
|
+
--card-transition-timing: ease;
|
|
87
|
+
--card-hover-lift: -0.125rem;
|
|
88
|
+
--card-hover-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
|
|
89
|
+
|
|
82
90
|
cursor: pointer;
|
|
83
|
-
transition:
|
|
91
|
+
transition:
|
|
92
|
+
box-shadow var(--card-transition-duration) var(--card-transition-timing),
|
|
93
|
+
transform var(--card-transition-duration) var(--card-transition-timing);
|
|
84
94
|
|
|
85
95
|
&:hover {
|
|
86
|
-
transform: translateY(-
|
|
87
|
-
box-shadow:
|
|
96
|
+
transform: translateY(var(--card-hover-lift));
|
|
97
|
+
box-shadow: var(--card-hover-shadow);
|
|
88
98
|
}
|
|
89
99
|
|
|
90
100
|
// Visible focus indicator with 3:1 minimum contrast (WCAG 2.4.7)
|
|
91
101
|
&:focus-visible {
|
|
92
|
-
outline: 0.125rem solid var(--focus
|
|
102
|
+
outline: 0.125rem solid var(--color-focus, #0066cc);
|
|
93
103
|
outline-offset: 0.125rem;
|
|
94
104
|
}
|
|
95
105
|
|
|
@@ -98,4 +108,3 @@
|
|
|
98
108
|
outline: none;
|
|
99
109
|
}
|
|
100
110
|
}
|
|
101
|
-
|
|
@@ -10,26 +10,28 @@ const meta: Meta<typeof Card> = {
|
|
|
10
10
|
component: Card,
|
|
11
11
|
args: {
|
|
12
12
|
children: <p>{content}</p>,
|
|
13
|
+
classes: "shadow-md",
|
|
13
14
|
},
|
|
14
15
|
argTypes: {
|
|
15
16
|
as: {
|
|
16
|
-
control:
|
|
17
|
-
options: [
|
|
18
|
-
description:
|
|
17
|
+
control: "select",
|
|
18
|
+
options: ["div", "article", "section", "aside"],
|
|
19
|
+
description: "HTML element to render",
|
|
19
20
|
},
|
|
20
21
|
interactive: {
|
|
21
|
-
control:
|
|
22
|
-
description:
|
|
22
|
+
control: "boolean",
|
|
23
|
+
description: "Enable keyboard navigation and button semantics",
|
|
23
24
|
},
|
|
24
25
|
role: {
|
|
25
|
-
control:
|
|
26
|
-
description:
|
|
26
|
+
control: "text",
|
|
27
|
+
description: "ARIA role attribute",
|
|
27
28
|
},
|
|
28
29
|
},
|
|
29
30
|
parameters: {
|
|
30
31
|
docs: {
|
|
31
32
|
description: {
|
|
32
|
-
component:
|
|
33
|
+
component:
|
|
34
|
+
"A flexible, accessible card component with compound component pattern. Supports polymorphic rendering, interactive variants, and WCAG 2.1 AA compliance.",
|
|
33
35
|
},
|
|
34
36
|
},
|
|
35
37
|
},
|
|
@@ -171,13 +173,13 @@ export const FlexibleContent: Story = {
|
|
|
171
173
|
export const InteractiveCard: Story = {
|
|
172
174
|
args: {
|
|
173
175
|
interactive: true,
|
|
174
|
-
|
|
176
|
+
"aria-label": "View product details",
|
|
175
177
|
},
|
|
176
178
|
render: (args) => (
|
|
177
179
|
<Card
|
|
178
180
|
{...args}
|
|
179
|
-
onClick={() => alert(
|
|
180
|
-
style={{ cursor:
|
|
181
|
+
onClick={() => alert("Card clicked!")}
|
|
182
|
+
style={{ cursor: "pointer" }}
|
|
181
183
|
>
|
|
182
184
|
<Card.Title>Interactive Product Card</Card.Title>
|
|
183
185
|
<Card.Content>
|
|
@@ -185,12 +187,12 @@ export const InteractiveCard: Story = {
|
|
|
185
187
|
This card is fully interactive! Click anywhere or use your keyboard
|
|
186
188
|
(Tab to focus, Enter or Space to activate) to trigger the action.
|
|
187
189
|
</p>
|
|
188
|
-
<p style={{ fontSize:
|
|
190
|
+
<p style={{ fontSize: "0.875rem", color: "#666", marginTop: "0.5rem" }}>
|
|
189
191
|
Try it: Tab to focus this card, then press Enter or Space.
|
|
190
192
|
</p>
|
|
191
193
|
</Card.Content>
|
|
192
194
|
<Card.Footer>
|
|
193
|
-
<span style={{ color:
|
|
195
|
+
<span style={{ color: "#007bff", fontWeight: "bold" }}>
|
|
194
196
|
Click to learn more →
|
|
195
197
|
</span>
|
|
196
198
|
</Card.Footer>
|
|
@@ -199,7 +201,8 @@ export const InteractiveCard: Story = {
|
|
|
199
201
|
parameters: {
|
|
200
202
|
docs: {
|
|
201
203
|
description: {
|
|
202
|
-
story:
|
|
204
|
+
story:
|
|
205
|
+
"Interactive cards support full keyboard navigation (Enter/Space keys) and automatically receive proper ARIA attributes for accessibility.",
|
|
203
206
|
},
|
|
204
207
|
},
|
|
205
208
|
},
|
|
@@ -217,7 +220,7 @@ export const AccessibleCard: Story = {
|
|
|
217
220
|
This card uses <code>aria-labelledby</code> to connect the title with
|
|
218
221
|
the card container, providing an accessible name for screen readers.
|
|
219
222
|
</p>
|
|
220
|
-
<p style={{ fontSize:
|
|
223
|
+
<p style={{ fontSize: "0.875rem", color: "#666", marginTop: "0.5rem" }}>
|
|
221
224
|
Screen readers will announce: "Featured Product, article"
|
|
222
225
|
</p>
|
|
223
226
|
</Card.Content>
|
|
@@ -229,7 +232,8 @@ export const AccessibleCard: Story = {
|
|
|
229
232
|
parameters: {
|
|
230
233
|
docs: {
|
|
231
234
|
description: {
|
|
232
|
-
story:
|
|
235
|
+
story:
|
|
236
|
+
"Demonstrates best practices for accessible cards using aria-labelledby to provide context to assistive technologies.",
|
|
233
237
|
},
|
|
234
238
|
},
|
|
235
239
|
},
|
|
@@ -240,7 +244,7 @@ export const AccessibleCard: Story = {
|
|
|
240
244
|
*/
|
|
241
245
|
export const PolymorphicElements: Story = {
|
|
242
246
|
render: () => (
|
|
243
|
-
<div style={{ display:
|
|
247
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
|
|
244
248
|
<Card as="article">
|
|
245
249
|
<Card.Title as="h2">Article Card</Card.Title>
|
|
246
250
|
<Card.Content>
|
|
@@ -266,7 +270,8 @@ export const PolymorphicElements: Story = {
|
|
|
266
270
|
parameters: {
|
|
267
271
|
docs: {
|
|
268
272
|
description: {
|
|
269
|
-
story:
|
|
273
|
+
story:
|
|
274
|
+
"The Card component supports polymorphic rendering via the `as` prop, allowing you to use semantic HTML elements while maintaining consistent styling.",
|
|
270
275
|
},
|
|
271
276
|
},
|
|
272
277
|
},
|
|
@@ -277,7 +282,7 @@ export const PolymorphicElements: Story = {
|
|
|
277
282
|
*/
|
|
278
283
|
export const CustomHeadingLevels: Story = {
|
|
279
284
|
render: () => (
|
|
280
|
-
<div style={{ display:
|
|
285
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
|
|
281
286
|
<Card>
|
|
282
287
|
<Card.Title as="h1">Level 1 Heading</Card.Title>
|
|
283
288
|
<Card.Content>Main page title level</Card.Content>
|
|
@@ -290,7 +295,9 @@ export const CustomHeadingLevels: Story = {
|
|
|
290
295
|
|
|
291
296
|
<Card>
|
|
292
297
|
<Card.Title as="h3">Level 3 Heading (Default)</Card.Title>
|
|
293
|
-
<Card.Content>
|
|
298
|
+
<Card.Content>
|
|
299
|
+
Subsection title level - this is the default
|
|
300
|
+
</Card.Content>
|
|
294
301
|
</Card>
|
|
295
302
|
|
|
296
303
|
<Card>
|
|
@@ -302,7 +309,8 @@ export const CustomHeadingLevels: Story = {
|
|
|
302
309
|
parameters: {
|
|
303
310
|
docs: {
|
|
304
311
|
description: {
|
|
305
|
-
story:
|
|
312
|
+
story:
|
|
313
|
+
"Card.Title supports all heading levels (h1-h6) to maintain proper document outline and heading hierarchy.",
|
|
306
314
|
},
|
|
307
315
|
},
|
|
308
316
|
},
|
|
@@ -321,18 +329,23 @@ export const CustomHeadingLevels: Story = {
|
|
|
321
329
|
*/
|
|
322
330
|
export const Customization: Story = {
|
|
323
331
|
render: () => (
|
|
324
|
-
<div style={{ display:
|
|
332
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "2rem" }}>
|
|
325
333
|
{/* Custom padding and spacing */}
|
|
326
334
|
<div>
|
|
327
335
|
<h4>Custom Padding & Spacing</h4>
|
|
328
|
-
<Card
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
336
|
+
<Card
|
|
337
|
+
styles={{
|
|
338
|
+
"--card-padding": "3rem",
|
|
339
|
+
"--card-radius": "1rem",
|
|
340
|
+
"--card-gap": "1.5rem",
|
|
341
|
+
}}
|
|
342
|
+
>
|
|
333
343
|
<Card.Title>Spacious Card</Card.Title>
|
|
334
344
|
<Card.Content>
|
|
335
|
-
<p>
|
|
345
|
+
<p>
|
|
346
|
+
This card uses custom padding (3rem) and larger border radius
|
|
347
|
+
(1rem).
|
|
348
|
+
</p>
|
|
336
349
|
</Card.Content>
|
|
337
350
|
</Card>
|
|
338
351
|
</div>
|
|
@@ -340,14 +353,19 @@ export const Customization: Story = {
|
|
|
340
353
|
{/* Compact card */}
|
|
341
354
|
<div>
|
|
342
355
|
<h4>Compact Card</h4>
|
|
343
|
-
<Card
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
<Card
|
|
357
|
+
styles={{
|
|
358
|
+
"--card-padding": "1rem",
|
|
359
|
+
"--card-radius": "0.25rem",
|
|
360
|
+
"--card-gap": "0.5rem",
|
|
361
|
+
}}
|
|
362
|
+
>
|
|
348
363
|
<Card.Title>Compact Card</Card.Title>
|
|
349
364
|
<Card.Content>
|
|
350
|
-
<p>
|
|
365
|
+
<p>
|
|
366
|
+
This card uses minimal padding and smaller gaps for a compact
|
|
367
|
+
layout.
|
|
368
|
+
</p>
|
|
351
369
|
</Card.Content>
|
|
352
370
|
</Card>
|
|
353
371
|
</div>
|
|
@@ -355,41 +373,53 @@ export const Customization: Story = {
|
|
|
355
373
|
{/* Custom header/footer styling */}
|
|
356
374
|
<div>
|
|
357
375
|
<h4>Element-Specific Customization (Header, Body, Footer)</h4>
|
|
358
|
-
<div style={{ display:
|
|
359
|
-
<Card
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
376
|
+
<div style={{ display: "flex", gap: "1rem", flexWrap: "wrap" }}>
|
|
377
|
+
<Card
|
|
378
|
+
styles={{
|
|
379
|
+
"--card-header-padding": "1.5rem 2rem",
|
|
380
|
+
"--card-header-bg": "#0066cc",
|
|
381
|
+
"--card-header-border-bottom": "none",
|
|
382
|
+
"--card-body-padding": "2rem",
|
|
383
|
+
"--card-footer-padding": "1rem 2rem",
|
|
384
|
+
"--card-footer-bg": "#f0f0f0",
|
|
385
|
+
"--card-footer-border-top": "2px solid #ddd",
|
|
386
|
+
}}
|
|
387
|
+
>
|
|
388
|
+
<header data-card-header style={{ color: "white" }}>
|
|
369
389
|
<h3 style={{ margin: 0 }}>Custom Header</h3>
|
|
370
390
|
</header>
|
|
371
391
|
<div data-card-body>
|
|
372
|
-
<p>
|
|
373
|
-
|
|
392
|
+
<p>
|
|
393
|
+
This card demonstrates element-specific customization using the
|
|
394
|
+
new scoped variables.
|
|
395
|
+
</p>
|
|
396
|
+
<p>
|
|
397
|
+
Header has custom blue background, body has custom padding,
|
|
398
|
+
footer has custom gray background.
|
|
399
|
+
</p>
|
|
374
400
|
</div>
|
|
375
401
|
<footer data-card-footer>
|
|
376
402
|
<small>Custom Footer Content</small>
|
|
377
403
|
</footer>
|
|
378
404
|
</Card>
|
|
379
405
|
|
|
380
|
-
<Card
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
406
|
+
<Card
|
|
407
|
+
styles={{
|
|
408
|
+
"--card-header-padding": "0.75rem 1.25rem",
|
|
409
|
+
"--card-header-bg": "#28a745",
|
|
410
|
+
"--card-header-border-bottom": "3px solid #1e7e34",
|
|
411
|
+
"--card-body-padding": "1.25rem",
|
|
412
|
+
"--card-footer-padding": "0.75rem 1.25rem",
|
|
413
|
+
"--card-footer-bg": "#e7f5ea",
|
|
414
|
+
}}
|
|
415
|
+
>
|
|
416
|
+
<header data-card-header style={{ color: "white" }}>
|
|
389
417
|
<h3 style={{ margin: 0 }}>Green Theme</h3>
|
|
390
418
|
</header>
|
|
391
419
|
<div data-card-body>
|
|
392
|
-
<p>
|
|
420
|
+
<p>
|
|
421
|
+
Another example with green theme and custom element spacing.
|
|
422
|
+
</p>
|
|
393
423
|
</div>
|
|
394
424
|
<footer data-card-footer>
|
|
395
425
|
<small>Footer with light green background</small>
|
|
@@ -407,22 +437,27 @@ export const Customization: Story = {
|
|
|
407
437
|
}}
|
|
408
438
|
>
|
|
409
439
|
<h4 style={{ color: "white", marginTop: 0 }}>Dark Theme Example</h4>
|
|
410
|
-
<Card
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
440
|
+
<Card
|
|
441
|
+
styles={{
|
|
442
|
+
"--card-bg": "#2a2a2a",
|
|
443
|
+
"--card-padding": "2rem",
|
|
444
|
+
"--card-radius": "0.75rem",
|
|
445
|
+
"--card-header-bg": "#3a3a3a",
|
|
446
|
+
"--card-header-border-bottom": "1px solid #4a4a4a",
|
|
447
|
+
"--card-footer-bg": "#3a3a3a",
|
|
448
|
+
"--card-footer-border-top": "1px solid #4a4a4a",
|
|
449
|
+
}}
|
|
450
|
+
>
|
|
419
451
|
<header data-card-header>
|
|
420
|
-
<h3 style={{ margin: 0, color:
|
|
452
|
+
<h3 style={{ margin: 0, color: "white" }}>Dark Mode Card</h3>
|
|
421
453
|
</header>
|
|
422
|
-
<div data-card-body style={{ color:
|
|
423
|
-
<p>
|
|
454
|
+
<div data-card-body style={{ color: "#e5e7eb" }}>
|
|
455
|
+
<p>
|
|
456
|
+
This card demonstrates dark theme customization with all
|
|
457
|
+
element-specific variables.
|
|
458
|
+
</p>
|
|
424
459
|
</div>
|
|
425
|
-
<footer data-card-footer style={{ color:
|
|
460
|
+
<footer data-card-footer style={{ color: "#9ca3af" }}>
|
|
426
461
|
<small>Styled with CSS custom properties</small>
|
|
427
462
|
</footer>
|
|
428
463
|
</Card>
|
|
@@ -431,19 +466,24 @@ export const Customization: Story = {
|
|
|
431
466
|
{/* Brand card */}
|
|
432
467
|
<div>
|
|
433
468
|
<h4>Brand Card (No Radius, Custom Colors)</h4>
|
|
434
|
-
<Card
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
469
|
+
<Card
|
|
470
|
+
styles={{
|
|
471
|
+
"--card-bg": "#fff5e6",
|
|
472
|
+
"--card-radius": "0",
|
|
473
|
+
"--card-padding": "2.5rem",
|
|
474
|
+
"--card-gap": "2rem",
|
|
475
|
+
"--card-header-bg": "#ff9800",
|
|
476
|
+
"--card-header-border-bottom": "4px solid #f57c00",
|
|
477
|
+
}}
|
|
478
|
+
>
|
|
442
479
|
<header data-card-header>
|
|
443
|
-
<h3 style={{ margin: 0, color:
|
|
480
|
+
<h3 style={{ margin: 0, color: "white" }}>Brand Card</h3>
|
|
444
481
|
</header>
|
|
445
482
|
<div data-card-body>
|
|
446
|
-
<p>
|
|
483
|
+
<p>
|
|
484
|
+
This card uses brand colors and no border radius for a distinct
|
|
485
|
+
look.
|
|
486
|
+
</p>
|
|
447
487
|
</div>
|
|
448
488
|
</Card>
|
|
449
489
|
</div>
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
CardTitleProps,
|
|
6
6
|
CardContentProps,
|
|
7
7
|
CardFooterProps,
|
|
8
|
+
CardComponent,
|
|
8
9
|
} from './card.types'
|
|
9
10
|
import { cn, CARD_CLASSES, handleCardKeyDown, warnInteractiveUsage } from './card.utils'
|
|
10
11
|
|
|
@@ -218,11 +219,11 @@ Footer.displayName = 'Card.Footer'
|
|
|
218
219
|
* </Card>
|
|
219
220
|
* ```
|
|
220
221
|
*/
|
|
221
|
-
|
|
222
|
+
const CardRoot = ({
|
|
222
223
|
as = 'div',
|
|
223
224
|
styles,
|
|
224
225
|
children,
|
|
225
|
-
classes = 'shadow',
|
|
226
|
+
classes = 'shadow-sm',
|
|
226
227
|
id,
|
|
227
228
|
interactive = false,
|
|
228
229
|
onClick,
|
|
@@ -275,11 +276,20 @@ export const Card = ({
|
|
|
275
276
|
)
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
|
|
279
|
+
// Create compound component with proper TypeScript typing
|
|
280
|
+
export const Card = CardRoot as CardComponent
|
|
279
281
|
Card.displayName = 'Card'
|
|
280
282
|
Card.Title = Title
|
|
281
283
|
Card.Content = Content
|
|
282
284
|
Card.Footer = Footer
|
|
283
285
|
|
|
286
|
+
export default Card
|
|
287
|
+
|
|
284
288
|
// Export types for external consumption
|
|
285
|
-
export type {
|
|
289
|
+
export type {
|
|
290
|
+
CardProps,
|
|
291
|
+
CardTitleProps,
|
|
292
|
+
CardContentProps,
|
|
293
|
+
CardFooterProps,
|
|
294
|
+
CardComponent,
|
|
295
|
+
} from './card.types'
|
|
@@ -61,6 +61,19 @@ export interface CardFooterProps extends CardSubComponentProps {
|
|
|
61
61
|
as?: 'div' | 'footer'
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Type for Card component with attached sub-components.
|
|
66
|
+
*
|
|
67
|
+
* This type ensures TypeScript recognizes Card.Title, Card.Content, and Card.Footer
|
|
68
|
+
* as valid properties on the Card component.
|
|
69
|
+
*/
|
|
70
|
+
export interface CardComponent extends React.FC<CardProps> {
|
|
71
|
+
Title: React.FC<CardTitleProps>
|
|
72
|
+
Content: React.FC<CardContentProps>
|
|
73
|
+
Footer: React.FC<CardFooterProps>
|
|
74
|
+
displayName: string
|
|
75
|
+
}
|
|
76
|
+
|
|
64
77
|
/**
|
|
65
78
|
* Props for the main Card component.
|
|
66
79
|
*
|