0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-23 21:53:55 -05:00

feat: Add new component to toolbar library (#10906)

* feat: progress

* chore: changeset
This commit is contained in:
Erika 2024-05-08 11:26:00 +02:00 committed by GitHub
parent ddd8e49d1a
commit 7bbd66459d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 168 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
"astro": minor
---
Adds a new radio checkbox component to the dev toolbar UI library (`astro-dev-toolbar-radio-checkbox`)

View file

@ -0,0 +1,5 @@
---
"astro": minor
---
Adds a new `buttonBorderRadius` property to the `astro-dev-toolbar-button` component for the dev toolbar component library. This property can be useful to make a fully rounded button with an icon in the center.

View file

@ -33,6 +33,7 @@ import type {
DevToolbarCard,
DevToolbarHighlight,
DevToolbarIcon,
DevToolbarRadioCheckbox,
DevToolbarSelect,
DevToolbarToggle,
DevToolbarTooltip,
@ -3087,6 +3088,7 @@ declare global {
'astro-dev-toolbar-icon': DevToolbarIcon;
'astro-dev-toolbar-card': DevToolbarCard;
'astro-dev-toolbar-select': DevToolbarSelect;
'astro-dev-toolbar-radio-checkbox': DevToolbarRadioCheckbox;
// Deprecated names
// TODO: Remove in Astro 5.0

View file

@ -25,6 +25,7 @@ document.addEventListener('DOMContentLoaded', async () => {
DevToolbarBadge,
DevToolbarIcon,
DevToolbarSelect,
DevToolbarRadioCheckbox,
},
] = await Promise.all([
loadDevToolbarApps() as DevToolbarAppDefinition[],
@ -48,6 +49,7 @@ document.addEventListener('DOMContentLoaded', async () => {
customElements.define('astro-dev-toolbar-badge', DevToolbarBadge);
customElements.define('astro-dev-toolbar-icon', DevToolbarIcon);
customElements.define('astro-dev-toolbar-select', DevToolbarSelect);
customElements.define('astro-dev-toolbar-radio-checkbox', DevToolbarRadioCheckbox);
// Add deprecated names
// TODO: Remove in Astro 5.0

View file

@ -2,13 +2,16 @@ import { settings } from '../settings.js';
const sizes = ['small', 'medium', 'large'] as const;
const styles = ['ghost', 'outline', 'purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const;
const borderRadii = ['normal', 'rounded'] as const;
type ButtonSize = (typeof sizes)[number];
type ButtonStyle = (typeof styles)[number];
type ButtonBorderRadius = (typeof borderRadii)[number];
export class DevToolbarButton extends HTMLElement {
_size: ButtonSize = 'small';
_buttonStyle: ButtonStyle = 'purple';
_buttonBorderRadius: ButtonBorderRadius = 'normal';
get size() {
return this._size;
@ -40,7 +43,22 @@ export class DevToolbarButton extends HTMLElement {
this.updateStyle();
}
static observedAttributes = ['button-style', 'size'];
get buttonBorderRadius() {
return this._buttonBorderRadius;
}
set buttonBorderRadius(value) {
if (!borderRadii.includes(value)) {
settings.logger.error(
`Invalid border-radius: ${value}, expected one of ${borderRadii.join(', ')}, got ${value}.`
);
return;
}
this._buttonBorderRadius = value;
this.updateStyle();
}
static observedAttributes = ['button-style', 'size', 'button-border-radius'];
shadowRoot: ShadowRoot;
@ -88,8 +106,14 @@ export class DevToolbarButton extends HTMLElement {
--small-font-size: 12px;
--large-padding: 12px 16px;
--large-rounded-padding: 12px 12px;
--medium-padding: 8px 12px;
--medium-rounded-padding: 8px 8px;
--small-padding: 4px 8px;
--small-rounded-padding: 4px 4px;
--normal-border-radius: 4px;
--rounded-border-radius: 9999px;
border: 1px solid var(--border);
padding: var(--padding);
@ -97,7 +121,7 @@ export class DevToolbarButton extends HTMLElement {
background: var(--background);
color: var(--text-color);
border-radius: 4px;
border-radius: var(--border-radius);
display: flex;
align-items: center;
justify-content: center;
@ -137,8 +161,13 @@ export class DevToolbarButton extends HTMLElement {
--background: var(--${this.buttonStyle}-background);
--border: var(--${this.buttonStyle}-border);
--font-size: var(--${this.size}-font-size);
--padding: var(--${this.size}-padding);
--text-color: var(--${this.buttonStyle}-text);
${
this.buttonBorderRadius === 'normal'
? '--padding: var(--' + this.size + '-padding);'
: '--padding: var(--' + this.size + '-rounded-padding);'
}
--border-radius: var(--${this.buttonBorderRadius}-border-radius);
}`;
}
}

View file

@ -7,3 +7,4 @@ export { DevToolbarSelect } from './select.js';
export { DevToolbarToggle } from './toggle.js';
export { DevToolbarTooltip } from './tooltip.js';
export { DevToolbarWindow } from './window.js';
export { DevToolbarRadioCheckbox } from './radio-checkbox.js';

View file

@ -0,0 +1,121 @@
const styles = ['purple', 'gray', 'red', 'green', 'yellow', 'blue'] as const;
type RadioStyle = (typeof styles)[number];
export class DevToolbarRadioCheckbox extends HTMLElement {
private _radioStyle: RadioStyle = 'purple';
input: HTMLInputElement;
shadowRoot: ShadowRoot;
get radioStyle() {
return this._radioStyle;
}
set radioStyle(value) {
if (!styles.includes(value)) {
console.error(`Invalid style: ${value}, expected one of ${styles.join(', ')}.`);
return;
}
this._radioStyle = value;
this.updateStyle();
}
static observedAttributes = ['radio-style', 'checked', 'disabled', 'name', 'value'];
constructor() {
super();
this.shadowRoot = this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
:host {
--purple-unchecked: rgba(224, 204, 250, 0.33);
--purple-checked: rgba(224, 204, 250, 1);
--gray-unchecked: rgba(191, 193, 201, 0.33);
--gray-checked: rgba(191, 193, 201, 1);
--red-unchecked: rgba(249, 196, 215, 0.33);
--red-checked: rgba(179, 62, 102, 1);
--green-unchecked: rgba(213, 249, 196, 0.33);
--green-checked: rgba(61, 125, 31, 1);
--yellow-unchecked: rgba(255, 236, 179, 0.33);
--yellow-checked: rgba(181, 138, 45, 1);
--blue-unchecked: rgba(189, 195, 255, 0.33);
--blue-checked: rgba(54, 69, 217, 1);
}
input[type="radio"] {
appearance: none;
-webkit-appearance: none;
display: flex;
align-content: center;
justify-content: center;
border: 2px solid var(--unchecked-color);
border-radius: 9999px;
width: 16px;
height: 16px;
}
input[type="radio"]::before {
content: "";
background-color: var(--checked-color);
width: 8px;
height: 8px;
border-radius: 9999px;
visibility: hidden;
margin: 2px;
}
input[type="radio"]:checked {
border-color: var(--checked-color);
}
input[type="radio"]:checked::before {
visibility: visible;
}
</style>
<style id="selected-style"></style>
`;
this.input = document.createElement('input');
this.input.type = 'radio';
this.shadowRoot.append(this.input);
}
connectedCallback() {
this.updateInputState();
this.updateStyle();
}
updateStyle() {
const styleElement = this.shadowRoot.querySelector<HTMLStyleElement>('#selected-style');
if (styleElement) {
styleElement.innerHTML = `
:host {
--unchecked-color: var(--${this._radioStyle}-unchecked);
--checked-color: var(--${this._radioStyle}-checked);
}
`;
}
}
updateInputState() {
this.input.checked = this.hasAttribute('checked');
this.input.disabled = this.hasAttribute('disabled');
this.input.name = this.getAttribute('name') || '';
this.input.value = this.getAttribute('value') || '';
}
attributeChangedCallback() {
if (this.hasAttribute('radio-style')) {
this.radioStyle = this.getAttribute('radio-style') as RadioStyle;
}
this.updateInputState();
}
}