@fpkit/acss 3.2.0 → 3.3.0
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-KAR3HDXK.js +8 -0
- package/libs/chunk-KAR3HDXK.js.map +1 -0
- package/libs/chunk-M5JARVJD.cjs +18 -0
- package/libs/chunk-M5JARVJD.cjs.map +1 -0
- package/libs/components/card.cjs +6 -6
- package/libs/components/card.js +1 -1
- 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/index.cjs +5 -5
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.js +1 -1
- package/package.json +2 -2
- package/src/components/cards/card.scss +1 -0
- package/src/components/cards/card.stories.tsx +120 -80
- package/src/components/cards/card.tsx +46 -41
- package/src/index.scss +2 -1
- package/src/sass/_styles.scss +2 -2
- package/src/styles/cards/card.css +1 -0
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/index.css +1 -0
- package/src/styles/index.css.map +1 -1
- package/libs/chunk-IWP4VJEP.cjs +0 -18
- package/libs/chunk-IWP4VJEP.cjs.map +0 -1
- package/libs/chunk-UGMP72J2.js +0 -8
- package/libs/chunk-UGMP72J2.js.map +0 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@fpkit/acss",
|
|
3
3
|
"description": "A lightweight React UI library for building modern and accessible components that leverage CSS custom properties for reactive Styles.",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.3.0",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=22.12.0",
|
|
8
8
|
"npm": ">=8.0.0"
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"publishConfig": {
|
|
127
127
|
"access": "public"
|
|
128
128
|
},
|
|
129
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "1948e0adc68133b7c44f0ba3ffda118d8b0c1391"
|
|
130
130
|
}
|
|
@@ -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-sm rounded-lg",
|
|
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>
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import UI from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
3
|
import type {
|
|
4
4
|
CardProps,
|
|
5
5
|
CardTitleProps,
|
|
6
6
|
CardContentProps,
|
|
7
7
|
CardFooterProps,
|
|
8
8
|
CardComponent,
|
|
9
|
-
} from
|
|
10
|
-
import {
|
|
9
|
+
} from "./card.types";
|
|
10
|
+
import {
|
|
11
|
+
cn,
|
|
12
|
+
CARD_CLASSES,
|
|
13
|
+
handleCardKeyDown,
|
|
14
|
+
warnInteractiveUsage,
|
|
15
|
+
} from "./card.utils";
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Card.Title - Title sub-component for Card
|
|
@@ -36,22 +41,22 @@ export const Title = ({
|
|
|
36
41
|
children,
|
|
37
42
|
className,
|
|
38
43
|
style,
|
|
39
|
-
as =
|
|
44
|
+
as = "h3",
|
|
40
45
|
...props
|
|
41
46
|
}: CardTitleProps) => {
|
|
42
47
|
return (
|
|
43
48
|
<UI
|
|
44
49
|
as={as}
|
|
45
|
-
|
|
50
|
+
classes={cn(CARD_CLASSES.TITLE, className)}
|
|
46
51
|
styles={style}
|
|
47
52
|
{...props}
|
|
48
53
|
>
|
|
49
54
|
{children}
|
|
50
55
|
</UI>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
56
|
+
);
|
|
57
|
+
};
|
|
53
58
|
|
|
54
|
-
Title.displayName =
|
|
59
|
+
Title.displayName = "Card.Title";
|
|
55
60
|
|
|
56
61
|
/**
|
|
57
62
|
* Card.Content - Content sub-component for Card
|
|
@@ -86,22 +91,22 @@ export const Content = ({
|
|
|
86
91
|
children,
|
|
87
92
|
className,
|
|
88
93
|
style,
|
|
89
|
-
as =
|
|
94
|
+
as = "article",
|
|
90
95
|
...props
|
|
91
96
|
}: CardContentProps) => {
|
|
92
97
|
return (
|
|
93
98
|
<UI
|
|
94
99
|
as={as}
|
|
95
|
-
|
|
100
|
+
classes={cn(CARD_CLASSES.CONTENT, className)}
|
|
96
101
|
styles={style}
|
|
97
102
|
{...props}
|
|
98
103
|
>
|
|
99
104
|
{children}
|
|
100
105
|
</UI>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
106
|
+
);
|
|
107
|
+
};
|
|
103
108
|
|
|
104
|
-
Content.displayName =
|
|
109
|
+
Content.displayName = "Card.Content";
|
|
105
110
|
|
|
106
111
|
/**
|
|
107
112
|
* Card.Footer - Footer sub-component for Card
|
|
@@ -133,22 +138,22 @@ export const Footer = ({
|
|
|
133
138
|
children,
|
|
134
139
|
className,
|
|
135
140
|
style,
|
|
136
|
-
as =
|
|
141
|
+
as = "div",
|
|
137
142
|
...props
|
|
138
143
|
}: CardFooterProps) => {
|
|
139
144
|
return (
|
|
140
145
|
<UI
|
|
141
146
|
as={as}
|
|
142
|
-
|
|
147
|
+
classes={cn(CARD_CLASSES.FOOTER, className)}
|
|
143
148
|
styles={style}
|
|
144
149
|
{...props}
|
|
145
150
|
>
|
|
146
151
|
{children}
|
|
147
152
|
</UI>
|
|
148
|
-
)
|
|
149
|
-
}
|
|
153
|
+
);
|
|
154
|
+
};
|
|
150
155
|
|
|
151
|
-
Footer.displayName =
|
|
156
|
+
Footer.displayName = "Card.Footer";
|
|
152
157
|
|
|
153
158
|
/**
|
|
154
159
|
* Card - A flexible, accessible card component with compound component pattern
|
|
@@ -220,35 +225,35 @@ Footer.displayName = 'Card.Footer'
|
|
|
220
225
|
* ```
|
|
221
226
|
*/
|
|
222
227
|
const CardRoot = ({
|
|
223
|
-
as =
|
|
228
|
+
as = "div",
|
|
224
229
|
styles,
|
|
225
230
|
children,
|
|
226
|
-
classes =
|
|
231
|
+
classes = "shadow-sm",
|
|
227
232
|
id,
|
|
228
233
|
interactive = false,
|
|
229
234
|
onClick,
|
|
230
235
|
tabIndex,
|
|
231
236
|
role,
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
"aria-label": ariaLabel,
|
|
238
|
+
"aria-labelledby": ariaLabelledBy,
|
|
239
|
+
"aria-describedby": ariaDescribedBy,
|
|
235
240
|
...props
|
|
236
241
|
}: CardProps) => {
|
|
237
242
|
// Development warnings for common accessibility issues
|
|
238
243
|
React.useEffect(() => {
|
|
239
|
-
warnInteractiveUsage(!!onClick, interactive)
|
|
240
|
-
}, [onClick, interactive])
|
|
244
|
+
warnInteractiveUsage(!!onClick, interactive);
|
|
245
|
+
}, [onClick, interactive]);
|
|
241
246
|
|
|
242
247
|
// Interactive card handling
|
|
243
248
|
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
244
249
|
if (interactive || onClick) {
|
|
245
|
-
handleCardKeyDown(event, onClick)
|
|
250
|
+
handleCardKeyDown(event, onClick);
|
|
246
251
|
}
|
|
247
|
-
}
|
|
252
|
+
};
|
|
248
253
|
|
|
249
254
|
const interactiveProps = interactive
|
|
250
255
|
? {
|
|
251
|
-
role: role ||
|
|
256
|
+
role: role || "button",
|
|
252
257
|
tabIndex: tabIndex ?? 0,
|
|
253
258
|
onClick,
|
|
254
259
|
onKeyDown: handleKeyDown,
|
|
@@ -256,34 +261,34 @@ const CardRoot = ({
|
|
|
256
261
|
: {
|
|
257
262
|
role,
|
|
258
263
|
onClick,
|
|
259
|
-
}
|
|
264
|
+
};
|
|
260
265
|
|
|
261
266
|
return (
|
|
262
267
|
<UI
|
|
263
268
|
as={as}
|
|
264
269
|
id={id}
|
|
265
270
|
styles={styles}
|
|
266
|
-
|
|
271
|
+
classes={classes}
|
|
267
272
|
aria-label={ariaLabel}
|
|
268
273
|
aria-labelledby={ariaLabelledBy}
|
|
269
274
|
aria-describedby={ariaDescribedBy}
|
|
270
|
-
data-card={interactive ?
|
|
275
|
+
data-card={interactive ? "interactive" : true}
|
|
271
276
|
{...interactiveProps}
|
|
272
277
|
{...props}
|
|
273
278
|
>
|
|
274
279
|
{children}
|
|
275
280
|
</UI>
|
|
276
|
-
)
|
|
277
|
-
}
|
|
281
|
+
);
|
|
282
|
+
};
|
|
278
283
|
|
|
279
284
|
// Create compound component with proper TypeScript typing
|
|
280
|
-
export const Card = CardRoot as CardComponent
|
|
281
|
-
Card.displayName =
|
|
282
|
-
Card.Title = Title
|
|
283
|
-
Card.Content = Content
|
|
284
|
-
Card.Footer = Footer
|
|
285
|
+
export const Card = CardRoot as CardComponent;
|
|
286
|
+
Card.displayName = "Card";
|
|
287
|
+
Card.Title = Title;
|
|
288
|
+
Card.Content = Content;
|
|
289
|
+
Card.Footer = Footer;
|
|
285
290
|
|
|
286
|
-
export default Card
|
|
291
|
+
export default Card;
|
|
287
292
|
|
|
288
293
|
// Export types for external consumption
|
|
289
294
|
export type {
|
|
@@ -292,4 +297,4 @@ export type {
|
|
|
292
297
|
CardContentProps,
|
|
293
298
|
CardFooterProps,
|
|
294
299
|
CardComponent,
|
|
295
|
-
} from
|
|
300
|
+
} from "./card.types";
|
package/src/index.scss
CHANGED
package/src/sass/_styles.scss
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@
|
|
2
|
-
@
|
|
1
|
+
@forward "./styles/shadows";
|
|
2
|
+
@forward "./styles/colors";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../../components/cards/card.scss"],"names":[],"mappings":"AAAA;EAEE;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EAEE;EACA;;AAEF;AAAA;EACE;;AAEF;AAAA;EACE;EACA;EACA;;AAGF;AAAA;EACE;;AAEF;AAAA;EACE;;AAEF;AAAA;EAGE;;AAIF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;EACA;;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA,YACE;;AAGF;EACE;EACA;;AAIF;EACE;EACA;;AAIF;EACE","file":"card.css"}
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../../components/cards/card.scss"],"names":[],"mappings":"AAAA;EAEE;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EAEE;EACA;;AAEF;AAAA;EACE;;AAEF;AAAA;EACE;EACA;EACA;;AAGF;AAAA;EACE;;AAEF;AAAA;EACE;;AAEF;AAAA;EAGE;;AAIF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;EACA;;AAGF;AAAA;EACE;EACA;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;EACA;;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA,YACE;;AAGF;EACE;EACA;;AAIF;EACE;EACA;;AAIF;EACE","file":"card.css"}
|
package/src/styles/index.css
CHANGED
|
@@ -828,6 +828,7 @@ figure:has(img[alt]) > figcaption {
|
|
|
828
828
|
flex-direction: column;
|
|
829
829
|
gap: var(--card-gap);
|
|
830
830
|
border-radius: var(--card-radius);
|
|
831
|
+
border: var(--card-border, 0.0625rem solid rgba(0, 0, 0, 0.08));
|
|
831
832
|
background-color: var(--card-bg);
|
|
832
833
|
text-align: var(--card-align, left);
|
|
833
834
|
}
|