@fpkit/acss 0.6.2 → 1.0.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.
Files changed (131) hide show
  1. package/README.md +32 -0
  2. package/docs/README.md +325 -0
  3. package/docs/guides/accessibility.md +764 -0
  4. package/docs/guides/architecture.md +705 -0
  5. package/docs/guides/composition.md +688 -0
  6. package/docs/guides/css-variables.md +522 -0
  7. package/docs/guides/storybook.md +828 -0
  8. package/docs/guides/testing.md +817 -0
  9. package/docs/testing/focus-indicator-testing.md +437 -0
  10. package/libs/components/alert/alert.css +1 -1
  11. package/libs/components/alert/alert.css.map +1 -1
  12. package/libs/components/alert/alert.min.css +2 -2
  13. package/libs/components/badge/badge.css +1 -1
  14. package/libs/components/badge/badge.css.map +1 -1
  15. package/libs/components/badge/badge.min.css +2 -2
  16. package/libs/components/breadcrumbs/breadcrumb.css +1 -1
  17. package/libs/components/breadcrumbs/breadcrumb.css.map +1 -1
  18. package/libs/components/breadcrumbs/breadcrumb.min.css +2 -2
  19. package/libs/components/buttons/button.css +1 -1
  20. package/libs/components/buttons/button.css.map +1 -1
  21. package/libs/components/buttons/button.min.css +2 -2
  22. package/libs/components/cards/card.css +1 -1
  23. package/libs/components/cards/card.css.map +1 -1
  24. package/libs/components/cards/card.min.css +2 -2
  25. package/libs/components/details/details.css +1 -1
  26. package/libs/components/details/details.css.map +1 -1
  27. package/libs/components/details/details.min.css +2 -2
  28. package/libs/components/dialog/dialog.css +1 -1
  29. package/libs/components/dialog/dialog.css.map +1 -1
  30. package/libs/components/dialog/dialog.min.css +2 -2
  31. package/libs/components/form/form.css +1 -1
  32. package/libs/components/form/form.css.map +1 -1
  33. package/libs/components/form/form.min.css +2 -2
  34. package/libs/components/images/img.css +1 -1
  35. package/libs/components/images/img.css.map +1 -1
  36. package/libs/components/images/img.min.css +2 -2
  37. package/libs/components/layout/landmarks.css +1 -1
  38. package/libs/components/layout/landmarks.css.map +1 -1
  39. package/libs/components/layout/landmarks.min.css +2 -2
  40. package/libs/components/link/link.css +1 -1
  41. package/libs/components/link/link.css.map +1 -1
  42. package/libs/components/link/link.min.css +2 -2
  43. package/libs/components/list/list.css +1 -1
  44. package/libs/components/list/list.min.css +1 -1
  45. package/libs/components/nav/nav.css +1 -1
  46. package/libs/components/nav/nav.css.map +1 -1
  47. package/libs/components/nav/nav.min.css +2 -2
  48. package/libs/components/progress/progress.css +1 -1
  49. package/libs/components/progress/progress.css.map +1 -1
  50. package/libs/components/progress/progress.min.css +2 -2
  51. package/libs/components/tag/tag.css +1 -1
  52. package/libs/components/tag/tag.css.map +1 -1
  53. package/libs/components/tag/tag.min.css +2 -2
  54. package/libs/index.css +1 -1
  55. package/libs/index.css.map +1 -1
  56. package/package.json +4 -3
  57. package/src/components/README.mdx +1 -1
  58. package/src/components/alert/alert.scss +4 -4
  59. package/src/components/alert/alert.scss.backup +184 -0
  60. package/src/components/alert/alert.stories.tsx +53 -2
  61. package/src/components/badge/badge.scss +2 -2
  62. package/src/components/badge/badge.scss.backup +39 -0
  63. package/src/components/badge/badge.stories.tsx +40 -0
  64. package/src/components/breadcrumbs/breadcrumb.scss +5 -5
  65. package/src/components/breadcrumbs/breadcrumb.scss.backup +35 -0
  66. package/src/components/breadcrumbs/breadcrumb.stories.tsx +17 -1
  67. package/src/components/buttons/button.scss +32 -27
  68. package/src/components/buttons/button.scss.backup +145 -0
  69. package/src/components/buttons/button.stories.tsx +196 -7
  70. package/src/components/cards/card.scss +39 -5
  71. package/src/components/cards/card.scss.backup +67 -0
  72. package/src/components/cards/card.stories.tsx +184 -1
  73. package/src/components/details/details.scss +14 -14
  74. package/src/components/details/details.scss.backup +126 -0
  75. package/src/components/details/details.stories.tsx +41 -1
  76. package/src/components/dialog/dialog.scss +3 -3
  77. package/src/components/dialog/dialog.scss.backup +126 -0
  78. package/src/components/form/form.scss +25 -9
  79. package/src/components/form/form.scss.backup +87 -0
  80. package/src/components/form/form.stories.tsx +272 -1
  81. package/src/components/form/input.stories.tsx +159 -1
  82. package/src/components/form/select.stories.tsx +1 -1
  83. package/src/components/heading/README.mdx +292 -0
  84. package/src/components/icons/icon.stories.tsx +1 -1
  85. package/src/components/images/figure.stories.tsx +41 -1
  86. package/src/components/images/img.scss +8 -8
  87. package/src/components/images/img.scss.backup +59 -0
  88. package/src/components/layout/_header.scss +14 -14
  89. package/src/components/layout/_header.scss.backup +72 -0
  90. package/src/components/layout/landmarks.scss +7 -7
  91. package/src/components/layout/landmarks.scss.backup +51 -0
  92. package/src/components/layout/landmarks.stories.tsx +42 -0
  93. package/src/components/link/link.scss +5 -5
  94. package/src/components/link/link.scss.backup +145 -0
  95. package/src/components/link/link.stories.tsx +38 -2
  96. package/src/components/list/list.scss +1 -1
  97. package/src/components/nav/nav.scss +17 -17
  98. package/src/components/nav/nav.scss.backup +123 -0
  99. package/src/components/nav/nav.stories.tsx +36 -2
  100. package/src/components/progress/progress.scss +7 -7
  101. package/src/components/progress/progress.scss.backup +70 -0
  102. package/src/components/tag/tag.scss +10 -10
  103. package/src/components/tag/tag.scss.backup +130 -0
  104. package/src/components/tag/tag.stories.tsx +23 -2
  105. package/src/components/ui.stories.tsx +53 -19
  106. package/src/docs/accessibility.mdx +484 -0
  107. package/src/docs/composition.mdx +549 -0
  108. package/src/docs/css-variables.mdx +380 -0
  109. package/src/docs/fpkit-developer.mdx +545 -0
  110. package/src/introduction.mdx +356 -0
  111. package/src/styles/alert/alert.css +4 -4
  112. package/src/styles/badge/badge.css +2 -2
  113. package/src/styles/breadcrumbs/breadcrumb.css +5 -5
  114. package/src/styles/buttons/button.css +30 -27
  115. package/src/styles/buttons/button.css.map +1 -1
  116. package/src/styles/cards/card.css +35 -5
  117. package/src/styles/cards/card.css.map +1 -1
  118. package/src/styles/details/details.css +14 -14
  119. package/src/styles/dialog/dialog.css +3 -3
  120. package/src/styles/form/form.css +20 -10
  121. package/src/styles/form/form.css.map +1 -1
  122. package/src/styles/images/img.css +8 -8
  123. package/src/styles/index.css +179 -134
  124. package/src/styles/index.css.map +1 -1
  125. package/src/styles/layout/landmarks.css +21 -21
  126. package/src/styles/link/link.css +5 -5
  127. package/src/styles/list/list.css +1 -1
  128. package/src/styles/nav/nav.css +17 -17
  129. package/src/styles/progress/progress.css +6 -6
  130. package/src/styles/tag/tag.css +4 -4
  131. package/src/styles/utilities/_disabled.scss +5 -4
@@ -0,0 +1,67 @@
1
+ :root {
2
+ --card-p: 2rem;
3
+ --card-bg: #fff;
4
+ --card-radius: calc(var(--card-p) / 4);
5
+ --card-position: relative;
6
+ --card-display: flex;
7
+ --card-direction: column;
8
+ --card-gap: 1rem;
9
+ }
10
+
11
+ [data-card],
12
+ [data-component~='card'] {
13
+ display: var(--card-display);
14
+ flex-direction: var(--card-direction);
15
+ gap: var(--card-gap);
16
+ border-radius: var(--card-radius);
17
+ background-color: var(--card-bg);
18
+ text-align: var(--card-align, left);
19
+
20
+ h3,
21
+ h2 {
22
+ margin-block-end: 0;
23
+ padding-block-end: 0;
24
+ }
25
+ + div {
26
+ margin-block-start: 0;
27
+ }
28
+ > article {
29
+ display: flex;
30
+ flex-direction: column;
31
+ flex: 2;
32
+ }
33
+
34
+ > *:not(img) {
35
+ padding-inline: var(--card-p);
36
+ }
37
+ > *:last-child:not(img) {
38
+ // margin-block-end: 0;
39
+ padding-block-end: var(--card-p);
40
+ }
41
+ > *:first-child:not(img) {
42
+ padding-block-start: calc(var(--card-p) - 0.5rem);
43
+ }
44
+ }
45
+
46
+ // Interactive card styles - WCAG 2.4.7 compliant focus indicators
47
+ [data-card="interactive"] {
48
+ cursor: pointer;
49
+ transition: box-shadow 0.2s ease, transform 0.2s ease;
50
+
51
+ &:hover {
52
+ transform: translateY(-2px);
53
+ box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
54
+ }
55
+
56
+ // Visible focus indicator with 3:1 minimum contrast (WCAG 2.4.7)
57
+ &:focus-visible {
58
+ outline: 0.125rem solid var(--focus-color, #0066CC);
59
+ outline-offset: 0.125rem;
60
+ }
61
+
62
+ // Hide outline for mouse users (modern browsers)
63
+ &:focus:not(:focus-visible) {
64
+ outline: none;
65
+ }
66
+ }
67
+
@@ -6,7 +6,7 @@ const content =
6
6
 
7
7
  const meta: Meta<typeof Card> = {
8
8
  title: "FP.REACT Components/Card",
9
- tags: ["rc", "autodocs"],
9
+ tags: ["stable", "autodocs"],
10
10
  component: Card,
11
11
  args: {
12
12
  children: <p>{content}</p>,
@@ -307,3 +307,186 @@ export const CustomHeadingLevels: Story = {
307
307
  },
308
308
  },
309
309
  } as Story;
310
+
311
+ /**
312
+ * CSS Variable Customization
313
+ *
314
+ * Demonstrates how to customize card appearance using the new standardized
315
+ * CSS custom property naming convention.
316
+ *
317
+ * New variable naming patterns:
318
+ * - Base properties: `--card-padding`, `--card-radius`, `--card-bg`, `--card-gap`
319
+ * - Element-specific: `--card-header-*`, `--card-body-*`, `--card-footer-*`
320
+ * - Full property names (no single-letter abbreviations)
321
+ */
322
+ export const Customization: Story = {
323
+ render: () => (
324
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
325
+ {/* Custom padding and spacing */}
326
+ <div>
327
+ <h4>Custom Padding & Spacing</h4>
328
+ <Card styles={{
329
+ "--card-padding": "3rem",
330
+ "--card-radius": "1rem",
331
+ "--card-gap": "1.5rem",
332
+ }}>
333
+ <Card.Title>Spacious Card</Card.Title>
334
+ <Card.Content>
335
+ <p>This card uses custom padding (3rem) and larger border radius (1rem).</p>
336
+ </Card.Content>
337
+ </Card>
338
+ </div>
339
+
340
+ {/* Compact card */}
341
+ <div>
342
+ <h4>Compact Card</h4>
343
+ <Card styles={{
344
+ "--card-padding": "1rem",
345
+ "--card-radius": "0.25rem",
346
+ "--card-gap": "0.5rem",
347
+ }}>
348
+ <Card.Title>Compact Card</Card.Title>
349
+ <Card.Content>
350
+ <p>This card uses minimal padding and smaller gaps for a compact layout.</p>
351
+ </Card.Content>
352
+ </Card>
353
+ </div>
354
+
355
+ {/* Custom header/footer styling */}
356
+ <div>
357
+ <h4>Element-Specific Customization (Header, Body, Footer)</h4>
358
+ <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
359
+ <Card styles={{
360
+ "--card-header-padding": "1.5rem 2rem",
361
+ "--card-header-bg": "#0066cc",
362
+ "--card-header-border-bottom": "none",
363
+ "--card-body-padding": "2rem",
364
+ "--card-footer-padding": "1rem 2rem",
365
+ "--card-footer-bg": "#f0f0f0",
366
+ "--card-footer-border-top": "2px solid #ddd",
367
+ }}>
368
+ <header data-card-header style={{ color: 'white' }}>
369
+ <h3 style={{ margin: 0 }}>Custom Header</h3>
370
+ </header>
371
+ <div data-card-body>
372
+ <p>This card demonstrates element-specific customization using the new scoped variables.</p>
373
+ <p>Header has custom blue background, body has custom padding, footer has custom gray background.</p>
374
+ </div>
375
+ <footer data-card-footer>
376
+ <small>Custom Footer Content</small>
377
+ </footer>
378
+ </Card>
379
+
380
+ <Card styles={{
381
+ "--card-header-padding": "0.75rem 1.25rem",
382
+ "--card-header-bg": "#28a745",
383
+ "--card-header-border-bottom": "3px solid #1e7e34",
384
+ "--card-body-padding": "1.25rem",
385
+ "--card-footer-padding": "0.75rem 1.25rem",
386
+ "--card-footer-bg": "#e7f5ea",
387
+ }}>
388
+ <header data-card-header style={{ color: 'white' }}>
389
+ <h3 style={{ margin: 0 }}>Green Theme</h3>
390
+ </header>
391
+ <div data-card-body>
392
+ <p>Another example with green theme and custom element spacing.</p>
393
+ </div>
394
+ <footer data-card-footer>
395
+ <small>Footer with light green background</small>
396
+ </footer>
397
+ </Card>
398
+ </div>
399
+ </div>
400
+
401
+ {/* Dark theme card */}
402
+ <div
403
+ style={{
404
+ background: "#1a1a1a",
405
+ padding: "1.5rem",
406
+ borderRadius: "0.5rem",
407
+ }}
408
+ >
409
+ <h4 style={{ color: "white", marginTop: 0 }}>Dark Theme Example</h4>
410
+ <Card styles={{
411
+ "--card-bg": "#2a2a2a",
412
+ "--card-padding": "2rem",
413
+ "--card-radius": "0.75rem",
414
+ "--card-header-bg": "#3a3a3a",
415
+ "--card-header-border-bottom": "1px solid #4a4a4a",
416
+ "--card-footer-bg": "#3a3a3a",
417
+ "--card-footer-border-top": "1px solid #4a4a4a",
418
+ }}>
419
+ <header data-card-header>
420
+ <h3 style={{ margin: 0, color: 'white' }}>Dark Mode Card</h3>
421
+ </header>
422
+ <div data-card-body style={{ color: '#e5e7eb' }}>
423
+ <p>This card demonstrates dark theme customization with all element-specific variables.</p>
424
+ </div>
425
+ <footer data-card-footer style={{ color: '#9ca3af' }}>
426
+ <small>Styled with CSS custom properties</small>
427
+ </footer>
428
+ </Card>
429
+ </div>
430
+
431
+ {/* Brand card */}
432
+ <div>
433
+ <h4>Brand Card (No Radius, Custom Colors)</h4>
434
+ <Card styles={{
435
+ "--card-bg": "#fff5e6",
436
+ "--card-radius": "0",
437
+ "--card-padding": "2.5rem",
438
+ "--card-gap": "2rem",
439
+ "--card-header-bg": "#ff9800",
440
+ "--card-header-border-bottom": "4px solid #f57c00",
441
+ }}>
442
+ <header data-card-header>
443
+ <h3 style={{ margin: 0, color: 'white' }}>Brand Card</h3>
444
+ </header>
445
+ <div data-card-body>
446
+ <p>This card uses brand colors and no border radius for a distinct look.</p>
447
+ </div>
448
+ </Card>
449
+ </div>
450
+ </div>
451
+ ),
452
+ parameters: {
453
+ docs: {
454
+ description: {
455
+ story: `
456
+ ## Available CSS Variables
457
+
458
+ ### Base Properties
459
+ - \`--card-padding\`: Main card padding (default: 2rem)
460
+ - \`--card-bg\`: Background color (default: #fff)
461
+ - \`--card-radius\`: Border radius (default: calc(var(--card-padding) / 4))
462
+ - \`--card-display\`: Display property (default: flex)
463
+ - \`--card-direction\`: Flex direction (default: column)
464
+ - \`--card-gap\`: Gap between child elements (default: 1rem)
465
+
466
+ ### Element-Specific Variables (NEW)
467
+ #### Header
468
+ - \`--card-header-padding\`: Header padding (default: 1rem 1.5rem)
469
+ - \`--card-header-bg\`: Header background color (default: #f8f9fa)
470
+ - \`--card-header-border-bottom\`: Header bottom border (default: 1px solid #dee2e6)
471
+
472
+ #### Body
473
+ - \`--card-body-padding\`: Body content padding (default: 1.5rem)
474
+
475
+ #### Footer
476
+ - \`--card-footer-padding\`: Footer padding (default: 1rem 1.5rem)
477
+ - \`--card-footer-bg\`: Footer background color (default: #f8f9fa)
478
+ - \`--card-footer-border-top\`: Footer top border (default: 1px solid #dee2e6)
479
+
480
+ ### Migration from Old Names
481
+ - ❌ \`--card-p\` → ✅ \`--card-padding\`
482
+
483
+ ### Usage with Element Selectors
484
+ Element-specific variables work with:
485
+ - \`<header>\` or \`[data-card-header]\`
486
+ - \`[data-card-body]\`
487
+ - \`<footer>\` or \`[data-card-footer]\`
488
+ `,
489
+ },
490
+ },
491
+ },
492
+ } as Story;
@@ -3,14 +3,14 @@ details {
3
3
  --details-direction: column;
4
4
  --details-display: flex;
5
5
  --details-gap: 0rem;
6
- --details-h: max-content;
6
+ --details-height: max-content;
7
7
  --details-justify: flex-start;
8
- --details-px: 1.5rem;
9
- --details-py: 1rem;
8
+ --details-padding-inline: 1.5rem;
9
+ --details-padding-block: 1rem;
10
10
  --details-radius: 0;
11
- --details-w: 100%;
12
- --max-h-closed: 6.25rem;
13
- --max-h-open: 50rem;
11
+ --details-width: 100%;
12
+ --details-max-height-closed: 6.25rem;
13
+ --details-max-height-open: 50rem;
14
14
  --summary-align: center;
15
15
  --summary-cursor: pointer;
16
16
  --summary-display: flex;
@@ -23,12 +23,12 @@ details {
23
23
  flex-direction: var(--details-direction);
24
24
  justify-content: var(--details-justify);
25
25
  gap: var(--details-gap);
26
- width: var(--details-w);
26
+ width: var(--details-width);
27
27
  border: var(--details-border);
28
28
  border-left: none;
29
29
  border-right: none;
30
30
  transition: var(--summary-transitions);
31
- max-height: var(--max-h-closed);
31
+ max-height: var(--details-max-height-closed);
32
32
  overflow: clip;
33
33
 
34
34
  @starting-style {
@@ -62,8 +62,8 @@ details {
62
62
  display: var(--summary-display);
63
63
  justify-content: var(--summary-justify);
64
64
  align-items: var(--summary-align);
65
- padding-inline: var(--summary-px, var(--details-px));
66
- padding-block: var(--summary-py, var(--details-py));
65
+ padding-inline: var(--summary-padding-inline, var(--details-padding-inline));
66
+ padding-block: var(--summary-padding-block, var(--details-padding-block));
67
67
  gap: var(--summary-gap);
68
68
  list-style: none;
69
69
  border-top-left-radius: var(--details-radius);
@@ -85,7 +85,7 @@ details {
85
85
  cursor: var(--summary-cursor);
86
86
  }
87
87
  > section {
88
- width: var(--details-w);
88
+ width: var(--details-width);
89
89
  }
90
90
  }
91
91
 
@@ -97,8 +97,8 @@ details {
97
97
  }
98
98
 
99
99
  > section {
100
- padding-inline: var(--details-px);
101
- padding-block: var(--details-py);
100
+ padding-inline: var(--details-padding-inline);
101
+ padding-block: var(--details-padding-block);
102
102
  margin-block-start: 0;
103
103
  border: 1px transparent solid;
104
104
  }
@@ -110,7 +110,7 @@ details {
110
110
  border-bottom: var(--details-border);
111
111
  }
112
112
  > section {
113
- max-height: var(--max-h-open);
113
+ max-height: var(--details-max-height-open);
114
114
  @starting-style {
115
115
  max-height: 0;
116
116
  }
@@ -0,0 +1,126 @@
1
+ details {
2
+ --details-border: 0.0625rem solid #dfdfdf;
3
+ --details-direction: column;
4
+ --details-display: flex;
5
+ --details-gap: 0rem;
6
+ --details-h: max-content;
7
+ --details-justify: flex-start;
8
+ --details-px: 1.5rem;
9
+ --details-py: 1rem;
10
+ --details-radius: 0;
11
+ --details-w: 100%;
12
+ --max-h-closed: 6.25rem;
13
+ --max-h-open: 50rem;
14
+ --summary-align: center;
15
+ --summary-cursor: pointer;
16
+ --summary-display: flex;
17
+ --summary-gap: 0.5rem;
18
+ --summary-justify: flex-start;
19
+ --summary-transitions: all 0.75s ease-in-out;
20
+
21
+ interpolate-size: allow-keywords;
22
+ display: var(--details-display);
23
+ flex-direction: var(--details-direction);
24
+ justify-content: var(--details-justify);
25
+ gap: var(--details-gap);
26
+ width: var(--details-w);
27
+ border: var(--details-border);
28
+ border-left: none;
29
+ border-right: none;
30
+ transition: var(--summary-transitions);
31
+ max-height: var(--max-h-closed);
32
+ overflow: clip;
33
+
34
+ @starting-style {
35
+ transition: var(--summary-transitions);
36
+ color: red;
37
+ }
38
+
39
+ & + details {
40
+ border-radius: 0; // remove radius from middle elements
41
+ border-top: none; // optional: remove double borders
42
+ }
43
+
44
+ &:first-of-type {
45
+ border-radius: var(--details-radius) var(--details-radius) 0 0;
46
+ }
47
+
48
+ &:last-of-type {
49
+ border-radius: 0 0 var(--details-radius) var(--details-radius);
50
+ }
51
+
52
+ // If it's the only details element, keep original radius
53
+ &:only-of-type {
54
+ border-radius: var(--details-radius);
55
+ }
56
+
57
+ &::marker {
58
+ content: none;
59
+ }
60
+
61
+ summary {
62
+ display: var(--summary-display);
63
+ justify-content: var(--summary-justify);
64
+ align-items: var(--summary-align);
65
+ padding-inline: var(--summary-px, var(--details-px));
66
+ padding-block: var(--summary-py, var(--details-py));
67
+ gap: var(--summary-gap);
68
+ list-style: none;
69
+ border-top-left-radius: var(--details-radius);
70
+ border-top-right-radius: var(--details-radius);
71
+ transition: var(--summary-transitions);
72
+
73
+ &::-webkit-details-marker {
74
+ display: none;
75
+ }
76
+
77
+ &:focus-within {
78
+ outline: none;
79
+ border-bottom: solid 2px currentColor;
80
+ background-color: whitesmoke;
81
+ }
82
+
83
+ /* This ensures no bullet points are shown */
84
+ &:hover {
85
+ cursor: var(--summary-cursor);
86
+ }
87
+ > section {
88
+ width: var(--details-w);
89
+ }
90
+ }
91
+
92
+ .list-styles {
93
+ summary {
94
+ border-left: none;
95
+ border-right: none;
96
+ }
97
+ }
98
+
99
+ > section {
100
+ padding-inline: var(--details-px);
101
+ padding-block: var(--details-py);
102
+ margin-block-start: 0;
103
+ border: 1px transparent solid;
104
+ }
105
+
106
+ &[open] {
107
+ max-height: max-content;
108
+ transition: var(--summary-transitions);
109
+ > summary {
110
+ border-bottom: var(--details-border);
111
+ }
112
+ > section {
113
+ max-height: var(--max-h-open);
114
+ @starting-style {
115
+ max-height: 0;
116
+ }
117
+ }
118
+ }
119
+
120
+ @supports (transition-behavior: allow-discrete) {
121
+ @starting-style {
122
+ max-height: 0;
123
+ transition: var(--summary-transitions);
124
+ }
125
+ }
126
+ }
@@ -31,7 +31,47 @@ const icon = <Icons.Add />;
31
31
  const meta: Meta<typeof Details> = {
32
32
  title: "FP.REACT Components/Details",
33
33
  component: Details,
34
- tags: ["rc"],
34
+ tags: ["stable"],
35
+ parameters: {
36
+ docs: {
37
+ description: {
38
+ component: `Expandable/collapsible details component with smooth transitions and accessible markup.
39
+
40
+ ## CSS Variables
41
+
42
+ ### Layout & Display
43
+ - \`--details-display\`: Display mode (default: flex)
44
+ - \`--details-direction\`: Flex direction (default: column)
45
+ - \`--details-justify\`: Content justification (default: flex-start)
46
+ - \`--details-width\`: Details width (default: 100%)
47
+ - \`--details-height\`: Details height (default: max-content)
48
+ - \`--details-gap\`: Gap between elements (default: 0rem)
49
+
50
+ ### Sizing & Constraints
51
+ - \`--details-max-height-closed\`: Max height when closed (default: 6.25rem)
52
+ - \`--details-max-height-open\`: Max height when open (default: 50rem)
53
+
54
+ ### Spacing
55
+ - \`--details-padding-inline\`: Horizontal padding (default: 1.5rem)
56
+ - \`--details-padding-block\`: Vertical padding (default: 1rem)
57
+
58
+ ### Borders & Radius
59
+ - \`--details-border\`: Border style (default: 0.0625rem solid #dfdfdf)
60
+ - \`--details-radius\`: Border radius (default: 0)
61
+
62
+ ### Summary Element
63
+ - \`--summary-display\`: Summary display mode (default: flex)
64
+ - \`--summary-justify\`: Summary content justification (default: flex-start)
65
+ - \`--summary-align\`: Summary vertical alignment (default: center)
66
+ - \`--summary-gap\`: Gap within summary (default: 0.5rem)
67
+ - \`--summary-padding-inline\`: Summary horizontal padding (fallback: \`--details-padding-inline\`)
68
+ - \`--summary-padding-block\`: Summary vertical padding (fallback: \`--details-padding-block\`)
69
+ - \`--summary-cursor\`: Summary cursor style (default: pointer)
70
+ - \`--summary-transitions\`: Transition timing (default: all 0.75s ease-in-out)
71
+ `,
72
+ },
73
+ },
74
+ },
35
75
  args: {
36
76
  children: content,
37
77
  icon: icon,
@@ -1,5 +1,5 @@
1
1
  :root {
2
- --dialog-min-w: max(20rem, 80%);
2
+ --dialog-min-width: max(20rem, 80%);
3
3
  --dialog-gap: 0.625rem;
4
4
  --dialog-border-color: lightgray;
5
5
  --dialog-border-width: thin;
@@ -33,8 +33,8 @@
33
33
  }
34
34
 
35
35
  dialog {
36
- width: var(--dialog-min-w);
37
- min-width: var(--min-w);
36
+ width: var(--dialog-min-width);
37
+ min-width: var(--dialog-min-width);
38
38
  gap: var(--dialog-gap);
39
39
  border: var(--dialog-border-color) var(--dialog-border-width) solid;
40
40
  border-radius: var(--dialog-border-radius);
@@ -0,0 +1,126 @@
1
+ :root {
2
+ --dialog-min-w: max(20rem, 80%);
3
+ --dialog-gap: 0.625rem;
4
+ --dialog-border-color: lightgray;
5
+ --dialog-border-width: thin;
6
+ --dialog-border-style: solid;
7
+ --dialog-border-radius: var(--border-radius);
8
+ --dialog-padding: 1.5rem;
9
+ --dialog-padding-inline: 1rem;
10
+ --dialog-close-color: gray;
11
+ --dialog-button-bg: transparent;
12
+ --dialog-button-border: transparent thin solid;
13
+ --dialog-button-hover-bg: whitesmoke;
14
+ --dialog-display: flex;
15
+ --dialog-flex-direction: column;
16
+
17
+ /* Focus and accessibility */
18
+ --dialog-focus-color: #0066cc;
19
+ --dialog-focus-width: 0.125rem;
20
+ --dialog-focus-offset: 0.125rem;
21
+ --dialog-focus-outline: var(--dialog-focus-width) solid var(--dialog-focus-color);
22
+ }
23
+
24
+ /* High contrast mode support */
25
+ @media (prefers-contrast: high) {
26
+ :root {
27
+ --dialog-border-color: currentColor;
28
+ --dialog-border-width: 0.125rem;
29
+ --dialog-close-color: currentColor;
30
+ --dialog-button-border: currentColor 0.125rem solid;
31
+ --dialog-focus-width: 0.1875rem;
32
+ }
33
+ }
34
+
35
+ dialog {
36
+ width: var(--dialog-min-w);
37
+ min-width: var(--min-w);
38
+ gap: var(--dialog-gap);
39
+ border: var(--dialog-border-color) var(--dialog-border-width) solid;
40
+ border-radius: var(--dialog-border-radius);
41
+ padding: var(--dialog-padding);
42
+ padding-block-start: var(--dialog-padding);
43
+
44
+ /* Focus visible for keyboard navigation */
45
+ &:focus-visible {
46
+ outline: var(--dialog-focus-outline);
47
+ outline-offset: var(--dialog-focus-offset);
48
+ }
49
+
50
+ &[open] {
51
+ display: var(--dialog-display);
52
+ flex-direction: var(--dialog-flex-direction);
53
+ gap: var(--dialog-gap);
54
+ }
55
+
56
+ section {
57
+ width: 100%;
58
+ display: flex;
59
+ justify-content: start;
60
+ gap: var(--dialog-gap);
61
+ flex-direction: var(--dialog-flex-direction);
62
+ margin-block-start: 0;
63
+ --sect-y: 0;
64
+ }
65
+ }
66
+
67
+ .dialog-header {
68
+ display: flex;
69
+ justify-content: space-between;
70
+ align-items: center;
71
+ width: 100%;
72
+ min-width: 100%;
73
+
74
+ h3 {
75
+ margin-block-start: 0;
76
+ margin-block-end: 0;
77
+ }
78
+
79
+ .dialog-close {
80
+ margin-block-end: 0;
81
+ }
82
+
83
+ button[type="button"] {
84
+ background-color: var(--dialog-button-bg);
85
+ border: var(--dialog-button-border);
86
+ cursor: pointer;
87
+
88
+ &:hover {
89
+ border-color: var(--dialog-close-color);
90
+ background-color: var(--dialog-button-hover-bg);
91
+ }
92
+
93
+ /* Keyboard focus indicator */
94
+ &:focus-visible {
95
+ outline: var(--dialog-focus-outline);
96
+ outline-offset: var(--dialog-focus-offset);
97
+ border-color: var(--dialog-focus-color);
98
+ background-color: var(--dialog-button-hover-bg);
99
+ }
100
+
101
+ /* Remove default focus for mouse users */
102
+ &:focus:not(:focus-visible) {
103
+ outline: none;
104
+ }
105
+ }
106
+ }
107
+
108
+ .alert-dialog-actions,
109
+ .dialog-footer {
110
+ display: flex;
111
+ flex-direction: row;
112
+ flex-wrap: wrap;
113
+ justify-content: var(--dialog-footer-justify, flex-end);
114
+ gap: var(--dialog-gap);
115
+ width: 100%;
116
+
117
+ /* Focus styles for footer buttons */
118
+ button:focus-visible {
119
+ outline: var(--dialog-focus-outline);
120
+ outline-offset: var(--dialog-focus-offset);
121
+ }
122
+
123
+ button:focus:not(:focus-visible) {
124
+ outline: none;
125
+ }
126
+ }