ab-nextjs-components 0.1.11 → 0.1.12
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/CHANGELOG.md +7 -0
- package/README.md +8 -0
- package/ab-button/helpers.ts +3 -1
- package/ab-button/index.tsx +2 -1
- package/ab-button/styles.module.css +11 -0
- package/ab-install-snippet/styles.module.css +16 -6
- package/package.json +3 -3
- package/server/ab-button/index.tsx +1 -1
- package/server/ab-button/styles.module.css +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## 0.1.12 — 2026-10-16
|
|
2
|
+
|
|
3
|
+
* ♿ **AbInstallSnippet tabs pass AA in every state.** Each state now paints an explicit text/background pair from the live palette instead of a transparent tab and a 12% bronze tint: inactive `on-surface-variant` on `surface-container` (8.04:1 light / 9.67:1 dark), hover `on-surface` on an 8% `on-surface` state layer (12.63:1 / 10.39:1), active and active + hover `on-primary-container` on `primary-container` (13.28:1 / 7.22:1). Fallbacks are the light bronze palette, so it also passes without the theme
|
|
4
|
+
* 🥉 **New `AbButton type="filled"`** (client + server): solid bronze `--md-sys-color-primary` with `on-primary` label and icon. Sets `data-type="filled"`, styled with hover / focus / disabled by `ab-nextjs-theme@^0.3.3`; a `.isFilled` fallback paints the rest state on older themes. `AbButtonType` gains `'filled'`
|
|
5
|
+
* ⬆️ **`ab-nextjs-theme ^0.3.3`** (peer + dev, was `^0.3.1`) for the filled hover / focus / disabled states and the button icon-colour fix. The `.isFilled` fallback stays for apps still on an older theme
|
|
6
|
+
* Tests: contrast computed from the theme palette (light + dark, every state, plus the no-theme fallbacks); filled type on client + server twins. Checked in WebKit (ratios above; filled 6.47:1 light / 7.74:1 dark)
|
|
7
|
+
|
|
1
8
|
## 0.1.11 — 2026-10-15
|
|
2
9
|
|
|
3
10
|
* 🐛 **AbFlowDiagram: nodes no longer cover the header in small boxes.** At 390px wide the Live Playground's top node ("core") sat under the "Live Playground" header. With a header (title, live dot or caption) the root now gets `data-ab-header="true"`, and nodes + wires live in a stage that starts below the header band: `--ab-flow-diagram-inset-top` (default `2.75rem`, tunable). Node `x` / `y` stay 0–100 but now map onto that stage, and the wires share the same box so they still meet the nodes. Without a header the stage is the full card (unchanged)
|
package/README.md
CHANGED
|
@@ -66,6 +66,14 @@ Shipped assets: `assets/logos/ab-logo.svg`, `assets/spinners/3-dots-scale.svg`,
|
|
|
66
66
|
* `<AbLogo>` defaults to the Ab logo **shipped in this package** (data URI / `ab-logo/ab-logo.svg`). Pass `src` to override.
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
### Buttons & install snippet (0.1.12)
|
|
70
|
+
|
|
71
|
+
* `<AbButton type="filled">` 🥉 is a solid bronze button (`--md-sys-color-primary` background, `--md-sys-color-on-primary` label and icon). It sets `data-type="filled"`, which **`ab-nextjs-theme@^0.3.3`** styles with hover, focus and disabled states. On older themes a built-in fallback still paints the solid bronze rest state.
|
|
72
|
+
```tsx
|
|
73
|
+
<AbButton type="filled" label="Get started" />
|
|
74
|
+
```
|
|
75
|
+
* `<AbInstallSnippet>` tabs are **≥ 4.5:1** (WCAG AA) in light and dark, active, inactive and hover: inactive = on-surface-variant on surface-container, hover = on-surface on an 8% state layer, active = on-primary-container on primary-container.
|
|
76
|
+
|
|
69
77
|
## Getting Started
|
|
70
78
|
|
|
71
79
|
### Installation
|
package/ab-button/helpers.ts
CHANGED
|
@@ -37,7 +37,9 @@
|
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
// 🎨 visual types shared by the client + server twins
|
|
40
|
-
|
|
40
|
+
// 🥉 'filled' (0.1.12): solid bronze, painted by ab-nextjs-theme ≥ 0.3.3's
|
|
41
|
+
// `button[data-type="filled"]` rule (fallback in styles.module.css → .isFilled)
|
|
42
|
+
export type AbButtonType = 'contained' | 'filled' | 'outlined' | 'text';
|
|
41
43
|
// 🎨 colour roles
|
|
42
44
|
export type AbButtonColor = 'primary' | 'secondary' | 'tertiary' | 'white' | 'black';
|
|
43
45
|
// 🏷️ badge tones (G22): neutral grey or bronze accent
|
package/ab-button/index.tsx
CHANGED
|
@@ -63,7 +63,7 @@ export type { AbButtonBadgeTone, AbButtonColor, AbButtonType, AbButtonDisabledMo
|
|
|
63
63
|
// ⚙️ props
|
|
64
64
|
export interface AbButtonProps {
|
|
65
65
|
id?: string; // 🆔
|
|
66
|
-
type?: AbButtonType; // 🎨 contained / outlined / text
|
|
66
|
+
type?: AbButtonType; // 🎨 contained / filled 🥉 / outlined / text
|
|
67
67
|
htmlType?: 'button' | 'submit' | 'reset'; // 🧾
|
|
68
68
|
className?: string; // 🏷️
|
|
69
69
|
spinnerClassName?: string; // ⏳ spinner class
|
|
@@ -140,6 +140,7 @@ const AbButton = forwardRef<HTMLButtonElement | HTMLAnchorElement, AbButtonProps
|
|
|
140
140
|
className, // 🏷️
|
|
141
141
|
rounded && styles.abButtonRounded, // 💊
|
|
142
142
|
type === 'contained' && styles.isContained, // 🎨
|
|
143
|
+
type === 'filled' && styles.isFilled, // 🥉 solid bronze (theme ≥ 0.3.3 paints it, this is the fallback)
|
|
143
144
|
mode === 'native' && styles.isDisabled, // 🚫
|
|
144
145
|
);
|
|
145
146
|
|
|
@@ -62,6 +62,17 @@
|
|
|
62
62
|
|
|
63
63
|
.isContained {}
|
|
64
64
|
|
|
65
|
+
/* 🥉 Filled (0.1.12): solid bronze fallback for apps on ab-nextjs-theme < 0.3.3.
|
|
66
|
+
* Theme ≥ 0.3.3 ships `button[data-type="filled"]` (higher specificity), which
|
|
67
|
+
* adds the hover / focus / disabled state layers on top of this 🎨 */
|
|
68
|
+
.isFilled {
|
|
69
|
+
--material-icon-color: var(--ab-button-text-color, var(--md-sys-color-on-primary, #fff)); /* 🎨 icon = label */
|
|
70
|
+
|
|
71
|
+
background: var(--ab-button-background-color, var(--md-sys-color-primary, rgb(133 83 24)));
|
|
72
|
+
color: var(--ab-button-text-color, var(--md-sys-color-on-primary, #fff));
|
|
73
|
+
font-weight: bold;
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
.isDisabled {
|
|
66
77
|
pointer-events: none;
|
|
67
78
|
opacity: 0.6;
|
|
@@ -53,21 +53,31 @@
|
|
|
53
53
|
gap: 0.25rem; /* 🧱 */
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
/* 🔘 tab
|
|
56
|
+
/* 🔘 tab
|
|
57
|
+
* ♿ 0.1.12: every state is an explicit text/background pair from the live
|
|
58
|
+
* Material palette, so it is ≥ 4.5:1 in light AND dark (tested in
|
|
59
|
+
* __tests__/ab-install-snippet-contrast.test.ts). Fallbacks are the light
|
|
60
|
+
* bronze palette, for apps that don't load the theme 🎨 */
|
|
57
61
|
.tab {
|
|
58
62
|
min-height: 28px; /* 📏 ≥ 24px target */
|
|
59
63
|
padding: 0.25rem 0.625rem; /* 🧱 */
|
|
60
64
|
border: 0; /* 🧹 */
|
|
61
65
|
border-radius: 9999px; /* 💊 */
|
|
62
|
-
background:
|
|
63
|
-
color: var(--ab-color-on-surface-variant,
|
|
66
|
+
background: var(--ab-color-surface-container, var(--md-sys-color-surface-container, rgb(252 235 226))); /* 🫥 inactive = card surface */
|
|
67
|
+
color: var(--ab-color-on-surface-variant, var(--md-sys-color-on-surface-variant, rgb(80 69 58))); /* 🎨 inactive label */
|
|
64
68
|
font: inherit; /* 🔤 */
|
|
65
69
|
font-size: 0.8125rem; /* 🔡 */
|
|
66
70
|
cursor: pointer; /* 👆 */
|
|
67
71
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
background: color-mix(in srgb, var(--ab-color-
|
|
72
|
+
/* 🖱️ hover (inactive): 8% on-surface state layer + full on-surface label */
|
|
73
|
+
.tab:hover {
|
|
74
|
+
background: color-mix(in srgb, var(--ab-color-on-surface, var(--md-sys-color-on-surface, rgb(34 26 21))) 8%, var(--ab-color-surface-container, var(--md-sys-color-surface-container, rgb(252 235 226))));
|
|
75
|
+
color: var(--ab-color-on-surface, var(--md-sys-color-on-surface, rgb(34 26 21)));
|
|
76
|
+
}
|
|
77
|
+
/* ✅ active (and active + hover): solid bronze container + its on-colour */
|
|
78
|
+
.tab[aria-selected='true'], .tab[aria-selected='true']:hover {
|
|
79
|
+
background: var(--md-sys-color-primary-container, rgb(255 220 189)); /* 🥉 */
|
|
80
|
+
color: var(--md-sys-color-on-primary-container, rgb(44 22 0)); /* ♿ */
|
|
71
81
|
font-weight: 600; /* 💪 */
|
|
72
82
|
}
|
|
73
83
|
.tab:focus-visible {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ab-nextjs-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "🚀 A lightweight collection of server & client React components created by Abraham Ukachi, and optimized for Next.js applications 😎.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"ab-nextjs-animations": "^0.2.4",
|
|
44
44
|
"ab-nextjs-hooks": "^0.1.6",
|
|
45
45
|
"ab-nextjs-icons": "^0.2.3",
|
|
46
|
-
"ab-nextjs-theme": "^0.3.
|
|
46
|
+
"ab-nextjs-theme": "^0.3.3",
|
|
47
47
|
"clsx": "^2",
|
|
48
48
|
"next": "^16.3.4",
|
|
49
49
|
"react": "^19",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"ab-nextjs-animations": "^0.2.4",
|
|
57
57
|
"ab-nextjs-hooks": "^0.1.6",
|
|
58
58
|
"ab-nextjs-icons": "^0.2.3",
|
|
59
|
-
"ab-nextjs-theme": "^0.3.
|
|
59
|
+
"ab-nextjs-theme": "^0.3.3",
|
|
60
60
|
"clsx": "^2.1.1",
|
|
61
61
|
"esbuild": "^0.28.2",
|
|
62
62
|
"eslint": "^9.39.0",
|
|
@@ -94,7 +94,7 @@ const AbButton = ({
|
|
|
94
94
|
const srReason = getAbButtonSrReason({ disabled, disabledReason });
|
|
95
95
|
|
|
96
96
|
// 🏷️ classes
|
|
97
|
-
const classNames = clsx('AbButton', styles.abButton, className, rounded && styles.abButtonRounded, mode === 'native' && styles.isDisabled);
|
|
97
|
+
const classNames = clsx('AbButton', styles.abButton, className, rounded && styles.abButtonRounded, type === 'filled' && styles.isFilled /* 🥉 */, mode === 'native' && styles.isDisabled);
|
|
98
98
|
|
|
99
99
|
// 🗂️ data attributes
|
|
100
100
|
const dataAttrs = {
|
|
@@ -62,6 +62,17 @@
|
|
|
62
62
|
|
|
63
63
|
.isContained {}
|
|
64
64
|
|
|
65
|
+
/* 🥉 Filled (0.1.12): solid bronze fallback for apps on ab-nextjs-theme < 0.3.3.
|
|
66
|
+
* Theme ≥ 0.3.3 ships `button[data-type="filled"]` (higher specificity), which
|
|
67
|
+
* adds the hover / focus / disabled state layers on top of this 🎨 */
|
|
68
|
+
.isFilled {
|
|
69
|
+
--material-icon-color: var(--ab-button-text-color, var(--md-sys-color-on-primary, #fff)); /* 🎨 icon = label */
|
|
70
|
+
|
|
71
|
+
background: var(--ab-button-background-color, var(--md-sys-color-primary, rgb(133 83 24)));
|
|
72
|
+
color: var(--ab-button-text-color, var(--md-sys-color-on-primary, #fff));
|
|
73
|
+
font-weight: bold;
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
.isDisabled {
|
|
66
77
|
pointer-events: none;
|
|
67
78
|
opacity: 0.6;
|