import { WebComponent, choice, string } from '../src/index.ts'; import { share } from './main-context.ts'; import { SWATCHES, THEMES } from './themes.ts'; import css from './color-swatch-picker.css' with { type: 'css' }; /** * Light DOM radio group. The radios are real light-DOM ``s, so arrow * keys, focus and form behaviour are native. A pick is shared with the nearest * `` as a `theme` update. */ const SPEC = { template: `
${THEMES.map( (theme) => ` `, ).join('')}
`, css, events: { change: true, }, element: { legend: 'legend' }, elements: { radios: 'input[type=radio]' }, props: { label: string({ default: 'Theme' }), value: choice(THEMES, { default: 'sunset' }), }, } as const; // Each picker needs its own radio group name. let count = 0; export class ColorSwatchPicker extends WebComponent(SPEC) { readonly #name = `color-swatch-picker-${(count += 1)}`; override onConnect(): void { for (const radio of this.refs.radios) radio.name = this.#name; this.#render(); } override onPropChange(): void { this.#render(); } override handleEvent(event: Event): void { const radio = this.refs.radios.find((input) => input === event.target); const theme = THEMES.find((name) => name === radio?.value); if (theme && this.value !== theme) { this.value = theme; share(this, 'theme', theme); } } #render(): void { if (this.refs.legend) this.refs.legend.textContent = this.label; for (const radio of this.refs.radios) radio.checked = radio.value === this.value; } } customElements.define('color-swatch-picker', ColorSwatchPicker); declare global { interface HTMLElementTagNameMap { 'color-swatch-picker': ColorSwatchPicker; } }