UNPKG

@anypoint-web-components/anypoint-radio-button

Version:
184 lines (171 loc) 5.3 kB
import { LitElement, html } from 'lit-element'; import { CheckedElementMixin } from '@anypoint-web-components/anypoint-form-mixins'; import '@anypoint-web-components/anypoint-styles/colors.js'; import radioStyles from './radio.styles.js'; /* eslint-disable class-methods-use-this */ /** * `anypoint-radio-button` * * Anypoint styled radio button. * * ## Usage * * Install element: * * ``` * npm i --save @anypoint-components/anypoint-radio-button * ``` * * Import into your app: * * ```html * <script type="module" src="node_modules/@anypoint-components/anypoint-radio-button.js"></script> * ``` * * Or into another component * * ```javascript * import '@anypoint-components/anypoint-radio-button.js'; * ``` * * Use it: * * ```html * <paper-radio-group selectable="anypoint-radio-button"> * <anypoint-radio-button name="a">Apple</anypoint-radio-button> * <anypoint-radio-button name="b">Banana</anypoint-radio-button> * <anypoint-radio-button name="c">Orange</anypoint-radio-button> * </paper-radio-group> * ``` * * ### Styling * * `<anypoint-radio-button>` provides the following custom properties and mixins for styling: * * Custom property | Description | Default * ----------------|-------------|---------- * `--anypoint-radio-button-radio-container` | A mixin applied to the internal radio container | `{}` * `--anypoint-radio-button-unchecked-color` | Border color of unchecked button | `--anypoint-color-aluminum5` * `--anypoint-radio-button-unchecked-background-color` | Unchecked button background color | `transparent` * `--anypoint-radio-button-checked-color` | Checked button selection color | `--anypoint-color-coreBlue3` * `--anypoint-radio-button-checked-inner-background-color` | Checked button inner circle background color | `#fff` * `--anypoint-radio-button-label-spacing` | Spacing between the label and the button | `5px` * `--anypoint-radio-button-label-color` | Label color | `--primary-text-color` * `--anypoint-radio-button-label` | A mixin applied to the internal label | `{}` */ export class AnypointRadioButtonElement extends CheckedElementMixin(LitElement) { get styles() { return radioStyles; } render() { return html`<style>${this.styles}</style> <div class="radio-container"> <div class="state-container"> <div id="offRadio"></div> <div id="onRadio"></div> </div> </div> <label class="radioLabel"><slot></slot></label>`; } get checked() { return this._checked || false; } set checked(value) { const old = this._checked; if (old === value) { return; } this._checked = value; this.requestUpdate('checked', old); this._updateCheckedAria(value); this._checkedChanged(value); } get disabled() { return this._disabled; } set disabled(value) { const old = this._disabled; if (old === value) { return; } this._disabled = value; this._disabledChanged(value); } connectedCallback() { super.connectedCallback(); if (!this.hasAttribute('role')) { this.setAttribute('role', 'radio'); } if (!this.hasAttribute('tabindex')) { this.setAttribute('tabindex', '0'); } if (this.checked === undefined) { this.checked = false; } else { this._updateCheckedAria(this.checked); } this.addEventListener('keydown', this._keyDownHandler); this.addEventListener('click', this._clickHandler); this._disabledChanged(this.disabled); } disconnectedCallback() { if (super.disconnectedCallback) { super.disconnectedCallback(); } this.addEventListener('keydown', this._keyDownHandler); this.addEventListener('click', this._clickHandler); } _updateCheckedAria(checked=false) { this.setAttribute('aria-checked', String(checked)); } /** * Handler for keyboard down event * @param {KeyboardEvent} e */ _keyDownHandler(e) { if (['Enter', 'NumpadEnter', 'Space'].includes(e.code)) { e.preventDefault(); this._clickHandler(); } } /** * Handler for pointer click event */ _clickHandler() { if (this.disabled) { return; } if (this.checked) { return; } this.checked = true; this.dispatchEvent(new Event('change')); } /** * Handles `disable` property state change and manages `aria-disabled` * and `tabindex` attributes. * @param {Boolean} disabled */ _disabledChanged(disabled) { if (this.parentElement === null) { return; } this.setAttribute('aria-disabled', disabled ? 'true' : 'false'); if (disabled) { // Read the `tabindex` attribute instead of the `tabIndex` property. // The property returns `-1` if there is no `tabindex` attribute. // This distinction is important when restoring the value because // leaving `-1` hides shadow root children from the tab order. this._oldTabIndex = this.getAttribute('tabindex'); this.focused = false; this.setAttribute('tabindex', '-1'); this.blur(); } else if (this._oldTabIndex !== undefined) { if (this._oldTabIndex === null) { this.removeAttribute('tabindex'); } else { this.setAttribute('tabindex', this._oldTabIndex); } } } }