@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
@@ -8,6 +8,46 @@ const meta: Meta<typeof Badge> = {
8
8
  title: "FP.REACT Components/Badge",
9
9
  component: Badge,
10
10
  tags: ["beta", "accessible"],
11
+ parameters: {
12
+ docs: {
13
+ description: {
14
+ component: `A notification badge component for displaying counts or status indicators with accessibility support.
15
+
16
+ ## CSS Variables
17
+
18
+ Customize the Badge appearance using CSS custom properties:
19
+
20
+ ### Layout & Structure
21
+ - \`--badge-bg\`: Background color (default: \`lightgray\`)
22
+ - \`--badge-color\`: Text color (default: \`currentColor\`)
23
+ - \`--badge-radius\`: Border radius (default: \`0.5rem\`)
24
+ - \`--badge-padding\`: Internal padding (default: \`0.3rem\`)
25
+ - \`--badge-vertical-align\`: Vertical alignment (default: \`0.5rem\`)
26
+
27
+ ### Typography
28
+ - \`--badge-fs\`: Font size (default: \`var(--fs-1)\`)
29
+
30
+ ### Rounded Variant
31
+ When using \`variant="rounded"\`:
32
+ - \`--badge-size\`: Fixed circular size (default: \`1.5625rem\`)
33
+ - Border radius automatically becomes \`50%\`
34
+ - Padding becomes \`0\`
35
+ - Content truncated with ellipsis if too long
36
+
37
+ **Example:**
38
+ \`\`\`css
39
+ sup:has(> span) {
40
+ --badge-bg: #ef4444;
41
+ --badge-color: white;
42
+ --badge-radius: 0.25rem;
43
+ --badge-padding: 0.5rem;
44
+ --badge-vertical-align: 0.75rem;
45
+ --badge-fs: 0.875rem;
46
+ }
47
+ \`\`\``,
48
+ },
49
+ },
50
+ },
11
51
  args: {
12
52
  children: "5",
13
53
  },
@@ -1,7 +1,7 @@
1
1
  nav:not(body > nav),
2
2
  nav[data-breadcrumb] {
3
- --breadcrumb-px: unset;
4
- --breadcrumb-dsp: flex;
3
+ --breadcrumb-padding-inline: unset;
4
+ --breadcrumb-display: flex;
5
5
  --breadcrumb-gap: 0.5rem;
6
6
  --breadcrumb-color: currentColor;
7
7
  --breadcrumb-current-color: rgb(46, 46, 46);
@@ -9,12 +9,12 @@ nav[data-breadcrumb] {
9
9
  margin-inline: unset;
10
10
  padding-inline: unset;
11
11
  ol {
12
- padding-inline: var(--breadcrumb-px);
13
- display: var(--breadcrumb-dsp);
12
+ padding-inline: var(--breadcrumb-padding-inline);
13
+ display: var(--breadcrumb-display);
14
14
  gap: var(--breadcrumb-gap);
15
15
  li {
16
16
  padding-inline: unset;
17
- width: var(--breadcrumb-w, fit-content);
17
+ width: var(--breadcrumb-width, fit-content);
18
18
  text-transform: capitalize;
19
19
  display: flex;
20
20
  color: var(--breadcrumb-color);
@@ -0,0 +1,35 @@
1
+ nav:not(body > nav),
2
+ nav[data-breadcrumb] {
3
+ --breadcrumb-px: unset;
4
+ --breadcrumb-dsp: flex;
5
+ --breadcrumb-gap: 0.5rem;
6
+ --breadcrumb-color: currentColor;
7
+ --breadcrumb-current-color: rgb(46, 46, 46);
8
+ --breadcrumb-fs: var(--fs-3);
9
+ margin-inline: unset;
10
+ padding-inline: unset;
11
+ ol {
12
+ padding-inline: var(--breadcrumb-px);
13
+ display: var(--breadcrumb-dsp);
14
+ gap: var(--breadcrumb-gap);
15
+ li {
16
+ padding-inline: unset;
17
+ width: var(--breadcrumb-w, fit-content);
18
+ text-transform: capitalize;
19
+ display: flex;
20
+ color: var(--breadcrumb-color);
21
+ gap: 0.5rem;
22
+ font-size: var(--breadcrumb-fs);
23
+ span[aria-hidden="true"] {
24
+ opacity: 0.6;
25
+ }
26
+ a[href] {
27
+ font-size: var(--breadcrumb-fs);
28
+ &[aria-current] {
29
+ color: var(--breadcrumb-current-color);
30
+ text-decoration: none;
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
@@ -17,7 +17,23 @@ const meta: Meta<typeof Breadcrumb> = {
17
17
 
18
18
  **Features:** Automatic path parsing, custom route naming, text truncation, full accessibility support, and performance optimized with memoization.
19
19
 
20
- **Accessibility:** Semantic HTML (\`<nav>\`, \`<ol>\`), proper ARIA labels, current page marked with \`aria-current="page"\`, and truncated text includes full text in \`aria-label\`.`,
20
+ **Accessibility:** Semantic HTML (\`<nav>\`, \`<ol>\`), proper ARIA labels, current page marked with \`aria-current="page"\`, and truncated text includes full text in \`aria-label\`.
21
+
22
+ ## CSS Variables
23
+
24
+ ### Layout & Display
25
+ - \`--breadcrumb-display\`: Display mode for breadcrumb list (default: flex)
26
+ - \`--breadcrumb-width\`: Width of list items (default: fit-content)
27
+
28
+ ### Spacing
29
+ - \`--breadcrumb-padding-inline\`: Horizontal padding (default: unset)
30
+ - \`--breadcrumb-gap\`: Gap between breadcrumb items (default: 0.5rem)
31
+
32
+ ### Typography & Color
33
+ - \`--breadcrumb-fs\`: Font size (default: var(--fs-3))
34
+ - \`--breadcrumb-color\`: Text color (default: currentColor)
35
+ - \`--breadcrumb-current-color\`: Current page color (default: rgb(46, 46, 46))
36
+ `,
21
37
  },
22
38
  },
23
39
  },
@@ -1,10 +1,11 @@
1
1
  button {
2
- --btn-xs: 0.6875rem;
3
- --btn-sm: 0.8125rem;
4
- --btn-md: 0.9375rem;
5
- --btn-lg: 1.125rem;
2
+ // Size tokens - renamed for clarity
3
+ --btn-size-xs: 0.6875rem;
4
+ --btn-size-sm: 0.8125rem;
5
+ --btn-size-md: 0.9375rem;
6
+ --btn-size-lg: 1.125rem;
6
7
  --btn-pill: 100rem;
7
- --btn-fs: var(--btn-md);
8
+ --btn-fs: var(--btn-size-md);
8
9
  --btn-height: calc(var(--btn-fs) * 2.25);
9
10
  --btn-bg: lightgray;
10
11
  --btn-width: max-content;
@@ -13,16 +14,16 @@ button {
13
14
  font-weight: var(--btn-fw, 500);
14
15
  height: var(--btn-height);
15
16
  place-items: var(--btn-place, center);
16
- padding-inline: var(--btn-px, calc(var(--btn-fs) * 1.5));
17
- padding-block: var(--btn-py, calc(var(--btn-fs) * 0.5));
18
- border: var(--btn-bdr, none);
19
- border-radius: var(--btn-rds, calc(6rem / 16));
17
+ padding-inline: var(--btn-padding-inline, calc(var(--btn-fs) * 1.5));
18
+ padding-block: var(--btn-padding-block, calc(var(--btn-fs) * 0.5));
19
+ border: var(--btn-border, none);
20
+ border-radius: var(--btn-radius, calc(6rem / 16));
20
21
  text-decoration: var(--btn-deco, none);
21
- color: var(--btn-cl, currentColor);
22
- display: var(--btn-dsp, inline-flex);
22
+ color: var(--btn-color, currentColor);
23
+ display: var(--btn-display, inline-flex);
23
24
  gap: var(--btn-gap, 0.2rem);
24
- white-space: var(--btn-wspc, inherit);
25
- margin: var(--btn-spc, 0);
25
+ white-space: var(--btn-whitespace, inherit);
26
+ margin: var(--btn-spacing, 0);
26
27
  transition: var(
27
28
  --btn-transition,
28
29
  var(--tran-all, all 0.3s cubic-bezier(0.4, 0, 0.2, 1))
@@ -36,7 +37,7 @@ button {
36
37
 
37
38
  &[type] {
38
39
  background-color: var(--btn-bg, var(--neutral-300));
39
- --btn-bdr: solid var(--btn-sg);
40
+ --btn-border: solid var(--btn-sg);
40
41
  }
41
42
 
42
43
  &[type="submit"],
@@ -73,16 +74,20 @@ button {
73
74
  }
74
75
  }
75
76
 
77
+ &:focus-visible {
78
+ outline: var(--btn-focus-outline, 2px solid currentColor);
79
+ outline-offset: var(--btn-focus-outline-offset, 1px);
80
+ }
81
+
76
82
  &[type="reset"] {
77
83
  --btn-bg: transparent;
78
84
  --btn-color: gray;
79
- --btn-bdr: gray thin solid;
85
+ --btn-border: gray thin solid;
80
86
  }
81
87
 
82
88
  &[type="submit"] {
83
89
  --btn-bg: var(--primary-700, blue);
84
- --btn-cl: #fff;
85
- --btn-color: rgb(231, 231, 231);
90
+ --btn-color: #fff;
86
91
  --btn-border: none;
87
92
  }
88
93
 
@@ -94,23 +99,23 @@ button {
94
99
 
95
100
  &[data-btn~="xs"],
96
101
  .btn-xs {
97
- --btn-fs: var(--btn-xs);
102
+ --btn-fs: var(--btn-size-xs);
98
103
  text-transform: uppercase;
99
104
  }
100
105
 
101
106
  &[data-btn~="sm"],
102
107
  .btn-sm {
103
- --btn-fs: var(--btn-sm);
108
+ --btn-fs: var(--btn-size-sm);
104
109
  }
105
110
 
106
111
  &[data-btn~="md"],
107
112
  .btn-md {
108
- --btn-fs: var(--btn-md);
113
+ --btn-fs: var(--btn-size-md);
109
114
  }
110
115
 
111
116
  &[data-btn~="lg"],
112
117
  .btn-lg {
113
- --btn-fs: var(--btn-lg);
118
+ --btn-fs: var(--btn-size-lg);
114
119
  }
115
120
 
116
121
  &[data-btn~="icon"],
@@ -129,15 +134,15 @@ button {
129
134
  &[data-btn~="text"],
130
135
  .btn-text {
131
136
  --btn-bg: transparent;
132
- --btn-cl: currentColor;
133
- --btn-bdr: none;
137
+ --btn-color: currentColor;
138
+ --btn-border: none;
134
139
  --btn-height: unset;
135
140
  --btn-width: unset;
136
- --btn-py: 0.75rem;
137
- --btn-px: 0.75rem;
141
+ --btn-padding-block: 0.75rem;
142
+ --btn-padding-inline: 0.75rem;
138
143
  &:is(:hover, :focus) {
139
- background-color: color-mix(in srgb, var(--btn-cl) 10%, transparent);
140
- outline: 0.025rem solid var(--btn-cl);
144
+ background-color: color-mix(in srgb, var(--btn-color) 10%, transparent);
145
+ outline: 0.025rem solid var(--btn-color);
141
146
  outline-offset: 0;
142
147
  filter: none; // Override parent filter
143
148
  }
@@ -0,0 +1,145 @@
1
+ button {
2
+ --btn-xs: 0.6875rem;
3
+ --btn-sm: 0.8125rem;
4
+ --btn-md: 0.9375rem;
5
+ --btn-lg: 1.125rem;
6
+ --btn-pill: 100rem;
7
+ --btn-fs: var(--btn-md);
8
+ --btn-height: calc(var(--btn-fs) * 2.25);
9
+ --btn-bg: lightgray;
10
+ --btn-width: max-content;
11
+
12
+ font-size: var(--btn-fs);
13
+ font-weight: var(--btn-fw, 500);
14
+ height: var(--btn-height);
15
+ place-items: var(--btn-place, center);
16
+ padding-inline: var(--btn-px, calc(var(--btn-fs) * 1.5));
17
+ padding-block: var(--btn-py, calc(var(--btn-fs) * 0.5));
18
+ border: var(--btn-bdr, none);
19
+ border-radius: var(--btn-rds, calc(6rem / 16));
20
+ text-decoration: var(--btn-deco, none);
21
+ color: var(--btn-cl, currentColor);
22
+ display: var(--btn-dsp, inline-flex);
23
+ gap: var(--btn-gap, 0.2rem);
24
+ white-space: var(--btn-wspc, inherit);
25
+ margin: var(--btn-spc, 0);
26
+ transition: var(
27
+ --btn-transition,
28
+ var(--tran-all, all 0.3s cubic-bezier(0.4, 0, 0.2, 1))
29
+ );
30
+ background-color: var(--btn-bg, var(--btn));
31
+ outline: none;
32
+ width: var(--btn-width);
33
+ display: inline-flex;
34
+ align-items: center;
35
+ line-height: 0cap;
36
+
37
+ &[type] {
38
+ background-color: var(--btn-bg, var(--neutral-300));
39
+ --btn-bdr: solid var(--btn-sg);
40
+ }
41
+
42
+ &[type="submit"],
43
+ &[style*="submit"] {
44
+ --btn-bg: var(--primary-500, royal-blue);
45
+ --btn-color: white;
46
+ }
47
+
48
+ &[disabled],
49
+ &[aria-disabled="true"] {
50
+ cursor: var(--btn-cursor, not-allowed);
51
+ // opacity: var(--btn-opacity, 0.5);
52
+
53
+ &:is(:hover, :focus) {
54
+ transform: none;
55
+ // background-color: var(--btn-bg, lightgray);
56
+ // opacity: var(--btn-opacity, 0.5);
57
+ }
58
+ }
59
+
60
+ // TODO: add hover/focus with :if()
61
+ &:is(:hover, :focus) {
62
+ // Darken the background on hover by reducing brightness
63
+ filter: var(--btn-hover-filter, brightness(0.85));
64
+ transform: var(--btn-hover-transform, scale(1.03));
65
+ outline: var(--btn-hover-outline, thin);
66
+ outline-offset: var(--line-offset, 1px);
67
+ // outline-style: var(--line-style, solid);
68
+
69
+ &[aria-disabled="true"] {
70
+ transform: none;
71
+ opacity: var(--btn-opacity, 0.5);
72
+ filter: none;
73
+ }
74
+ }
75
+
76
+ &[type="reset"] {
77
+ --btn-bg: transparent;
78
+ --btn-color: gray;
79
+ --btn-bdr: gray thin solid;
80
+ }
81
+
82
+ &[type="submit"] {
83
+ --btn-bg: var(--primary-700, blue);
84
+ --btn-cl: #fff;
85
+ --btn-color: rgb(231, 231, 231);
86
+ --btn-border: none;
87
+ }
88
+
89
+ &[data-fp-btn~="pill"],
90
+ &[data-btn~="pill"],
91
+ &[data-style~="pill"] {
92
+ border-radius: var(--btn-pill, 100rem);
93
+ }
94
+
95
+ &[data-btn~="xs"],
96
+ .btn-xs {
97
+ --btn-fs: var(--btn-xs);
98
+ text-transform: uppercase;
99
+ }
100
+
101
+ &[data-btn~="sm"],
102
+ .btn-sm {
103
+ --btn-fs: var(--btn-sm);
104
+ }
105
+
106
+ &[data-btn~="md"],
107
+ .btn-md {
108
+ --btn-fs: var(--btn-md);
109
+ }
110
+
111
+ &[data-btn~="lg"],
112
+ .btn-lg {
113
+ --btn-fs: var(--btn-lg);
114
+ }
115
+
116
+ &[data-btn~="icon"],
117
+ .btn-icon {
118
+ padding: unset;
119
+ height: unset;
120
+ --btn-bg: transparent;
121
+ min-width: 1.5rem;
122
+ min-height: 1.5rem;
123
+ text-align: center;
124
+ display: inline-flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ }
128
+
129
+ &[data-btn~="text"],
130
+ .btn-text {
131
+ --btn-bg: transparent;
132
+ --btn-cl: currentColor;
133
+ --btn-bdr: none;
134
+ --btn-height: unset;
135
+ --btn-width: unset;
136
+ --btn-py: 0.75rem;
137
+ --btn-px: 0.75rem;
138
+ &:is(:hover, :focus) {
139
+ background-color: color-mix(in srgb, var(--btn-cl) 10%, transparent);
140
+ outline: 0.025rem solid var(--btn-cl);
141
+ outline-offset: 0;
142
+ filter: none; // Override parent filter
143
+ }
144
+ }
145
+ }
@@ -9,7 +9,7 @@ const buttonClicked = fn();
9
9
  const meta = {
10
10
  title: "FP.React Components/Buttons",
11
11
  component: Button,
12
- tags: ["rc"],
12
+ tags: ["beta"],
13
13
  args: {
14
14
  children: "Click me",
15
15
  onClick: buttonClicked,
@@ -149,10 +149,13 @@ export const Disabled: Story = {
149
149
  expect(button).toHaveAttribute("aria-disabled", "true");
150
150
  });
151
151
 
152
- await step("Disabled button remains focusable for accessibility", async () => {
153
- await userEvent.tab();
154
- expect(button).toHaveFocus();
155
- });
152
+ await step(
153
+ "Disabled button remains focusable for accessibility",
154
+ async () => {
155
+ await userEvent.tab();
156
+ expect(button).toHaveFocus();
157
+ }
158
+ );
156
159
 
157
160
  await step("Disabled button prevents click interactions", async () => {
158
161
  const clickHandler = fn();
@@ -181,8 +184,8 @@ export const DisabledCustom: Story = {
181
184
  classes: "my-custom-button",
182
185
  styles: {
183
186
  "--btn-fs": "1.25rem",
184
- "--btn-py": "0.75rem",
185
- "--btn-px": "1.5rem",
187
+ "--btn-padding-block": "0.75rem",
188
+ "--btn-padding-inline": "1.5rem",
186
189
  },
187
190
  children: "Custom Disabled",
188
191
  },
@@ -225,3 +228,189 @@ Try clicking - only enabled button responds.
225
228
  },
226
229
  },
227
230
  } as Story;
231
+
232
+ /**
233
+ * CSS Variable Customization
234
+ *
235
+ * Demonstrates how to customize button appearance using the new standardized
236
+ * CSS custom property naming convention.
237
+ *
238
+ * New variable naming patterns:
239
+ * - Size tokens: `--btn-size-{xs|sm|md|lg}`
240
+ * - Logical properties: `--btn-padding-inline`, `--btn-padding-block`
241
+ * - Full property names: `--btn-radius`, `--btn-color`, `--btn-display`, `--btn-border`
242
+ * - Approved abbreviations: `--btn-fs` (font-size), `--btn-bg` (background), `--btn-fw` (font-weight)
243
+ */
244
+ export const Customization: Story = {
245
+ render: () => (
246
+ <div style={{ display: "flex", flexDirection: "column", gap: "2rem" }}>
247
+ {/* Custom brand colors */}
248
+ <div>
249
+ <h4>Custom Brand Colors</h4>
250
+ <Button
251
+ type="button"
252
+ styles={{
253
+ "--btn-bg": "#0066cc",
254
+ "--btn-color": "white",
255
+ "--btn-radius": "0.5rem",
256
+ "--btn-padding-inline": "2rem",
257
+ "--btn-padding-block": "0.75rem",
258
+ }}
259
+ >
260
+ Brand Button
261
+ </Button>
262
+ </div>
263
+
264
+ {/* Custom sizes using logical properties */}
265
+ <div>
266
+ <h4>Custom Padding (Logical Properties)</h4>
267
+ <div style={{ display: "flex", gap: "1rem", flexWrap: "wrap" }}>
268
+ <Button
269
+ type="button"
270
+ styles={{
271
+ "--btn-padding-inline": "0.5rem",
272
+ "--btn-padding-block": "0.25rem",
273
+ "--btn-fs": "0.875rem",
274
+ }}
275
+ >
276
+ Compact
277
+ </Button>
278
+ <Button
279
+ type="button"
280
+ styles={{
281
+ "--btn-padding-inline": "3rem",
282
+ "--btn-padding-block": "1rem",
283
+ "--btn-fs": "1.125rem",
284
+ }}
285
+ >
286
+ Spacious
287
+ </Button>
288
+ </div>
289
+ </div>
290
+
291
+ {/* Custom hover effects */}
292
+ <div>
293
+ <h4>Custom Hover Effects</h4>
294
+ <Button
295
+ type="button"
296
+ styles={{
297
+ "--btn-bg": "#28a745",
298
+ "--btn-color": "white",
299
+ "--btn-hover-filter": "brightness(1.1)",
300
+ "--btn-hover-transform": "translateY(-2px)",
301
+ }}
302
+ >
303
+ Hover Me
304
+ </Button>
305
+ </div>
306
+
307
+ {/* Custom borders and shapes */}
308
+ <div>
309
+ <h4>Custom Borders & Shapes</h4>
310
+ <div style={{ display: "flex", gap: "1rem", flexWrap: "wrap" }}>
311
+ <Button
312
+ type="button"
313
+ styles={{
314
+ "--btn-bg": "transparent",
315
+ "--btn-color": "#0066cc",
316
+ "--btn-border": "2px solid currentColor",
317
+ "--btn-radius": "0",
318
+ }}
319
+ >
320
+ Square Outline
321
+ </Button>
322
+ <Button
323
+ type="button"
324
+ styles={{
325
+ "--btn-bg": "#dc3545",
326
+ "--btn-color": "white",
327
+ "--btn-radius": "100rem",
328
+ "--btn-padding-inline": "2rem",
329
+ }}
330
+ >
331
+ Pill Shape
332
+ </Button>
333
+ </div>
334
+ </div>
335
+
336
+ {/* Dark theme example */}
337
+ <div
338
+ style={{
339
+ background: "#1a1a1a",
340
+ padding: "1.5rem",
341
+ borderRadius: "0.5rem",
342
+ }}
343
+ >
344
+ <h4 style={{ color: "white", marginTop: 0 }}>Dark Theme Example</h4>
345
+ <div style={{ display: "flex", gap: "1rem", flexWrap: "wrap" }}>
346
+ <Button
347
+ type="button"
348
+ styles={{
349
+ "--btn-bg": "#3b82f6",
350
+ "--btn-color": "white",
351
+ "--btn-hover-filter": "brightness(1.2)",
352
+ }}
353
+ >
354
+ Primary
355
+ </Button>
356
+ <Button
357
+ type="button"
358
+ styles={{
359
+ "--btn-bg": "transparent",
360
+ "--btn-color": "#e5e7eb",
361
+ "--btn-border": "1px solid #4b5563",
362
+ "--btn-hover-filter": "brightness(1.3)",
363
+ }}
364
+ >
365
+ Secondary
366
+ </Button>
367
+ </div>
368
+ </div>
369
+ </div>
370
+ ),
371
+ parameters: {
372
+ docs: {
373
+ description: {
374
+ story: `
375
+ ## Available CSS Variables
376
+
377
+ ### Size Tokens
378
+ - \`--btn-size-xs\`: 0.6875rem (11px)
379
+ - \`--btn-size-sm\`: 0.8125rem (13px)
380
+ - \`--btn-size-md\`: 0.9375rem (15px)
381
+ - \`--btn-size-lg\`: 1.125rem (18px)
382
+
383
+ ### Base Properties
384
+ - \`--btn-padding-inline\`: Horizontal padding (logical property)
385
+ - \`--btn-padding-block\`: Vertical padding (logical property)
386
+ - \`--btn-radius\`: Border radius
387
+ - \`--btn-color\`: Text color
388
+ - \`--btn-bg\`: Background color
389
+ - \`--btn-border\`: Border style
390
+ - \`--btn-display\`: Display property
391
+ - \`--btn-whitespace\`: White-space handling
392
+ - \`--btn-spacing\`: Margin/spacing
393
+
394
+ ### Typography (Approved Abbreviations)
395
+ - \`--btn-fs\`: Font size
396
+ - \`--btn-fw\`: Font weight
397
+
398
+ ### State Variables
399
+ - \`--btn-hover-filter\`: Filter on hover
400
+ - \`--btn-hover-transform\`: Transform on hover
401
+ - \`--btn-hover-outline\`: Outline on hover
402
+
403
+ ### Migration from Old Names
404
+ - ❌ \`--btn-px\` → ✅ \`--btn-padding-inline\`
405
+ - ❌ \`--btn-py\` → ✅ \`--btn-padding-block\`
406
+ - ❌ \`--btn-rds\` → ✅ \`--btn-radius\`
407
+ - ❌ \`--btn-cl\` → ✅ \`--btn-color\`
408
+ - ❌ \`--btn-dsp\` → ✅ \`--btn-display\`
409
+ - ❌ \`--btn-bdr\` → ✅ \`--btn-border\`
410
+ - ❌ \`--btn-wspc\` → ✅ \`--btn-whitespace\`
411
+ - ❌ \`--btn-spc\` → ✅ \`--btn-spacing\`
412
+ `,
413
+ },
414
+ },
415
+ },
416
+ } as Story;
@@ -1,11 +1,23 @@
1
1
  :root {
2
- --card-p: 2rem;
2
+ // Base card properties
3
+ --card-padding: 2rem;
3
4
  --card-bg: #fff;
4
- --card-radius: calc(var(--card-p) / 4);
5
+ --card-radius: calc(var(--card-padding) / 4);
5
6
  --card-position: relative;
6
7
  --card-display: flex;
7
8
  --card-direction: column;
8
9
  --card-gap: 1rem;
10
+
11
+ // Element-specific variables (NEW - for complex card layouts)
12
+ --card-header-padding: 1rem 1.5rem;
13
+ --card-header-bg: #f8f9fa;
14
+ --card-header-border-bottom: 1px solid #dee2e6;
15
+
16
+ --card-body-padding: 1.5rem;
17
+
18
+ --card-footer-padding: 1rem 1.5rem;
19
+ --card-footer-bg: #f8f9fa;
20
+ --card-footer-border-top: 1px solid #dee2e6;
9
21
  }
10
22
 
11
23
  [data-card],
@@ -32,14 +44,36 @@
32
44
  }
33
45
 
34
46
  > *:not(img) {
35
- padding-inline: var(--card-p);
47
+ padding-inline: var(--card-padding);
36
48
  }
37
49
  > *:last-child:not(img) {
38
50
  // margin-block-end: 0;
39
- padding-block-end: var(--card-p);
51
+ padding-block-end: var(--card-padding);
40
52
  }
41
53
  > *:first-child:not(img) {
42
- padding-block-start: calc(var(--card-p) - 0.5rem);
54
+ padding-block-start: calc(var(--card-padding) - 0.5rem);
55
+ }
56
+
57
+ // Element-specific styling (using new scoped variables)
58
+ > header,
59
+ > [data-card-header] {
60
+ padding: var(--card-header-padding);
61
+ background-color: var(--card-header-bg);
62
+ border-bottom: var(--card-header-border-bottom);
63
+ border-radius: var(--card-radius) var(--card-radius) 0 0;
64
+ }
65
+
66
+ > [data-card-body] {
67
+ padding: var(--card-body-padding);
68
+ flex: 1;
69
+ }
70
+
71
+ > footer,
72
+ > [data-card-footer] {
73
+ padding: var(--card-footer-padding);
74
+ background-color: var(--card-footer-bg);
75
+ border-top: var(--card-footer-border-top);
76
+ border-radius: 0 0 var(--card-radius) var(--card-radius);
43
77
  }
44
78
  }
45
79