diff --git a/examples/button-state-verification.html b/examples/button-state-verification.html new file mode 100644 index 0000000..6e0c42c --- /dev/null +++ b/examples/button-state-verification.html @@ -0,0 +1,70 @@ + + + + + + Button State Verification + + + + +

Button State Verification

+ +
+

Aria-Busy (Loading) State

+
+ + + + +
+
+ +
+

Aria-Disabled State

+
+ + + + + +
+
+ +
+

Forced States (Recipe Output Verification)

+
+ + + +
+
+ + + diff --git a/package-lock.json b/package-lock.json index 99b3e56..be9fa98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4363,6 +4363,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/src/recipes/button.ts b/src/recipes/button.ts index 9b85939..86a9f87 100644 --- a/src/recipes/button.ts +++ b/src/recipes/button.ts @@ -85,9 +85,9 @@ export function getButtonClasses(opts: ButtonRecipeOptions = {}): string { fullWidth && "sp-btn--full", loading && "sp-btn--loading", disabled && "sp-btn--disabled", - hovered && "sp-btn--hover", - focused && "sp-btn--focus", - active && "sp-btn--active", + hovered && "sp-btn--hover is-hover", + focused && "sp-btn--focus is-focus", + active && "sp-btn--active is-active", iconOnly && "sp-btn--icon", pill && "sp-btn--pill", ); diff --git a/src/styles/components.css b/src/styles/components.css index e84c02b..d869d2a 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -271,7 +271,8 @@ pointer-events: none; } - .sp-btn--loading { + .sp-btn--loading, + .sp-btn[aria-busy="true"] { pointer-events: none; opacity: var(--sp-opacity-active); } @@ -338,6 +339,7 @@ } .sp-btn--primary.sp-btn--disabled, + .sp-btn--primary[aria-disabled="true"], .sp-btn--primary:disabled { background-color: var(--sp-component-button-primary-bg-disabled); color: var(--sp-component-button-primary-text-disabled); @@ -364,6 +366,7 @@ } .sp-btn--secondary.sp-btn--disabled, + .sp-btn--secondary[aria-disabled="true"], .sp-btn--secondary:disabled { background-color: var(--sp-component-button-secondary-bg-disabled); color: var(--sp-component-button-secondary-text-disabled); @@ -389,6 +392,7 @@ } .sp-btn--ghost.sp-btn--disabled, + .sp-btn--ghost[aria-disabled="true"], .sp-btn--ghost:disabled { color: var(--sp-component-button-ghost-text-disabled); background-color: var(--sp-component-button-ghost-bg-disabled); @@ -413,6 +417,7 @@ } .sp-btn--danger.sp-btn--disabled, + .sp-btn--danger[aria-disabled="true"], .sp-btn--danger:disabled { background-color: var(--sp-component-button-danger-bg-disabled); color: var(--sp-component-button-danger-text-disabled); @@ -437,6 +442,7 @@ } .sp-btn--success.sp-btn--disabled, + .sp-btn--success[aria-disabled="true"], .sp-btn--success:disabled { background-color: var(--sp-component-button-success-bg-disabled); color: var(--sp-component-button-success-text-disabled); @@ -462,6 +468,7 @@ } .sp-btn--cta.sp-btn--disabled, + .sp-btn--cta[aria-disabled="true"], .sp-btn--cta:disabled { background-color: var(--sp-component-button-cta-bg-disabled); color: var(--sp-component-button-cta-text-disabled); @@ -487,6 +494,7 @@ } .sp-btn--accent.sp-btn--disabled, + .sp-btn--accent[aria-disabled="true"], .sp-btn--accent:disabled { background-color: var(--sp-component-button-accent-bg-disabled); color: var(--sp-component-button-accent-text-disabled); diff --git a/tests/button-recipe.test.ts b/tests/button-recipe.test.ts index ed1aae1..1517371 100644 --- a/tests/button-recipe.test.ts +++ b/tests/button-recipe.test.ts @@ -61,9 +61,9 @@ describe('getButtonClasses', () => { expect(result).toContain('sp-btn--full'); expect(result).toContain('sp-btn--loading'); expect(result).toContain('sp-btn--disabled'); - expect(result).toContain('sp-btn--hover'); - expect(result).toContain('sp-btn--focus'); - expect(result).toContain('sp-btn--active'); + expect(result).toContain('sp-btn--hover is-hover'); + expect(result).toContain('sp-btn--focus is-focus'); + expect(result).toContain('sp-btn--active is-active'); expect(result).toContain('sp-btn--icon'); expect(result).toContain('sp-btn--pill'); }); diff --git a/tests/css-contract.test.ts b/tests/css-contract.test.ts index 88d7630..28ff502 100644 --- a/tests/css-contract.test.ts +++ b/tests/css-contract.test.ts @@ -207,19 +207,35 @@ const interactionStateContracts = [ '.sp-btn.sp-btn--disabled', '.sp-btn[aria-disabled="true"]', '.sp-btn:disabled', + '.sp-btn--loading', + '.sp-btn[aria-busy="true"]', '.sp-btn--primary:hover', + '.sp-btn--primary.sp-btn--disabled', + '.sp-btn--primary[aria-disabled="true"]', '.sp-btn--primary:disabled', '.sp-btn--secondary:hover', + '.sp-btn--secondary.sp-btn--disabled', + '.sp-btn--secondary[aria-disabled="true"]', '.sp-btn--secondary:disabled', '.sp-btn--ghost:hover', + '.sp-btn--ghost.sp-btn--disabled', + '.sp-btn--ghost[aria-disabled="true"]', '.sp-btn--ghost:disabled', '.sp-btn--danger:hover', + '.sp-btn--danger.sp-btn--disabled', + '.sp-btn--danger[aria-disabled="true"]', '.sp-btn--danger:disabled', '.sp-btn--success:hover', + '.sp-btn--success.sp-btn--disabled', + '.sp-btn--success[aria-disabled="true"]', '.sp-btn--success:disabled', '.sp-btn--cta:hover', + '.sp-btn--cta.sp-btn--disabled', + '.sp-btn--cta[aria-disabled="true"]', '.sp-btn--cta:disabled', '.sp-btn--accent:hover', + '.sp-btn--accent.sp-btn--disabled', + '.sp-btn--accent[aria-disabled="true"]', '.sp-btn--accent:disabled', ], },