@fpkit/acss 6.2.0 → 6.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-25KCUE3R.cjs +17 -0
- package/libs/chunk-25KCUE3R.cjs.map +1 -0
- package/libs/chunk-34NWHFHP.js +10 -0
- package/libs/chunk-34NWHFHP.js.map +1 -0
- package/libs/{chunk-SQ44OCJ2.js → chunk-6NMLU5FA.js} +2 -2
- package/libs/{chunk-GVVCXXKI.cjs → chunk-6YVR4TDM.cjs} +3 -3
- package/libs/chunk-DSQ2TUCR.js +7 -0
- package/libs/chunk-DSQ2TUCR.js.map +1 -0
- package/libs/{chunk-H6A2CUWA.js → chunk-VQTCTLFN.js} +2 -2
- package/libs/chunk-ZJ4RUKI2.cjs +14 -0
- package/libs/chunk-ZJ4RUKI2.cjs.map +1 -0
- package/libs/{chunk-H4JRUNKU.cjs → chunk-ZOPHCNFD.cjs} +3 -3
- package/libs/components/button.cjs +3 -3
- package/libs/components/button.d.cts +34 -1
- package/libs/components/button.d.ts +34 -1
- package/libs/components/button.js +1 -1
- 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/buttons/icon-button.css +1 -0
- package/libs/components/buttons/icon-button.css.map +1 -0
- package/libs/components/buttons/icon-button.min.css +3 -0
- package/libs/components/dialog/dialog.cjs +4 -4
- package/libs/components/dialog/dialog.js +2 -2
- package/libs/components/icons/icon.d.cts +1 -1
- package/libs/components/icons/icon.d.ts +1 -1
- package/libs/components/link/link.css +1 -1
- package/libs/components/link/link.min.css +1 -1
- package/libs/components/modal.cjs +3 -3
- package/libs/components/modal.js +2 -2
- package/libs/components/popover/popover.cjs +3 -8
- package/libs/components/popover/popover.css +1 -0
- package/libs/components/popover/popover.css.map +1 -0
- package/libs/components/popover/popover.d.cts +54 -26
- package/libs/components/popover/popover.d.ts +54 -26
- package/libs/components/popover/popover.js +1 -2
- package/libs/components/popover/popover.min.css +3 -0
- package/libs/hooks.cjs +3 -6
- package/libs/hooks.cjs.map +1 -1
- package/libs/hooks.d.cts +30 -10
- package/libs/hooks.d.ts +30 -10
- package/libs/hooks.js +5 -1
- package/libs/hooks.js.map +1 -1
- package/libs/{icons-48788561.d.ts → icons-2c09535c.d.ts} +32 -32
- package/libs/icons.d.cts +1 -1
- package/libs/icons.d.ts +1 -1
- package/libs/index.cjs +35 -35
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +64 -5
- package/libs/index.d.ts +64 -5
- package/libs/index.js +9 -10
- package/libs/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/buttons/README.mdx +107 -11
- package/src/components/buttons/STYLES.mdx +182 -47
- package/src/components/buttons/button.scss +93 -16
- package/src/components/buttons/button.stories.tsx +149 -0
- package/src/components/buttons/button.test.tsx +12 -0
- package/src/components/buttons/button.tsx +50 -6
- package/src/components/buttons/icon-button.scss +45 -0
- package/src/components/buttons/icon-button.stories.tsx +200 -0
- package/src/components/buttons/icon-button.test.tsx +132 -0
- package/src/components/buttons/icon-button.tsx +72 -0
- package/src/components/form/select.tsx +55 -51
- package/src/components/link/link.scss +2 -2
- package/src/components/popover/README.mdx +478 -0
- package/src/components/popover/STYLES.mdx +389 -0
- package/src/components/popover/index.ts +3 -0
- package/src/components/popover/popover.scss +249 -0
- package/src/components/popover/popover.stories.tsx +315 -15
- package/src/components/popover/popover.test.tsx +249 -37
- package/src/components/popover/popover.tsx +165 -62
- package/src/hooks/popover/popover.tsx +26 -10
- package/src/hooks/popover/use-popover.tsx +30 -10
- package/src/hooks.ts +5 -0
- package/src/index.scss +1 -0
- package/src/index.ts +1 -0
- package/src/styles/buttons/button.css +78 -16
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/buttons/icon-button.css +32 -0
- package/src/styles/buttons/icon-button.css.map +1 -0
- package/src/styles/index.css +268 -18
- package/src/styles/index.css.map +1 -1
- package/src/styles/link/link.css +2 -2
- package/src/styles/popover/popover.css +190 -0
- package/src/styles/popover/popover.css.map +1 -0
- package/src/types/popover.d.ts +64 -0
- package/libs/chunk-4I5MF54P.js +0 -8
- package/libs/chunk-4I5MF54P.js.map +0 -1
- package/libs/chunk-GCGKYLDG.js +0 -7
- package/libs/chunk-GCGKYLDG.js.map +0 -1
- package/libs/chunk-NZVSXRTB.cjs +0 -16
- package/libs/chunk-NZVSXRTB.cjs.map +0 -1
- package/libs/chunk-PDD4N5P5.cjs +0 -10
- package/libs/chunk-PDD4N5P5.cjs.map +0 -1
- package/libs/chunk-S7NIA6PI.cjs +0 -17
- package/libs/chunk-S7NIA6PI.cjs.map +0 -1
- package/libs/chunk-X2RDXWH5.js +0 -10
- package/libs/chunk-X2RDXWH5.js.map +0 -1
- /package/libs/{chunk-SQ44OCJ2.js.map → chunk-6NMLU5FA.js.map} +0 -0
- /package/libs/{chunk-GVVCXXKI.cjs.map → chunk-6YVR4TDM.cjs.map} +0 -0
- /package/libs/{chunk-H6A2CUWA.js.map → chunk-VQTCTLFN.js.map} +0 -0
- /package/libs/{chunk-H4JRUNKU.cjs.map → chunk-ZOPHCNFD.cjs.map} +0 -0
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": "6.
|
|
5
|
+
"version": "6.3.0",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=22.12.0",
|
|
8
8
|
"npm": ">=8.0.0"
|
|
@@ -123,5 +123,5 @@
|
|
|
123
123
|
"publishConfig": {
|
|
124
124
|
"access": "public"
|
|
125
125
|
},
|
|
126
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "267091cf42709bbb5e74aa9b1d75bc2ced157b04"
|
|
127
127
|
}
|
|
@@ -18,16 +18,21 @@ supports various types and styles. It is designed to be reusable and accessible.
|
|
|
18
18
|
|
|
19
19
|
## Props
|
|
20
20
|
|
|
21
|
-
| Name | Type
|
|
22
|
-
| ---------------- |
|
|
23
|
-
| `type` | `'button' \| 'submit' \| 'reset'`
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
21
|
+
| Name | Type | Default | Description |
|
|
22
|
+
| ---------------- | ----------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------- |
|
|
23
|
+
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | The button type |
|
|
24
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | - | Size variant — merged into `data-btn` |
|
|
25
|
+
| `variant` | `'text' \| 'pill' \| 'icon' \| 'outline'` | - | Style variant — maps to `data-style` |
|
|
26
|
+
| `color` | `'primary' \| 'secondary' \| 'danger' \| 'success' \| 'warning'` | - | Color variant using semantic tokens — maps to `data-color` |
|
|
27
|
+
| `block` | `boolean` | - | Stretches button to 100% container width — merged into `data-btn` as `"block"` |
|
|
28
|
+
| `"data-btn"` | `string` | - | Raw `data-btn` tokens. Merged with `size` and `block` into the final attribute. `data-btn` tokens take precedence over `size` tokens — if both conflict, `data-btn` wins. |
|
|
29
|
+
| `styles` | `React.CSSProperties` | - | Inline styles — use to override CSS custom properties e.g. `--btn-bg` |
|
|
30
|
+
| `disabled` | `boolean` | `false` | Disables the button using the `aria-disabled` pattern (stays keyboard-focusable) |
|
|
31
|
+
| `classes` | `string` | - | Additional CSS classes (merged automatically with `.is-disabled` when disabled) |
|
|
32
|
+
| `onPointerDown` | `(e: React.PointerEvent<HTMLButtonElement>) => void` | - | Callback for pointer down event |
|
|
33
|
+
| `onPointerOver` | `(e: React.PointerEvent<HTMLButtonElement>) => void` | - | Callback for pointer over event |
|
|
34
|
+
| `onPointerLeave` | `(e: React.PointerEvent<HTMLButtonElement>) => void` | - | Callback for pointer leave event |
|
|
35
|
+
| `onClick` | `(e: React.MouseEvent<HTMLButtonElement>) => void` | - | Callback for click event |
|
|
31
36
|
|
|
32
37
|
## Technical Details
|
|
33
38
|
|
|
@@ -56,6 +61,85 @@ const BasicButton = () => (
|
|
|
56
61
|
export default BasicButton;
|
|
57
62
|
```
|
|
58
63
|
|
|
64
|
+
### Size, Variant & Color Props
|
|
65
|
+
|
|
66
|
+
The `size`, `variant`, and `color` props provide a typed React API over the
|
|
67
|
+
underlying `data-*` attributes. This gives consumers autocomplete and type
|
|
68
|
+
safety without needing to know the attribute names.
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import Button from "#components/buttons/button";
|
|
72
|
+
|
|
73
|
+
// Size variants
|
|
74
|
+
<Button type="button" size="xs">Extra Small</Button>
|
|
75
|
+
<Button type="button" size="sm">Small</Button>
|
|
76
|
+
<Button type="button" size="lg">Large</Button>
|
|
77
|
+
<Button type="button" size="xl">Extra Large</Button>
|
|
78
|
+
<Button type="button" size="2xl">2X Large</Button>
|
|
79
|
+
|
|
80
|
+
// Style variants
|
|
81
|
+
<Button type="button" variant="outline">Outline</Button>
|
|
82
|
+
<Button type="button" variant="pill">Pill</Button>
|
|
83
|
+
<Button type="button" variant="text">Text Button</Button>
|
|
84
|
+
<Button type="button" variant="icon" aria-label="Close">✕</Button>
|
|
85
|
+
|
|
86
|
+
// Color variants (use semantic design tokens)
|
|
87
|
+
<Button type="button" color="primary">Primary</Button>
|
|
88
|
+
<Button type="button" color="secondary">Secondary</Button>
|
|
89
|
+
<Button type="button" color="danger">Delete</Button>
|
|
90
|
+
<Button type="button" color="success">Confirm</Button>
|
|
91
|
+
<Button type="button" color="warning">Warning</Button>
|
|
92
|
+
|
|
93
|
+
// Combine props freely
|
|
94
|
+
<Button type="button" color="primary" variant="outline" size="lg">
|
|
95
|
+
Large Primary Outline
|
|
96
|
+
</Button>
|
|
97
|
+
<Button type="button" color="danger" variant="pill">Danger Pill</Button>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Note:** `size`, `block`, and `data-btn` are all merged into a single
|
|
101
|
+
whitespace-separated `data-btn` attribute. `<Button size="lg" block data-btn="pill">`
|
|
102
|
+
resolves to `data-btn="lg block pill"`.
|
|
103
|
+
|
|
104
|
+
### Block Layout
|
|
105
|
+
|
|
106
|
+
The `block` prop stretches the button to 100% of its container width. It
|
|
107
|
+
composes freely with `size` and other `data-btn` tokens.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<Button type="button" block>Full Width</Button>
|
|
111
|
+
<Button type="button" size="lg" block color="primary">Large Full Width Primary</Button>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### IconButton
|
|
115
|
+
|
|
116
|
+
`IconButton` wraps `Button` with enforced accessibility and icon-specific defaults.
|
|
117
|
+
It requires exactly one of `aria-label` or `aria-labelledby` (XOR — passing
|
|
118
|
+
both or neither is a TypeScript compile-time error).
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { IconButton } from "@fpkit/acss";
|
|
122
|
+
|
|
123
|
+
// Icon only
|
|
124
|
+
<IconButton type="button" aria-label="Close menu" icon={<CloseIcon />} />
|
|
125
|
+
|
|
126
|
+
// Icon + visible label (label hides on mobile, stays in a11y tree)
|
|
127
|
+
<IconButton
|
|
128
|
+
type="button"
|
|
129
|
+
aria-label="Settings"
|
|
130
|
+
icon={<SettingsIcon />}
|
|
131
|
+
label="Settings"
|
|
132
|
+
variant="outline"
|
|
133
|
+
/>
|
|
134
|
+
|
|
135
|
+
// Labelled by external element
|
|
136
|
+
<span id="btn-lbl">Delete item</span>
|
|
137
|
+
<IconButton type="button" aria-labelledby="btn-lbl" icon={<TrashIcon />} />
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Defaults:** `variant="icon"` (transparent bg, `currentColor` icon color, square touch target).
|
|
141
|
+
Override `variant` to restore padding when using a `label`.
|
|
142
|
+
|
|
59
143
|
### Advanced Usage
|
|
60
144
|
|
|
61
145
|
```tsx
|
|
@@ -77,7 +161,8 @@ const handlePointerLeave = (e: React.PointerEvent<HTMLButtonElement>) => {
|
|
|
77
161
|
const AdvancedButton = () => (
|
|
78
162
|
<Button
|
|
79
163
|
type="submit"
|
|
80
|
-
|
|
164
|
+
color="primary"
|
|
165
|
+
size="lg"
|
|
81
166
|
onPointerDown={handlePointerDown}
|
|
82
167
|
onPointerOver={handlePointerOver}
|
|
83
168
|
onPointerLeave={handlePointerLeave}
|
|
@@ -150,6 +235,10 @@ When `disabled={true}`:
|
|
|
150
235
|
- ✅ Hover effects still work (visual feedback)
|
|
151
236
|
- ✅ Can receive focus for tooltips/help text
|
|
152
237
|
|
|
238
|
+
### Handler Precedence When Disabled
|
|
239
|
+
|
|
240
|
+
When `disabled` or `isDisabled` is set, built-in pointer handlers (`onPointerDown`, `onPointerOver`, `onPointerLeave`, `onClick`) take precedence over any handlers passed via props. This prevents interaction callbacks from firing on a disabled button.
|
|
241
|
+
|
|
153
242
|
### Migration Guide
|
|
154
243
|
|
|
155
244
|
No breaking changes! The API remains the same:
|
|
@@ -205,3 +294,10 @@ This implementation follows:
|
|
|
205
294
|
- The `styles` prop can be used to apply inline styles to the button.
|
|
206
295
|
- The `disabled` prop uses the accessible `aria-disabled` pattern instead of
|
|
207
296
|
native `disabled` attribute.
|
|
297
|
+
- **Breaking (height):** The `--btn-height` multiplier changed from `2.25` to
|
|
298
|
+
`2.75`. All buttons are ~22% taller. Override `--btn-height` via the `styles`
|
|
299
|
+
prop or a stylesheet rule to restore previous sizing.
|
|
300
|
+
- **Breaking (`.btn-pill`):** The `.btn-pill` CSS class is now scoped to
|
|
301
|
+
`button.btn-pill` only. Non-button elements carrying the class no longer
|
|
302
|
+
receive pill border-radius. Prefer `variant="pill"` (React) or
|
|
303
|
+
`data-style="pill"` / `data-btn="pill"` (HTML) instead.
|
|
@@ -16,8 +16,9 @@ accessibility.
|
|
|
16
16
|
|
|
17
17
|
### Key Features
|
|
18
18
|
|
|
19
|
-
- **Size variants** - Extra small (xs) through large (
|
|
20
|
-
- **Style variants** - Pill, icon, and text button styles
|
|
19
|
+
- **Size variants** - Extra small (xs) through 2X large (2xl) with fluid typography
|
|
20
|
+
- **Style variants** - Pill, outline, icon, and text button styles via `data-style`
|
|
21
|
+
- **Color variants** - Semantic color tokens (primary, secondary, danger, success, warning) via `data-color`
|
|
21
22
|
- **Type-based styling** - Automatic styling for submit, reset button types
|
|
22
23
|
- **State management** - Hover, focus, and disabled states with smooth
|
|
23
24
|
transitions
|
|
@@ -37,13 +38,15 @@ button {
|
|
|
37
38
|
--btn-size-xs: 0.6875rem; /* 11px */
|
|
38
39
|
--btn-size-sm: 0.8125rem; /* 13px */
|
|
39
40
|
--btn-size-md: 0.9375rem; /* 15px */
|
|
40
|
-
--btn-size-lg: 1.125rem;
|
|
41
|
+
--btn-size-lg: 1.125rem; /* 18px */
|
|
42
|
+
--btn-size-xl: 1.375rem; /* 22px */
|
|
43
|
+
--btn-size-2xl: 1.75rem; /* 28px */
|
|
41
44
|
|
|
42
45
|
/* Default font size */
|
|
43
46
|
--btn-fs: var(--btn-size-md);
|
|
44
47
|
|
|
45
48
|
/* Dynamic height based on font size */
|
|
46
|
-
--btn-height: calc(var(--btn-fs) * 2.
|
|
49
|
+
--btn-height: calc(var(--btn-fs) * 2.75); /* ⚠️ changed from * 2.25, see CHANGELOG */
|
|
47
50
|
}
|
|
48
51
|
```
|
|
49
52
|
|
|
@@ -56,8 +59,8 @@ button {
|
|
|
56
59
|
--btn-fw: 500; /* Font weight */
|
|
57
60
|
|
|
58
61
|
/* Colors */
|
|
59
|
-
--btn-bg:
|
|
60
|
-
--btn-color:
|
|
62
|
+
--btn-bg: var(--color-primary); /* Background color — ⚠️ changed from color-neutral-300, see CHANGELOG */
|
|
63
|
+
--btn-color: var(--color-text-inverse); /* Text color */
|
|
61
64
|
|
|
62
65
|
/* Spacing */
|
|
63
66
|
--btn-padding-inline: calc(var(--btn-fs) * 1.5); /* Horizontal padding */
|
|
@@ -71,7 +74,7 @@ button {
|
|
|
71
74
|
|
|
72
75
|
/* Layout */
|
|
73
76
|
--btn-width: max-content; /* Button width */
|
|
74
|
-
--btn-height: calc(var(--btn-fs) * 2.
|
|
77
|
+
--btn-height: calc(var(--btn-fs) * 2.75); /* Button height */
|
|
75
78
|
--btn-display: inline-flex; /* Display mode */
|
|
76
79
|
--btn-place: center; /* place-items value */
|
|
77
80
|
|
|
@@ -114,7 +117,7 @@ button[aria-disabled="true"] {
|
|
|
114
117
|
```css
|
|
115
118
|
button {
|
|
116
119
|
/* Pill variant */
|
|
117
|
-
--btn-pill:
|
|
120
|
+
--btn-pill: 100vw; /* Fully rounded borders */
|
|
118
121
|
}
|
|
119
122
|
```
|
|
120
123
|
|
|
@@ -153,12 +156,12 @@ Standard button with default styling:
|
|
|
153
156
|
button {
|
|
154
157
|
font-size: var(--btn-fs); /* 0.9375rem / 15px */
|
|
155
158
|
font-weight: 500;
|
|
156
|
-
height: calc(var(--btn-fs) * 2.
|
|
159
|
+
height: calc(var(--btn-fs) * 2.75);
|
|
157
160
|
padding-inline: calc(var(--btn-fs) * 1.5);
|
|
158
161
|
padding-block: calc(var(--btn-fs) * 0.5);
|
|
159
162
|
border-radius: 0.375rem;
|
|
160
|
-
background-color:
|
|
161
|
-
color:
|
|
163
|
+
background-color: var(--color-primary); /* ⚠️ breaking change — was color-neutral-300 */
|
|
164
|
+
color: var(--color-text-inverse);
|
|
162
165
|
display: inline-flex;
|
|
163
166
|
align-items: center;
|
|
164
167
|
gap: 0.2rem;
|
|
@@ -206,12 +209,15 @@ button[type="reset"] {
|
|
|
206
209
|
|
|
207
210
|
Control button size using data attributes or classes:
|
|
208
211
|
|
|
209
|
-
| Data Attribute
|
|
210
|
-
|
|
|
211
|
-
| `data-btn="xs"`
|
|
212
|
-
| `data-btn="sm"`
|
|
213
|
-
| `data-btn="md"`
|
|
214
|
-
| `data-btn="lg"`
|
|
212
|
+
| Data Attribute | Class | Font Size | Pixel Equivalent | Description |
|
|
213
|
+
| ----------------- | ----------- | ----------- | ---------------- | --------------------- |
|
|
214
|
+
| `data-btn="xs"` | `.btn-xs` | `0.6875rem` | 11px | Extra small button |
|
|
215
|
+
| `data-btn="sm"` | `.btn-sm` | `0.8125rem` | 13px | Small button |
|
|
216
|
+
| `data-btn="md"` | `.btn-md` | `0.9375rem` | 15px | Medium (default) |
|
|
217
|
+
| `data-btn="lg"` | `.btn-lg` | `1.125rem` | 18px | Large button |
|
|
218
|
+
| `data-btn="xl"` | `.btn-xl` | `1.375rem` | 22px | Extra large button |
|
|
219
|
+
| `data-btn="2xl"` | `.btn-2xl` | `1.75rem` | 28px | 2X large button |
|
|
220
|
+
| `data-btn="block"`| `.btn-block`| — | — | 100% container width |
|
|
215
221
|
|
|
216
222
|
### Examples
|
|
217
223
|
|
|
@@ -228,6 +234,12 @@ Control button size using data attributes or classes:
|
|
|
228
234
|
|
|
229
235
|
<!-- Large -->
|
|
230
236
|
<button data-btn="lg">Large Button</button>
|
|
237
|
+
|
|
238
|
+
<!-- Extra Large -->
|
|
239
|
+
<button data-btn="xl">Extra Large Button</button>
|
|
240
|
+
|
|
241
|
+
<!-- 2X Large -->
|
|
242
|
+
<button data-btn="2xl">2X Large Button</button>
|
|
231
243
|
```
|
|
232
244
|
|
|
233
245
|
### Size Customization
|
|
@@ -237,14 +249,75 @@ Height and padding scale automatically based on font size:
|
|
|
237
249
|
```css
|
|
238
250
|
button[data-btn~="lg"] {
|
|
239
251
|
--btn-fs: 1.125rem; /* 18px */
|
|
240
|
-
--btn-height: calc(1.125rem * 2.
|
|
252
|
+
--btn-height: calc(1.125rem * 2.75); /* ~3.09rem / ~49.5px */
|
|
241
253
|
--btn-padding-inline: calc(1.125rem * 1.5); /* 1.6875rem / 27px */
|
|
242
254
|
--btn-padding-block: calc(1.125rem * 0.5); /* 0.5625rem / 9px */
|
|
243
255
|
}
|
|
244
256
|
```
|
|
245
257
|
|
|
258
|
+
## Color Variants
|
|
259
|
+
|
|
260
|
+
Color variants map to semantic design tokens defined in `index.css`. Using
|
|
261
|
+
`data-color` (or the `color` prop in React) keeps button colors consistent with
|
|
262
|
+
the global color system — no hardcoded hex values needed.
|
|
263
|
+
|
|
264
|
+
| `data-color` value | Background token | Text token |
|
|
265
|
+
| ------------------ | ----------------- | ----------------------- |
|
|
266
|
+
| `primary` | `--color-primary` | `--color-text-inverse` |
|
|
267
|
+
| `secondary` | `--color-secondary` | `--color-text-inverse` |
|
|
268
|
+
| `danger` | `--color-error` | `--color-text-inverse` |
|
|
269
|
+
| `success` | `--color-success` | `--color-text-inverse` |
|
|
270
|
+
| `warning` | `--color-warning` | `--color-text-inverse` |
|
|
271
|
+
|
|
272
|
+
### HTML Usage
|
|
273
|
+
|
|
274
|
+
```html
|
|
275
|
+
<button data-color="primary">Primary</button>
|
|
276
|
+
<button data-color="secondary">Secondary</button>
|
|
277
|
+
<button data-color="danger">Delete</button>
|
|
278
|
+
<button data-color="success">Confirm</button>
|
|
279
|
+
<button data-color="warning">Warning</button>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### React Usage
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
<Button type="button" color="danger">Delete</Button>
|
|
286
|
+
<Button type="button" color="success" variant="outline">Confirm</Button>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### CSS
|
|
290
|
+
|
|
291
|
+
```css
|
|
292
|
+
button[data-color="primary"] {
|
|
293
|
+
--btn-bg: var(--color-primary);
|
|
294
|
+
--btn-color: var(--color-text-inverse);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
button[data-color="danger"] {
|
|
298
|
+
--btn-bg: var(--color-error);
|
|
299
|
+
--btn-color: var(--color-text-inverse);
|
|
300
|
+
}
|
|
301
|
+
/* etc. */
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Tip:** Color variants compose with style variants. `data-color="primary"` +
|
|
305
|
+
`data-style="outline"` gives you a transparent primary-colored outlined button.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
246
309
|
## Style Variants
|
|
247
310
|
|
|
311
|
+
Style variants are applied via the `data-style` attribute (or the `variant` prop
|
|
312
|
+
in React). Multiple values can be space-separated.
|
|
313
|
+
|
|
314
|
+
| `data-style` value | Description |
|
|
315
|
+
| ------------------ | ---------------------------------------------- |
|
|
316
|
+
| `pill` | Fully rounded corners (`border-radius: 100rem`) |
|
|
317
|
+
| `outline` | Transparent bg, border, subtle hover |
|
|
318
|
+
| `text` | Ghost button — no bg or border, subtle hover |
|
|
319
|
+
| `icon` | Square icon-only, no padding, min 1.5rem |
|
|
320
|
+
|
|
248
321
|
### Pill Button
|
|
249
322
|
|
|
250
323
|
Fully rounded button with large border radius:
|
|
@@ -259,10 +332,12 @@ Fully rounded button with large border radius:
|
|
|
259
332
|
|
|
260
333
|
```css
|
|
261
334
|
button[data-btn~="pill"] {
|
|
262
|
-
border-radius: var(--btn-pill,
|
|
335
|
+
border-radius: var(--btn-pill, 100vw);
|
|
263
336
|
}
|
|
264
337
|
```
|
|
265
338
|
|
|
339
|
+
> **⚠️ Breaking change:** The `.btn-pill` CSS class selector was scoped to `button.btn-pill` only. Applying `.btn-pill` to non-`<button>` elements (e.g. `<div>`, `<a>`) no longer sets the border-radius. Use `data-style="pill"` or `data-btn="pill"` attributes instead, which remain element-agnostic.
|
|
340
|
+
|
|
266
341
|
**Example:**
|
|
267
342
|
|
|
268
343
|
```html
|
|
@@ -304,6 +379,8 @@ button[data-btn~="icon"] {
|
|
|
304
379
|
<button data-btn="icon lg" aria-label="Menu">☰</button>
|
|
305
380
|
```
|
|
306
381
|
|
|
382
|
+
**IconButton label visibility:** When using the `IconButton` React component with the `label` prop, the label text is visually hidden below `48rem` (768px) but remains in the accessibility tree at all viewport sizes.
|
|
383
|
+
|
|
307
384
|
### Text Button
|
|
308
385
|
|
|
309
386
|
Minimal button with transparent background and subtle hover:
|
|
@@ -337,7 +414,41 @@ button[data-btn~="text"]:is(:hover, :focus) {
|
|
|
337
414
|
|
|
338
415
|
```html
|
|
339
416
|
<button data-btn="text">Learn More</button>
|
|
340
|
-
<button data-
|
|
417
|
+
<button data-style="text" style="--btn-color: #0066cc">View Details</button>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Outline Button
|
|
421
|
+
|
|
422
|
+
Transparent background with a visible border and subtle hover effect powered by
|
|
423
|
+
`color-mix()`:
|
|
424
|
+
|
|
425
|
+
```html
|
|
426
|
+
<button data-style="outline">Outline</button>
|
|
427
|
+
<button data-style="outline" data-color="primary">Primary Outline</button>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**CSS:**
|
|
431
|
+
|
|
432
|
+
```css
|
|
433
|
+
button[data-style~="outline"] {
|
|
434
|
+
--btn-bg: transparent;
|
|
435
|
+
--btn-color: currentColor;
|
|
436
|
+
--btn-border: 0.125rem solid currentColor;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
button[data-style~="outline"]:is(:hover, :focus) {
|
|
440
|
+
background-color: color-mix(in srgb, currentColor 10%, transparent);
|
|
441
|
+
outline: 0.025rem solid currentColor;
|
|
442
|
+
outline-offset: 0;
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**React:**
|
|
447
|
+
|
|
448
|
+
```tsx
|
|
449
|
+
<Button type="button" variant="outline">Outline</Button>
|
|
450
|
+
<Button type="button" color="primary" variant="outline">Primary Outline</Button>
|
|
451
|
+
<Button type="button" color="danger" variant="outline">Danger Outline</Button>
|
|
341
452
|
```
|
|
342
453
|
|
|
343
454
|
## State Styles
|
|
@@ -439,6 +550,10 @@ You can combine multiple variants using space-separated values:
|
|
|
439
550
|
### Primary Action Button
|
|
440
551
|
|
|
441
552
|
```html
|
|
553
|
+
<!-- Using semantic color token (recommended) -->
|
|
554
|
+
<button type="submit" data-btn="lg" data-color="primary">Get Started</button>
|
|
555
|
+
|
|
556
|
+
<!-- Or with custom override -->
|
|
442
557
|
<button
|
|
443
558
|
type="submit"
|
|
444
559
|
data-btn="lg"
|
|
@@ -451,10 +566,8 @@ You can combine multiple variants using space-separated values:
|
|
|
451
566
|
### Secondary Button
|
|
452
567
|
|
|
453
568
|
```html
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
style="--btn-bg: transparent; --btn-color: #1976D2; --btn-border: 2px solid #1976D2"
|
|
457
|
-
>
|
|
569
|
+
<!-- Outline style using semantic tokens -->
|
|
570
|
+
<button type="button" data-color="primary" data-style="outline">
|
|
458
571
|
Learn More
|
|
459
572
|
</button>
|
|
460
573
|
```
|
|
@@ -462,9 +575,11 @@ You can combine multiple variants using space-separated values:
|
|
|
462
575
|
### Danger Button
|
|
463
576
|
|
|
464
577
|
```html
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
578
|
+
<!-- Semantic token (recommended) -->
|
|
579
|
+
<button type="button" data-color="danger">Delete</button>
|
|
580
|
+
|
|
581
|
+
<!-- React -->
|
|
582
|
+
<!-- <Button type="button" color="danger">Delete</Button> -->
|
|
468
583
|
```
|
|
469
584
|
|
|
470
585
|
### Icon Button Group
|
|
@@ -508,8 +623,17 @@ You can combine multiple variants using space-separated values:
|
|
|
508
623
|
|
|
509
624
|
### Full Width Button
|
|
510
625
|
|
|
626
|
+
Use `data-btn="block"` (or the `block` prop in React) to stretch a button to
|
|
627
|
+
100% of its container. Composes with size and other tokens.
|
|
628
|
+
|
|
511
629
|
```html
|
|
512
|
-
<button
|
|
630
|
+
<button data-btn="block" type="submit">Continue</button>
|
|
631
|
+
<button data-btn="lg block" type="submit">Large Full Width</button>
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
```tsx
|
|
635
|
+
<Button type="submit" block>Continue</Button>
|
|
636
|
+
<Button type="submit" size="lg" block color="primary">Large Full Width Primary</Button>
|
|
513
637
|
```
|
|
514
638
|
|
|
515
639
|
## Accessibility Considerations
|
|
@@ -655,7 +779,9 @@ All button CSS variables follow the `--btn-{property}` pattern:
|
|
|
655
779
|
--btn-size-xs /* 0.6875rem / 11px */
|
|
656
780
|
--btn-size-sm /* 0.8125rem / 13px */
|
|
657
781
|
--btn-size-md /* 0.9375rem / 15px */
|
|
658
|
-
--btn-size-lg /* 1.125rem
|
|
782
|
+
--btn-size-lg /* 1.125rem / 18px */
|
|
783
|
+
--btn-size-xl /* 1.375rem / 22px */
|
|
784
|
+
--btn-size-2xl /* 1.75rem / 28px */
|
|
659
785
|
```
|
|
660
786
|
|
|
661
787
|
## Browser Support
|
|
@@ -732,27 +858,36 @@ Create reusable button classes for common patterns:
|
|
|
732
858
|
|
|
733
859
|
### From Tailwind CSS
|
|
734
860
|
|
|
735
|
-
| Tailwind | fpkit Button
|
|
736
|
-
| ------------------------------- |
|
|
737
|
-
| `class="btn btn-primary"` | `
|
|
738
|
-
| `class="btn-sm"` | `data-btn="sm"`
|
|
739
|
-
| `class="btn-lg"` | `data-btn="lg"`
|
|
740
|
-
| `class="
|
|
741
|
-
| `class="
|
|
742
|
-
| `class="btn-
|
|
743
|
-
| `class="btn-
|
|
861
|
+
| Tailwind | fpkit Button (HTML) | fpkit Button (React) |
|
|
862
|
+
| ------------------------------- | ---------------------------- | -------------------------------- |
|
|
863
|
+
| `class="btn btn-primary"` | `data-color="primary"` | `color="primary"` |
|
|
864
|
+
| `class="btn-sm"` | `data-btn="sm"` | `size="sm"` |
|
|
865
|
+
| `class="btn-lg"` | `data-btn="lg"` | `size="lg"` |
|
|
866
|
+
| `class="btn-xl"` (custom) | `data-btn="xl"` | `size="xl"` |
|
|
867
|
+
| `class="rounded-full"` | `data-style="pill"` | `variant="pill"` |
|
|
868
|
+
| `class="btn-ghost"` | `data-style="text"` | `variant="text"` |
|
|
869
|
+
| `class="btn-outline"` | `data-style="outline"` | `variant="outline"` |
|
|
870
|
+
| `class="btn-circle"` | `data-style="icon pill"` | `variant="icon"` |
|
|
871
|
+
| `class="btn-error"` | `data-color="danger"` | `color="danger"` |
|
|
872
|
+
| `class="btn-success"` | `data-color="success"` | `color="success"` |
|
|
873
|
+
| `class="btn-disabled" disabled` | `disabled` | `disabled` |
|
|
744
874
|
|
|
745
875
|
### From Bootstrap
|
|
746
876
|
|
|
747
|
-
| Bootstrap | fpkit Button
|
|
748
|
-
| --------------------------- |
|
|
749
|
-
| `class="btn btn-primary"` | `
|
|
750
|
-
| `class="btn btn-secondary"` | `
|
|
751
|
-
| `class="btn btn-
|
|
752
|
-
| `class="btn btn-
|
|
753
|
-
| `class="btn
|
|
754
|
-
| `class="btn btn-
|
|
755
|
-
| `class="btn"
|
|
877
|
+
| Bootstrap | fpkit Button (HTML) | fpkit Button (React) |
|
|
878
|
+
| --------------------------- | --------------------------------- | --------------------------- |
|
|
879
|
+
| `class="btn btn-primary"` | `data-color="primary"` | `color="primary"` |
|
|
880
|
+
| `class="btn btn-secondary"` | `data-color="secondary"` | `color="secondary"` |
|
|
881
|
+
| `class="btn btn-danger"` | `data-color="danger"` | `color="danger"` |
|
|
882
|
+
| `class="btn btn-success"` | `data-color="success"` | `color="success"` |
|
|
883
|
+
| `class="btn btn-sm"` | `data-btn="sm"` | `size="sm"` |
|
|
884
|
+
| `class="btn btn-lg"` | `data-btn="lg"` | `size="lg"` |
|
|
885
|
+
| `class="btn btn-xl"` (n/a) | `data-btn="xl"` | `size="xl"` |
|
|
886
|
+
| `class="btn btn-xxl"` (n/a) | `data-btn="2xl"` | `size="2xl"` |
|
|
887
|
+
| `class="btn rounded-pill"` | `data-style="pill"` | `variant="pill"` |
|
|
888
|
+
| `class="btn btn-outline-*"` | `data-style="outline" data-color` | `variant="outline" color` |
|
|
889
|
+
| `class="btn btn-link"` | `data-style="text"` | `variant="text"` |
|
|
890
|
+
| `class="btn" disabled` | `disabled` | `disabled` |
|
|
756
891
|
|
|
757
892
|
## Related Resources
|
|
758
893
|
|