Skip to content

Commit 1999a43

Browse files
authored
Merge pull request #84 from AegisJSProject/feature/custom-states
Add support for `:state(--disabled)` in button styles and path to other custom states
2 parents eb2ce3e + 18fbd21 commit 1999a43

8 files changed

Lines changed: 93 additions & 27 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [v0.2.5] - 2024-11-06
11+
12+
### Added
13+
- Add support for `:state(--disabled)` in button styles and path to other custom states
14+
1015
## [v0.2.4] - 2024-11-05
1116

1217
### Added

button.js

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { css } from '@aegisjsproject/core/parsers/css.js';
22
import { blue, green, red, yellow, gray, cyan } from './palette/bootstrap.js';
3+
import { SUPPORTS_CUSTOM_STATES } from './consts.js';
34
import {
45
colorLight, colorDark, btnPrimary, btnPrimaryActive, btnSecondary, btnSecondaryActive, btnSecondaryHover,
56
btnPrimaryHover, btnDisabled, btnSuccess, btnSuccessActive, btnSuccessHover, btnDanger, btnDangerActive,
@@ -8,6 +9,10 @@ import {
89
btnLinkActive, linkColor,
910
} from './palette/aegis.js';
1011

12+
const DISABLED_STATE = SUPPORTS_CUSTOM_STATES ? ':state(--disabled)' : '._state--disabled';
13+
14+
const DISABLED = `:disabled, .disabled, ${DISABLED_STATE}`;
15+
1116
export const btn = css`.btn:not([hidden]) {
1217
cursor: pointer;
1318
display: inline-block;
@@ -40,13 +45,13 @@ export const btn = css`.btn:not([hidden]) {
4045
width: 100%;
4146
}
4247
43-
.btn:disabled:not(.btn-system, .btn-system-accent), .btn.disabled:not(.btn-system, .btn-system-accent) {
48+
.btn:disabled:not(.btn-system, .btn-system-accent), .btn.disabled:not(.btn-system, .btn-system-accent), .btn${DISABLED} {
4449
cursor: not-allowed;
4550
opacity: var(--aegis-btn-disabled-opacity, 0.65);
4651
filter: saturate(var(--aegis-btn-disabled-saturation, 50%)) brightness(var(--aegis-btn-disabled-brightness, 90%));
4752
}
4853
49-
.btn.disabled {
54+
.btn.disabled, .btn${DISABLED_STATE} {
5055
pointer-events: none;
5156
}
5257
@@ -78,7 +83,7 @@ const system = css`.btn.btn-system {
7883
border-color: hsl(from ButtonFace h s calc(l * 0.8));
7984
}
8085
81-
.btn.btn-system:disabled, .btn.btn-system.disabled {
86+
.btn.btn-system:disabled, .btn.btn-system.disabled, .btn.btn-system${DISABLED_STATE} {
8287
background-color: hsl(from ButtonFace h calc(s * 0.2) l);
8388
border-color: hsl(from ButtonFace h calc(s * 0.2) l);
8489
color: GrayText;
@@ -107,7 +112,7 @@ const systemAccent = css`.btn.btn-system-accent {
107112
border-color: hsl(from AccentColor h s calc(l * 0.8));
108113
}
109114
110-
.btn.btn-system-accent:disabled, .btn.btn-system-accent.disabled {
115+
.btn.btn-system-accent:disabled, .btn.btn-system-accent.disabled, .btn.btn-system${DISABLED_STATE} {
111116
background-color: hsl(from AccentColor h calc(s * 0.2) l);
112117
border-color: hsl(from AccentColor h calc(s * 0.2) l);
113118
color: GrayText;
@@ -119,7 +124,7 @@ const primary = css`.btn.btn-primary {
119124
border-color: ${blue[6]};
120125
}
121126
122-
.btn.btn-primary:hover:not(:disabled, .disabled), .btn.btn-primary:focus-visible {
127+
.btn.btn-primary:hover:not(${DISABLED}), .btn.btn-primary:focus-visible {
123128
background-color: var(--aegis-btn-primary-hover, ${btnPrimaryHover});
124129
border-color: ${blue[7]};
125130
}
@@ -143,7 +148,7 @@ export const btnOutlinePrimary = css`.btn.btn-outline-primary {
143148
outline-color: var(--aegis-btn-primary, ${btnPrimary});
144149
}
145150
146-
.btn.btn-outline-primary:hover:not(:disabled, .disabled), .btn.btn-outline-primary:focus-visible {
151+
.btn.btn-outline-primary:hover:not(${DISABLED}), .btn.btn-outline-primary:focus-visible {
147152
background-color: var(--aegis-btn-primary-hover, ${btnPrimaryHover});
148153
border-color: ${blue[7]};
149154
color: var(--aegis-color-dark, ${colorDark});
@@ -161,7 +166,7 @@ const secondary = css`.btn.btn-secondary {
161166
border-color: ${gray[7]};
162167
}
163168
164-
.btn.btn-secondary:hover:not(:disabled, .disabled), .btn.btn-secondary:focus-visible {
169+
.btn.btn-secondary:hover:not(${DISABLED}), .btn.btn-secondary:focus-visible {
165170
background-color: var(--aegis-btn-secondary-hover, ${btnSecondaryHover});
166171
border-color: ${gray[8]};
167172
}
@@ -181,7 +186,7 @@ export const btnOutlineSecondary = css`.btn.btn-outline-secondary {
181186
border-color: currentColor;
182187
}
183188
184-
.btn.btn-outline-secondary:hover:not(:disabled, .disabled), .btn.btn-outline-secondary:focus-visible {
189+
.btn.btn-outline-secondary:hover:not(${DISABLED}), .btn.btn-outline-secondary:focus-visible {
185190
background-color: var(--aegis-btn-secondary-hover, ${btnSecondaryHover});
186191
border-color: ${gray[8]};
187192
color: var(--aegis-color-dark, ${colorDark});
@@ -197,7 +202,7 @@ export const btnOutlineSecondary = css`.btn.btn-outline-secondary {
197202
color: var(--aegis-color-dark, ${colorDark});
198203
}
199204
200-
.btn.btn-outline-secondary:disabled, .btn.btn-outline-secondary.disabled {
205+
.btn.btn-outline-secondary:disabled, .btn.btn-outline-secondary.disabled, .btn.btn-outline-seconday${DISABLED_STATE} {
201206
color: var(--aegis-btn-active-disabled, ${btnDisabled});
202207
}`;
203208

@@ -207,7 +212,7 @@ const success = css`.btn.btn-success {
207212
border-color: ${green[6]};
208213
}
209214
210-
.btn.btn-success:hover:not(:disabled, .disabled), .btn.btn-success:focus-visible {
215+
.btn.btn-success:hover:not(${DISABLED}), .btn.btn-success:focus-visible {
211216
background-color: var(--aegis-btn-success-hover, ${btnSuccessHover});
212217
border-color: ${green[7]};
213218
}
@@ -227,7 +232,7 @@ export const btnOutlineSuccess = css`.btn.btn-outline-success {
227232
border-color: currentColor;
228233
}
229234
230-
.btn.btn-outline-success:hover:not(:disabled, .disabled), .btn.btn-outline-success:focus-visible {
235+
.btn.btn-outline-success:hover:not(${DISABLED}), .btn.btn-outline-success:focus-visible {
231236
background-color: var(--aegis-btn-success-hover, ${btnSuccessHover});
232237
border-color: ${green[7]};
233238
color: var(--aegis-color-dark, ${colorDark});
@@ -249,7 +254,7 @@ const info = css`.btn.btn-info {
249254
border-color: ${cyan[6]};
250255
}
251256
252-
.btn.btn-info:not(:disabled, .disabled), .btn.btn-info:focus-visible {
257+
.btn.btn-info:not(${DISABLED}), .btn.btn-info:focus-visible {
253258
background-color: var(--aegis-btn-info-hover, ${btnInfoHover});
254259
border-color: ${cyan[7]};
255260
}
@@ -269,7 +274,7 @@ export const btnOutlineInfo = css`.btn.btn-outline-info {
269274
border-color: currentColor;
270275
}
271276
272-
.btn.btn-outline-info:hover:not(:disabled, .disabled), .btn.btn-outline-info:focus-visible {
277+
.btn.btn-outline-info:hover:not(${DISABLED}), .btn.btn-outline-info:focus-visible {
273278
background-color: var(--aegis-btn-info-hover, ${btnInfoHover});
274279
border-color: ${cyan[7]};
275280
color: var(--aegis-color-dark, ${colorDark});
@@ -291,7 +296,7 @@ const danger = css`.btn.btn-danger {
291296
border-color: ${red[6]};
292297
}
293298
294-
.btn.btn-danger:hover:not(:disabled, .disabled), .btn.btn-danger:focus-visible {
299+
.btn.btn-danger:hover:not(${DISABLED}), .btn.btn-danger:focus-visible {
295300
background-color: var(--aegis-btn-danger-hover, ${btnDangerHover});
296301
border-color: ${red[7]};
297302
}
@@ -311,7 +316,7 @@ export const btnOutlineDanger = css`.btn.btn-outline-danger {
311316
border-color: currentColor;
312317
}
313318
314-
.btn.btn-outline-danger:hover:not(:disabled, .disabled), .btn.btn-outline-danger:focus-visible {
319+
.btn.btn-outline-danger:hover:not(${DISABLED}), .btn.btn-outline-danger:focus-visible {
315320
background-color: var(--aegis-btn-danger-hover, ${btnDangerHover});
316321
border-color: ${red[7]};
317322
color: var(--aegis-color-dark, ${colorDark});
@@ -333,7 +338,7 @@ const warning = css`.btn.btn-warning {
333338
border-color: ${yellow[6]};
334339
}
335340
336-
.btn.btn-warning:hover:not(:disabled, .disabled), .btn.btn-warning:focus-visible {
341+
.btn.btn-warning:hover:not(${DISABLED}), .btn.btn-warning:focus-visible {
337342
background-color: var(--aegis-btn-warning-hover, ${btnWarningHover});
338343
border-color: ${yellow[7]};
339344
}
@@ -353,7 +358,7 @@ export const btnOutlineWarning = css`.btn.btn-outline-warning {
353358
border-color: currentColor;
354359
}
355360
356-
.btn.btn-outline-warning:not(:disabled, .disabled), .btn.btn-outline-warning:focus-visible {
361+
.btn.btn-outline-warning:not(${DISABLED}), .btn.btn-outline-warning:focus-visible {
357362
background-color: var(--aegis-btn-warning-hover, ${btnWarningHover});
358363
border-color: ${yellow[7]};
359364
color: var(--aegis-color-light, ${colorLight});
@@ -375,7 +380,7 @@ const light = css`.btn.btn-light {
375380
border-color: ${gray[2]};
376381
}
377382
378-
.btn.btn-light:hover:not(:disabled, .disabled), .btn.btn-light:focus-visible {
383+
.btn.btn-light:hover:not(${DISABLED}), .btn.btn-light:focus-visible {
379384
background-color: var(--aegis-btn-light-hover, ${btnLightHover});
380385
border-color: ${gray[3]};
381386
}
@@ -395,7 +400,7 @@ export const btnOutlineLight = css`.btn.btn-outline-light {
395400
border-color: currentColor;
396401
}
397402
398-
.btn.btn-outline-light:hover:not(:disabled, .disabled), .btn.btn-outline-light:focus-visible {
403+
.btn.btn-outline-light:hover:not(${DISABLED}), .btn.btn-outline-light:focus-visible {
399404
background-color: var(--aegis-btn-light-hover, ${btnLightHover});
400405
border-color: ${gray[3]};
401406
color: var(--aegis-color-light, ${colorLight});
@@ -417,7 +422,7 @@ const dark = css`.btn.btn-dark {
417422
border-color: ${gray[7]};
418423
}
419424
420-
.btn.btn-dark:hover:not(:disabled, .disabled), .btn.btn-dark:focus-visible {
425+
.btn.btn-dark:hover:not(${DISABLED}), .btn.btn-dark:focus-visible {
421426
background-color: var(--aegis-btn-dark-hover, ${btnDarkHover});
422427
border-color: ${gray[8]};
423428
}
@@ -437,7 +442,7 @@ export const btnOutlineDark = css`.btn.btn-outline-dark {
437442
border-color: currentColor;
438443
}
439444
440-
.btn.btn-outline-dark:hover:not(:disabled, .disabled), .btn.btn-outline-dark:focus-visible {
445+
.btn.btn-outline-dark:hover:not(${DISABLED}), .btn.btn-outline-dark:focus-visible {
441446
background-color: var(--aegis-btn-dark-hover, ${btnDarkHover});
442447
border-color: ${gray[8]};
443448
color: var(--aegis-color-dark, ${colorDark});
@@ -453,7 +458,7 @@ export const btnOutlineDark = css`.btn.btn-outline-dark {
453458
color: var(--aegis-color-dark, ${colorDark});
454459
}
455460
456-
.btn.btn-outline-secondary:disabled, .btn.btn-outline-secondary.disabled {
461+
.btn.btn-outline-secondary:disabled, .btn.btn-outline-secondary.disabled, .btn.btn-outline-secondary${DISABLED_STATE} {
457462
color: var(--aegis-btn-active-disabled, ${btnDisabled});
458463
}`;
459464

@@ -464,7 +469,7 @@ const link = css`.btn.btn-link {
464469
text-decoration: none;
465470
}
466471
467-
.btn.btn-link:hover:not(:disabled, .disabled), .btn.btn-link:focus-visible {
472+
.btn.btn-link:hover:not(${DISABLED}), .btn.btn-link:focus-visible {
468473
background-color: var(--aegis-btn-link-hover, ${btnLinkHover});
469474
text-decoration: underline;
470475
}

consts.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,5 @@ export const customProperties = {
6565
'btn-disabled-saturation': { initialValue: '50%', syntax: '<percentage>' },
6666
'btn-disabled-brightness': { initialValue: '90%', syntax: '<percentage>' },
6767
};
68+
69+
export const SUPPORTS_CUSTOM_STATES = CSS.supports('selector(:state(foo))');

createSheets.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class CSSStyleSheet {
2121
}
2222
}
2323

24+
globalThis.CSS = { supports: () => true };
2425
globalThis.CSSStyleSheet = CSSStyleSheet;
2526
globalThis.document = {};
2627
globalThis.MediaQueryList = class MediaQueryList extends EventTarget {};

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aegisjsproject/styles",
3-
"version": "0.2.4",
3+
"version": "0.2.5",
44
"description": "Pre-made and reusable styles for `@aegisjsproject/core`",
55
"keywords": [
66
"aegis",

test/index.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
<test-el theme="light"></test-el>
3939
<test-el theme="dark"></test-el>
4040
<test-el hidden=""></test-el>
41-
<div id="btns"></div>
41+
<div id="btns">
42+
<test-button disabled>
43+
<span slot="content">Custom Button</span>
44+
</test-button>
45+
</div>
4246
</body>
4347
</html>

test/index.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,55 @@ customElements.define('test-el', class TestElement extends HTMLElement {
6161
}
6262
});
6363

64+
customElements.define('test-button', class TestButton extends HTMLElement {
65+
#shadow;
66+
#internals;
67+
68+
constructor() {
69+
super();
70+
this.#shadow = this.attachShadow({ mode: 'open' });
71+
this.#internals = this.attachInternals();
72+
const slot = document.createElement('slot');
73+
slot.name = 'content';
74+
slot.textContent = 'No content';
75+
this.#shadow.append(slot);
76+
this.#internals.role = 'button';
77+
this.tabIndex = 0;
78+
this.classList.add('btn', 'btn-primary');
79+
80+
Promise.all([
81+
new CSSStyleSheet().replace(`:host {
82+
appearance: button;
83+
background-color: ButtonFace;
84+
color: ButtonText;
85+
border: 1px solid ButtonBorder;
86+
padding: 2px 4px;
87+
border-radius: 4px;
88+
}`),
89+
]).then(sheets => this.#shadow.adoptedStyleSheets = sheets);
90+
}
91+
92+
attributeChangedCallback(name, oldVal, newVal) {
93+
if (typeof newVal === 'string') {
94+
this.#internals.states.add('--disabled');
95+
} else {
96+
this.#internals.states.delete('--disabled');
97+
}
98+
}
99+
100+
get disabled() {
101+
return this.hasAttribute('disabled');
102+
}
103+
104+
set disabled(val) {
105+
this.toggleAttribute('disabled', val);
106+
}
107+
108+
static get observedAttributes() {
109+
return ['disabled'];
110+
}
111+
});
112+
64113
const btns = document.getElementById('btns');
65114

66115
[

0 commit comments

Comments
 (0)