@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.
- package/README.md +32 -0
- package/docs/README.md +325 -0
- package/docs/guides/accessibility.md +764 -0
- package/docs/guides/architecture.md +705 -0
- package/docs/guides/composition.md +688 -0
- package/docs/guides/css-variables.md +522 -0
- package/docs/guides/storybook.md +828 -0
- package/docs/guides/testing.md +817 -0
- package/docs/testing/focus-indicator-testing.md +437 -0
- package/libs/components/alert/alert.css +1 -1
- package/libs/components/alert/alert.css.map +1 -1
- package/libs/components/alert/alert.min.css +2 -2
- package/libs/components/badge/badge.css +1 -1
- package/libs/components/badge/badge.css.map +1 -1
- package/libs/components/badge/badge.min.css +2 -2
- package/libs/components/breadcrumbs/breadcrumb.css +1 -1
- package/libs/components/breadcrumbs/breadcrumb.css.map +1 -1
- package/libs/components/breadcrumbs/breadcrumb.min.css +2 -2
- package/libs/components/buttons/button.css +1 -1
- package/libs/components/buttons/button.css.map +1 -1
- package/libs/components/buttons/button.min.css +2 -2
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/details/details.css +1 -1
- package/libs/components/details/details.css.map +1 -1
- package/libs/components/details/details.min.css +2 -2
- package/libs/components/dialog/dialog.css +1 -1
- package/libs/components/dialog/dialog.css.map +1 -1
- package/libs/components/dialog/dialog.min.css +2 -2
- package/libs/components/form/form.css +1 -1
- package/libs/components/form/form.css.map +1 -1
- package/libs/components/form/form.min.css +2 -2
- package/libs/components/images/img.css +1 -1
- package/libs/components/images/img.css.map +1 -1
- package/libs/components/images/img.min.css +2 -2
- package/libs/components/layout/landmarks.css +1 -1
- package/libs/components/layout/landmarks.css.map +1 -1
- package/libs/components/layout/landmarks.min.css +2 -2
- package/libs/components/link/link.css +1 -1
- package/libs/components/link/link.css.map +1 -1
- package/libs/components/link/link.min.css +2 -2
- package/libs/components/list/list.css +1 -1
- package/libs/components/list/list.min.css +1 -1
- package/libs/components/nav/nav.css +1 -1
- package/libs/components/nav/nav.css.map +1 -1
- package/libs/components/nav/nav.min.css +2 -2
- package/libs/components/progress/progress.css +1 -1
- package/libs/components/progress/progress.css.map +1 -1
- package/libs/components/progress/progress.min.css +2 -2
- package/libs/components/tag/tag.css +1 -1
- package/libs/components/tag/tag.css.map +1 -1
- package/libs/components/tag/tag.min.css +2 -2
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/package.json +4 -3
- package/src/components/README.mdx +1 -1
- package/src/components/alert/alert.scss +4 -4
- package/src/components/alert/alert.scss.backup +184 -0
- package/src/components/alert/alert.stories.tsx +53 -2
- package/src/components/badge/badge.scss +2 -2
- package/src/components/badge/badge.scss.backup +39 -0
- package/src/components/badge/badge.stories.tsx +40 -0
- package/src/components/breadcrumbs/breadcrumb.scss +5 -5
- package/src/components/breadcrumbs/breadcrumb.scss.backup +35 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +17 -1
- package/src/components/buttons/button.scss +32 -27
- package/src/components/buttons/button.scss.backup +145 -0
- package/src/components/buttons/button.stories.tsx +196 -7
- package/src/components/cards/card.scss +39 -5
- package/src/components/cards/card.scss.backup +67 -0
- package/src/components/cards/card.stories.tsx +184 -1
- package/src/components/details/details.scss +14 -14
- package/src/components/details/details.scss.backup +126 -0
- package/src/components/details/details.stories.tsx +41 -1
- package/src/components/dialog/dialog.scss +3 -3
- package/src/components/dialog/dialog.scss.backup +126 -0
- package/src/components/form/form.scss +25 -9
- package/src/components/form/form.scss.backup +87 -0
- package/src/components/form/form.stories.tsx +272 -1
- package/src/components/form/input.stories.tsx +159 -1
- package/src/components/form/select.stories.tsx +1 -1
- package/src/components/heading/README.mdx +292 -0
- package/src/components/icons/icon.stories.tsx +1 -1
- package/src/components/images/figure.stories.tsx +41 -1
- package/src/components/images/img.scss +8 -8
- package/src/components/images/img.scss.backup +59 -0
- package/src/components/layout/_header.scss +14 -14
- package/src/components/layout/_header.scss.backup +72 -0
- package/src/components/layout/landmarks.scss +7 -7
- package/src/components/layout/landmarks.scss.backup +51 -0
- package/src/components/layout/landmarks.stories.tsx +42 -0
- package/src/components/link/link.scss +5 -5
- package/src/components/link/link.scss.backup +145 -0
- package/src/components/link/link.stories.tsx +38 -2
- package/src/components/list/list.scss +1 -1
- package/src/components/nav/nav.scss +17 -17
- package/src/components/nav/nav.scss.backup +123 -0
- package/src/components/nav/nav.stories.tsx +36 -2
- package/src/components/progress/progress.scss +7 -7
- package/src/components/progress/progress.scss.backup +70 -0
- package/src/components/tag/tag.scss +10 -10
- package/src/components/tag/tag.scss.backup +130 -0
- package/src/components/tag/tag.stories.tsx +23 -2
- package/src/components/ui.stories.tsx +53 -19
- package/src/docs/accessibility.mdx +484 -0
- package/src/docs/composition.mdx +549 -0
- package/src/docs/css-variables.mdx +380 -0
- package/src/docs/fpkit-developer.mdx +545 -0
- package/src/introduction.mdx +356 -0
- package/src/styles/alert/alert.css +4 -4
- package/src/styles/badge/badge.css +2 -2
- package/src/styles/breadcrumbs/breadcrumb.css +5 -5
- package/src/styles/buttons/button.css +30 -27
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/cards/card.css +35 -5
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/details/details.css +14 -14
- package/src/styles/dialog/dialog.css +3 -3
- package/src/styles/form/form.css +20 -10
- package/src/styles/form/form.css.map +1 -1
- package/src/styles/images/img.css +8 -8
- package/src/styles/index.css +179 -134
- package/src/styles/index.css.map +1 -1
- package/src/styles/layout/landmarks.css +21 -21
- package/src/styles/link/link.css +5 -5
- package/src/styles/list/list.css +1 -1
- package/src/styles/nav/nav.css +17 -17
- package/src/styles/progress/progress.css +6 -6
- package/src/styles/tag/tag.css +4 -4
- 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-
|
|
4
|
-
--breadcrumb-
|
|
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-
|
|
13
|
-
display: var(--breadcrumb-
|
|
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-
|
|
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
|
-
|
|
3
|
-
--btn-
|
|
4
|
-
--btn-
|
|
5
|
-
--btn-
|
|
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-
|
|
17
|
-
padding-block: var(--btn-
|
|
18
|
-
border: var(--btn-
|
|
19
|
-
border-radius: var(--btn-
|
|
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-
|
|
22
|
-
display: var(--btn-
|
|
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-
|
|
25
|
-
margin: var(--btn-
|
|
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-
|
|
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-
|
|
85
|
+
--btn-border: gray thin solid;
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
&[type="submit"] {
|
|
83
89
|
--btn-bg: var(--primary-700, blue);
|
|
84
|
-
--btn-
|
|
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-
|
|
133
|
-
--btn-
|
|
137
|
+
--btn-color: currentColor;
|
|
138
|
+
--btn-border: none;
|
|
134
139
|
--btn-height: unset;
|
|
135
140
|
--btn-width: unset;
|
|
136
|
-
--btn-
|
|
137
|
-
--btn-
|
|
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-
|
|
140
|
-
outline: 0.025rem solid var(--btn-
|
|
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: ["
|
|
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(
|
|
153
|
-
|
|
154
|
-
|
|
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-
|
|
185
|
-
"--btn-
|
|
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
|
-
|
|
2
|
+
// Base card properties
|
|
3
|
+
--card-padding: 2rem;
|
|
3
4
|
--card-bg: #fff;
|
|
4
|
-
--card-radius: calc(var(--card-
|
|
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-
|
|
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-
|
|
51
|
+
padding-block-end: var(--card-padding);
|
|
40
52
|
}
|
|
41
53
|
> *:first-child:not(img) {
|
|
42
|
-
padding-block-start: calc(var(--card-
|
|
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
|
|