From 265ee0454118d9633b7163280fa2c9e2f233c673 Mon Sep 17 00:00:00 2001 From: Chris Zuber Date: Fri, 10 Apr 2026 09:34:23 -0700 Subject: [PATCH] Add shared stylesheet for custom buttons --- CHANGELOG.md | 5 +++++ createSheets.js | 2 +- custom-button.js | 36 ++++++++++++++++++++++++++++++++++++ package-lock.json | 7 +++++-- package.json | 2 +- styles.js | 1 + test/index.html | 1 + test/index.js | 45 +++++++++++++++++++++++++-------------------- 8 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 custom-button.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 623b6f5..6c12ce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v0.3.1] - 2026-04-10 + +### Added +- Add shared stylesheet for custom buttons + ## [v0.3.0] - 2026-04-07 ### Added diff --git a/createSheets.js b/createSheets.js index bb96ef8..d2d7061 100644 --- a/createSheets.js +++ b/createSheets.js @@ -5,7 +5,7 @@ globalThis.reportError ??= console.error; const scripts = [ './animations.js', './button.js', './forms.js', './misc.js', './properties.js', './reset.js', './scrollbar.js', './styles.js', './theme.js', './properties-legacy.js', './presentation.js', - './layers.js', + './layers.js', './custom-button.js', ]; class CSSStyleSheet { diff --git a/custom-button.js b/custom-button.js new file mode 100644 index 0000000..e412598 --- /dev/null +++ b/custom-button.js @@ -0,0 +1,36 @@ +import { css } from '@aegisjsproject/parsers/css.js'; + +const DISABLED_SELECTOR = ':state(disabled)'; + +export const customButton = css`@layer components.aegisjsproject.button { + :host { + display: inline flow-root; + appearance: button; + user-select: none; + white-space: nowrap; + align-items: flex-start; + text-align: center; + cursor: default; + box-sizing: border-box; + background-color: ButtonFace; + color: ButtonText; + border: 1px outset ButtonBorder; + border-radius: 2px; + padding: 2px 6px; + font-family: system-ui, -apple-system, sans-serif; + } + + :host(${DISABLED_SELECTOR}) { + color: GrayText; + border-color: color-mix(in srgb, GrayText, transparent 50%); + background-color: color-mix(in srgb, ButtonFace, transparent 50%); + } + + :host(:hover:not(${DISABLED_SELECTOR})) { + background-color: color-mix(in srgb, ButtonFace, ButtonText 10%); + } + + :host(:active:not(${DISABLED_SELECTOR})) { + background-color: color-mix(in srgb, ButtonFace, ButtonText 20%); + } +}`; diff --git a/package-lock.json b/package-lock.json index ab6126d..50a8141 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aegisjsproject/styles", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@aegisjsproject/styles", - "version": "0.3.0", + "version": "0.3.1", "funding": [ { "type": "librepay", @@ -851,6 +851,7 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1156,6 +1157,7 @@ "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", @@ -2034,6 +2036,7 @@ "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, diff --git a/package.json b/package.json index 6fff04c..47006ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aegisjsproject/styles", - "version": "0.3.0", + "version": "0.3.1", "description": "Pre-made and reusable styles for `@aegisjsproject/core`", "keywords": [ "aegis", diff --git a/styles.js b/styles.js index cf0ea32..3ba8e1a 100644 --- a/styles.js +++ b/styles.js @@ -6,6 +6,7 @@ export { reset } from './reset.js'; export * from './properties.js'; export * from './theme.js'; export * from './button.js'; +export { customButton } from './custom-button.js'; export * from './misc.js'; export * from './forms.js'; export * from './scrollbar.js'; diff --git a/test/index.html b/test/index.html index 0da3799..476531c 100644 --- a/test/index.html +++ b/test/index.html @@ -18,6 +18,7 @@ + Custom Button
diff --git a/test/index.js b/test/index.js index cca8f92..9b67771 100644 --- a/test/index.js +++ b/test/index.js @@ -6,6 +6,8 @@ import theme from '../css/theme.css' with { type: 'css' }; import btn from '../css/button.css' with { type: 'css' }; import layers from '../css/layers.css' with { type: 'css' }; import animations from '../css/animations.css' with { type: 'css' }; +import customButton from '../css/custom-button.css' with { type: 'css' }; + const { reset } = await import('@aegisjsproject/styles'); // document.head.append(await sheetToLink(propertiesLegacy)); @@ -68,38 +70,41 @@ customElements.define('test-el', class TestElement extends HTMLElement { }); customElements.define('test-button', class TestButton extends HTMLElement { - #shadow; - #internals; + #shadow = this.attachShadow({ mode: 'open' }); + #internals = this.attachInternals(); - constructor() { - super(); - this.#shadow = this.attachShadow({ mode: 'open' }); - this.#internals = this.attachInternals(); + connectedCallback() { const slot = document.createElement('slot'); slot.name = 'content'; slot.textContent = 'No content'; this.#shadow.append(slot); this.#internals.role = 'button'; this.tabIndex = 0; - this.classList.add('btn', 'btn-primary'); - - Promise.all([ - new CSSStyleSheet().replace(`:host { - appearance: button; - background-color: ButtonFace; - color: ButtonText; - border: 1px solid ButtonBorder; - padding: 2px 4px; - border-radius: 4px; - }`), - ]).then(sheets => this.#shadow.adoptedStyleSheets = sheets); + this.#shadow.adoptedStyleSheets = [layers, customButton]; + + this.addEventListener('keydown', event => { + if (event.key === ' ' || event.key === 'Enter') { + event.preventDefault(); + event.currentTarget.click(); + } + }); + + this.addEventListener('click', ({ currentTarget }) => { + if (currentTarget.classList.contains('btn')) { + currentTarget.classList.remove('btn', 'btn-primary'); + } else { + currentTarget.classList.add('btn', 'btn-primary'); + } + }); } attributeChangedCallback(name, oldVal, newVal) { if (typeof newVal === 'string') { - this.#internals.states.add('--disabled'); + this.#internals.states.add('disabled'); + this.inert = true; } else { - this.#internals.states.delete('--disabled'); + this.#internals.states.delete('disabled'); + this.inert = false; } }