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:
parent
ddd8e49d1a
commit
7bbd66459d
7 changed files with 168 additions and 3 deletions
5
.changeset/metal-crabs-applaud.md
Normal file
5
.changeset/metal-crabs-applaud.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"astro": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Adds a new radio checkbox component to the dev toolbar UI library (`astro-dev-toolbar-radio-checkbox`)
|
5
.changeset/twelve-dolphins-roll.md
Normal file
5
.changeset/twelve-dolphins-roll.md
Normal 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.
|
|
@ -33,6 +33,7 @@ import type {
|
||||||
DevToolbarCard,
|
DevToolbarCard,
|
||||||
DevToolbarHighlight,
|
DevToolbarHighlight,
|
||||||
DevToolbarIcon,
|
DevToolbarIcon,
|
||||||
|
DevToolbarRadioCheckbox,
|
||||||
DevToolbarSelect,
|
DevToolbarSelect,
|
||||||
DevToolbarToggle,
|
DevToolbarToggle,
|
||||||
DevToolbarTooltip,
|
DevToolbarTooltip,
|
||||||
|
@ -3087,6 +3088,7 @@ declare global {
|
||||||
'astro-dev-toolbar-icon': DevToolbarIcon;
|
'astro-dev-toolbar-icon': DevToolbarIcon;
|
||||||
'astro-dev-toolbar-card': DevToolbarCard;
|
'astro-dev-toolbar-card': DevToolbarCard;
|
||||||
'astro-dev-toolbar-select': DevToolbarSelect;
|
'astro-dev-toolbar-select': DevToolbarSelect;
|
||||||
|
'astro-dev-toolbar-radio-checkbox': DevToolbarRadioCheckbox;
|
||||||
|
|
||||||
// Deprecated names
|
// Deprecated names
|
||||||
// TODO: Remove in Astro 5.0
|
// TODO: Remove in Astro 5.0
|
||||||
|
|
|
@ -25,6 +25,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
DevToolbarBadge,
|
DevToolbarBadge,
|
||||||
DevToolbarIcon,
|
DevToolbarIcon,
|
||||||
DevToolbarSelect,
|
DevToolbarSelect,
|
||||||
|
DevToolbarRadioCheckbox,
|
||||||
},
|
},
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
loadDevToolbarApps() as DevToolbarAppDefinition[],
|
loadDevToolbarApps() as DevToolbarAppDefinition[],
|
||||||
|
@ -48,6 +49,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
customElements.define('astro-dev-toolbar-badge', DevToolbarBadge);
|
customElements.define('astro-dev-toolbar-badge', DevToolbarBadge);
|
||||||
customElements.define('astro-dev-toolbar-icon', DevToolbarIcon);
|
customElements.define('astro-dev-toolbar-icon', DevToolbarIcon);
|
||||||
customElements.define('astro-dev-toolbar-select', DevToolbarSelect);
|
customElements.define('astro-dev-toolbar-select', DevToolbarSelect);
|
||||||
|
customElements.define('astro-dev-toolbar-radio-checkbox', DevToolbarRadioCheckbox);
|
||||||
|
|
||||||
// Add deprecated names
|
// Add deprecated names
|
||||||
// TODO: Remove in Astro 5.0
|
// TODO: Remove in Astro 5.0
|
||||||
|
|
|
@ -2,13 +2,16 @@ import { settings } from '../settings.js';
|
||||||
|
|
||||||
const sizes = ['small', 'medium', 'large'] as const;
|
const sizes = ['small', 'medium', 'large'] as const;
|
||||||
const styles = ['ghost', 'outline', 'purple', 'gray', 'red', 'green', 'yellow', 'blue'] 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 ButtonSize = (typeof sizes)[number];
|
||||||
type ButtonStyle = (typeof styles)[number];
|
type ButtonStyle = (typeof styles)[number];
|
||||||
|
type ButtonBorderRadius = (typeof borderRadii)[number];
|
||||||
|
|
||||||
export class DevToolbarButton extends HTMLElement {
|
export class DevToolbarButton extends HTMLElement {
|
||||||
_size: ButtonSize = 'small';
|
_size: ButtonSize = 'small';
|
||||||
_buttonStyle: ButtonStyle = 'purple';
|
_buttonStyle: ButtonStyle = 'purple';
|
||||||
|
_buttonBorderRadius: ButtonBorderRadius = 'normal';
|
||||||
|
|
||||||
get size() {
|
get size() {
|
||||||
return this._size;
|
return this._size;
|
||||||
|
@ -40,7 +43,22 @@ export class DevToolbarButton extends HTMLElement {
|
||||||
this.updateStyle();
|
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;
|
shadowRoot: ShadowRoot;
|
||||||
|
|
||||||
|
@ -88,8 +106,14 @@ export class DevToolbarButton extends HTMLElement {
|
||||||
--small-font-size: 12px;
|
--small-font-size: 12px;
|
||||||
|
|
||||||
--large-padding: 12px 16px;
|
--large-padding: 12px 16px;
|
||||||
|
--large-rounded-padding: 12px 12px;
|
||||||
--medium-padding: 8px 12px;
|
--medium-padding: 8px 12px;
|
||||||
|
--medium-rounded-padding: 8px 8px;
|
||||||
--small-padding: 4px 8px;
|
--small-padding: 4px 8px;
|
||||||
|
--small-rounded-padding: 4px 4px;
|
||||||
|
|
||||||
|
--normal-border-radius: 4px;
|
||||||
|
--rounded-border-radius: 9999px;
|
||||||
|
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
|
@ -97,7 +121,7 @@ export class DevToolbarButton extends HTMLElement {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
|
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
border-radius: 4px;
|
border-radius: var(--border-radius);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -137,8 +161,13 @@ export class DevToolbarButton extends HTMLElement {
|
||||||
--background: var(--${this.buttonStyle}-background);
|
--background: var(--${this.buttonStyle}-background);
|
||||||
--border: var(--${this.buttonStyle}-border);
|
--border: var(--${this.buttonStyle}-border);
|
||||||
--font-size: var(--${this.size}-font-size);
|
--font-size: var(--${this.size}-font-size);
|
||||||
--padding: var(--${this.size}-padding);
|
|
||||||
--text-color: var(--${this.buttonStyle}-text);
|
--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);
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,3 +7,4 @@ export { DevToolbarSelect } from './select.js';
|
||||||
export { DevToolbarToggle } from './toggle.js';
|
export { DevToolbarToggle } from './toggle.js';
|
||||||
export { DevToolbarTooltip } from './tooltip.js';
|
export { DevToolbarTooltip } from './tooltip.js';
|
||||||
export { DevToolbarWindow } from './window.js';
|
export { DevToolbarWindow } from './window.js';
|
||||||
|
export { DevToolbarRadioCheckbox } from './radio-checkbox.js';
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue