mirror of
https://github.com/material-components/material-web.git
synced 2026-03-09 00:09:23 +08:00
- `selectedIcon` is now optional, will fallback to default slot icon - `icon-button-toggle-change` removed for `change` and `input` events PiperOrigin-RevId: 502997869
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2021 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
// Required for @ariaProperty
|
|
// tslint:disable:no-new-decorators
|
|
|
|
import '../../focus/focus-ring.js';
|
|
import '../../icon/icon.js';
|
|
import '../../ripple/ripple.js';
|
|
|
|
import {html, nothing, TemplateResult} from 'lit';
|
|
import {property} from 'lit/decorators.js';
|
|
import {ClassInfo, classMap} from 'lit/directives/class-map.js';
|
|
import {when} from 'lit/directives/when.js';
|
|
|
|
import {ripple} from '../../ripple/directive.js';
|
|
|
|
import {IconButton} from './icon-button.js';
|
|
|
|
/**
|
|
* @fires change {Event}
|
|
* Dispatched whenever `selected` is changed via user click
|
|
*
|
|
* @fires input {InputEvent}
|
|
* Dispatched whenever `selected` is changed via user click
|
|
*/
|
|
export class IconButtonToggle extends IconButton {
|
|
/**
|
|
* The `aria-label` of the button when the toggle button is selected.
|
|
*/
|
|
@property({type: String}) ariaLabelSelected!: string;
|
|
|
|
/**
|
|
* Sets the selected state. When false, displays the default icon. When true,
|
|
* displays the `selectedIcon`, or the default icon If no `selectedIcon` is
|
|
* provided.
|
|
*/
|
|
@property({type: Boolean, reflect: true}) selected = false;
|
|
|
|
protected override render(): TemplateResult {
|
|
const hasToggledAriaLabel = this.ariaLabel && this.ariaLabelSelected;
|
|
const ariaPressedValue = hasToggledAriaLabel ? nothing : this.selected;
|
|
const ariaLabelValue = (hasToggledAriaLabel && this.selected) ?
|
|
this.ariaLabelSelected :
|
|
this.ariaLabel;
|
|
return html`<button
|
|
class="md3-icon-button ${classMap(this.getRenderClasses())}"
|
|
aria-pressed="${ariaPressedValue}"
|
|
aria-label="${ariaLabelValue || nothing}"
|
|
?disabled="${this.disabled}"
|
|
@focus="${this.handleFocus}"
|
|
@blur="${this.handleBlur}"
|
|
@pointerdown="${this.handlePointerDown}"
|
|
@click="${this.handleClick}"
|
|
${ripple(this.getRipple)}>
|
|
${this.renderFocusRing()}
|
|
${when(this.showRipple, this.renderRipple)}
|
|
${this.renderTouchTarget()}
|
|
${!this.selected ? this.renderIcon() : nothing}
|
|
${this.selected ? this.renderSelectedIcon() : nothing}
|
|
</button>`;
|
|
}
|
|
|
|
protected renderSelectedIcon() {
|
|
// Use default slot as fallback to not require specifying multiple icons
|
|
return html`<md-icon class="md3-icon-button__icon md3-icon-button__icon--selected"><slot name="selectedIcon"><slot></slot></slot></md-icon>`;
|
|
}
|
|
|
|
protected override getRenderClasses(): ClassInfo {
|
|
return {
|
|
...super.getRenderClasses(),
|
|
'md3-icon-button--selected': this.selected,
|
|
};
|
|
}
|
|
|
|
protected handleClick() {
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
|
|
this.selected = !this.selected;
|
|
this.dispatchEvent(
|
|
new InputEvent('input', {bubbles: true, composed: true}));
|
|
// Bubbles but does not compose to mimic native browser <input> & <select>
|
|
// Additionally, native change event is not an InputEvent.
|
|
this.dispatchEvent(new Event('change', {bubbles: true}));
|
|
}
|
|
}
|