/** * Copyright Aquera Inc 2023 * * This source code is licensed under the BSD-3-Clause license found in the * LICENSE file in the root directory of this source tree. */ import {LitElement, html, CSSResultArray, TemplateResult} from 'lit'; import { customElement, property } from 'lit/decorators.js'; import {styles} from './nile-radio.css'; import { classMap } from 'lit/directives/class-map.js'; import { state } from 'lit/decorators.js'; import { watch } from '../internal/watch'; import NileElement from '../internal/nile-element'; import type { CSSResultGroup } from 'lit'; /** * Nile icon component. * * @tag nile-radio * * * @dependency nile-icon * * @slot - The radio's label. * * @event blur - Emitted when the control loses focus. * @event focus - Emitted when the control gains focus. * * @csspart base - The component's base wrapper. * @csspart control - The circular container that wraps the radio's checked state. * @csspart control--checked - The radio control when the radio is checked. * @csspart checked-icon - The checked icon, an `` element. * @csspart label - The container that wraps the radio's label. */ @customElement('nile-radio') export class NileRadio extends NileElement { static styles: CSSResultGroup = styles; @property({type:Boolean}) checked = false; @state() protected hasFocus = false; /** The radio's value. When selected, the radio group will receive this value. */ @property() value: string = ''; /** The radio's size. */ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; /** Disables the radio. */ @property({ type: Boolean, reflect: true }) disabled = false; /** The radio's labelborder. */ @property({ type: Boolean, reflect: true }) islabelborder = false; @property({ type: Boolean, reflect: true }) allowUncheck = false; connectedCallback() { super.connectedCallback(); this.handleBlur = this.handleBlur.bind(this); this.handleClick = this.handleClick.bind(this); this.handleFocus = this.handleFocus.bind(this); this.setInitialAttributes(); this.addEventListeners(); this.emit('nile-init'); } disconnectedCallback() { this.removeEventListeners(); this.emit('nile-destroy'); } private addEventListeners() { this.addEventListener('blur', this.handleBlur); this.addEventListener('click', this.handleClick); this.addEventListener('focus', this.handleFocus); } private removeEventListeners() { this.removeEventListener('blur', this.handleBlur); this.removeEventListener('click', this.handleClick); this.removeEventListener('focus', this.handleFocus); } private handleBlur() { this.hasFocus = false; this.emit('nile-blur') } private handleClick() { if(this.allowUncheck && !this.disabled) { this.checked = !this.checked; } else if (!this.disabled) { this.checked = true; } } private handleFocus() { this.hasFocus = true; this.emit('nile-focus') } private setInitialAttributes() { this.setAttribute('role', 'radio'); this.setAttribute('tabindex', '-1'); this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false'); } @watch('checked') handleCheckedChange() { this.setAttribute('aria-checked', this.checked ? 'true' : 'false'); if (this.disabled) { this.setAttribute('tabindex', '-1'); } else { this.setAttribute('tabindex', this.checked ? '0' : '-1'); } } @watch('disabled', { waitUntilFirstUpdate: true }) handleDisabledChange() { this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false'); if (this.disabled) { this.setAttribute('tabindex', '-1'); if (this.matches(':focus')) { (this as HTMLElement).blur(); } } else { this.setAttribute('tabindex', this.checked ? '0' : '-1'); } } render() { return html` ${this.checked ? html` ` : ''} `; } } export default NileRadio; declare global { interface HTMLElementTagNameMap { 'nile-radio': NileRadio; } }