UNPKG

@material/web

Version:
170 lines (169 loc) 5.47 kB
/** * @license * Copyright 2018 Google LLC * SPDX-License-Identifier: Apache-2.0 */ var _a; import { __decorate } from "tslib"; import '../../focus/md-focus-ring.js'; import '../../ripple/ripple.js'; import { html, isServer, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { polyfillElementInternalsAria, setupHostAria } from '../../internal/aria/aria.js'; import { isActivationClick } from '../../internal/controller/events.js'; import { SingleSelectionController } from './single-selection-controller.js'; const CHECKED = Symbol('checked'); let maskId = 0; /** * A radio component. * * @fires input Dispatched when the value changes from user interaction. * --bubbles * @fires change Dispatched when the value changes from user interaction. * --bubbles --composed */ export class Radio extends LitElement { /** * Whether or not the radio is selected. */ get checked() { return this[CHECKED]; } set checked(checked) { const wasChecked = this.checked; if (wasChecked === checked) { return; } this[CHECKED] = checked; const state = String(checked); this.internals.setFormValue(this.checked ? this.value : null, state); this.requestUpdate('checked', wasChecked); this.selectionController.handleCheckedChange(); } /** * The HTML name to use in form submission. */ get name() { return this.getAttribute('name') ?? ''; } set name(name) { this.setAttribute('name', name); } /** * The associated form element with which this element's value will submit. */ get form() { return this.internals.form; } /** * The labels this element is associated with. */ get labels() { return this.internals.labels; } constructor() { super(); // Unique maskId is required because of a Safari bug that fail to persist // reference to the mask. This should be removed once the bug is fixed. this.maskId = `cutout${++maskId}`; this[_a] = false; /** * Whether or not the radio is disabled. */ this.disabled = false; /** * The element value to use in form submission when checked. */ this.value = 'on'; this.selectionController = new SingleSelectionController(this); this.internals = polyfillElementInternalsAria(this, this /* needed for closure */.attachInternals()); this.addController(this.selectionController); if (!isServer) { this.internals.role = 'radio'; this.addEventListener('click', this.handleClick.bind(this)); this.addEventListener('keydown', this.handleKeydown.bind(this)); } } render() { const classes = { checked: this.checked }; return html ` <div class="container ${classMap(classes)}" aria-hidden="true"> <md-ripple part="ripple" .control=${this} ?disabled=${this.disabled}></md-ripple> <md-focus-ring part="focus-ring" .control=${this}></md-focus-ring> <svg class="icon" viewBox="0 0 20 20"> <mask id="${this.maskId}"> <rect width="100%" height="100%" fill="white" /> <circle cx="10" cy="10" r="8" fill="black" /> </mask> <circle class="outer circle" cx="10" cy="10" r="10" mask="url(#${this.maskId})" /> <circle class="inner circle" cx="10" cy="10" r="5" /> </svg> <input id="input" type="radio" tabindex="-1" .checked=${this.checked} .value=${this.value} ?disabled=${this.disabled} > </div> `; } updated() { this.internals.ariaChecked = String(this.checked); } async handleClick(event) { if (this.disabled) { return; } // allow event to propagate to user code after a microtask. await 0; if (event.defaultPrevented) { return; } if (isActivationClick(event)) { this.focus(); } // Per spec, clicking on a radio input always selects it. this.checked = true; this.dispatchEvent(new Event('change', { bubbles: true })); this.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true })); } async handleKeydown(event) { // allow event to propagate to user code after a microtask. await 0; if (event.key !== ' ' || event.defaultPrevented) { return; } this.click(); } /** @private */ formResetCallback() { // The checked property does not reflect, so the original attribute set by // the user is used to determine the default value. this.checked = this.hasAttribute('checked'); } /** @private */ formStateRestoreCallback(state) { this.checked = state === 'true'; } } _a = CHECKED; (() => { setupHostAria(Radio); })(); /** @nocollapse */ Radio.formAssociated = true; __decorate([ property({ type: Boolean }) ], Radio.prototype, "checked", null); __decorate([ property({ type: Boolean, reflect: true }) ], Radio.prototype, "disabled", void 0); __decorate([ property() ], Radio.prototype, "value", void 0); //# sourceMappingURL=radio.js.map