blob: 52868bd46bf34b8d75b6f62f0b34f17e51ca8e46 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {LitElement, html, css} from 'lit-element';
6
7/**
8 * `<chops-toggle>`
9 *
10 * A toggle button component. This component is primarily a wrapper
11 * around a native checkbox to allow easy sharing of styles.
12 *
13 */
14export class ChopsToggle extends LitElement {
15 /** @override */
16 static get styles() {
17 return css`
18 :host {
19 --chops-toggle-bg: none;
20 --chops-toggle-color: var(--chops-primary-font-color);
21 --chops-toggle-hover-bg: rgba(0, 0, 0, 0.3);
22 --chops-toggle-focus-border: hsl(193, 82%, 63%);
23 --chops-toggle-checked-bg: rgba(0, 0, 0, 0.6);
24 --chops-toggle-checked-color: var(--chops-white);
25 }
26 label {
27 background: var(--chops-toggle-bg);
28 color: var(--chops-toggle-color);
29 cursor: pointer;
30 align-items: center;
31 padding: 2px 4px;
32 border: var(--chops-normal-border);
33 border-radius: var(--chops-button-radius);
34 }
35 input[type="checkbox"] {
36 /* We need the checkbox to be hidden but still accessible. */
37 opacity: 0;
38 width: 0;
39 height: 0;
40 position: absolute;
41 top: -9999;
42 left: -9999;
43 }
44 input[type="checkbox"]:focus + label {
45 /* Make sure an outline shows around this element for
46 * accessibility.
47 */
48 box-shadow: 0 0 5px 1px var(--chops-toggle-focus-border);
49 }
50 input[type="checkbox"]:hover + label {
51 background: var(--chops-toggle-hover-bg);
52 }
53 input[type="checkbox"]:checked + label {
54 background: var(--chops-toggle-checked-bg);
55 color: var(--chops-toggle-checked-color);
56 }
57 input[type="checkbox"]:disabled + label {
58 opacity: 0.8;
59 cursor: default;
60 pointer-events: none;
61 }
62 `;
63 }
64
65 /** @override */
66 render() {
67 return html`
68 <input id="checkbox"
69 type="checkbox"
70 ?checked=${this.checked}
71 ?disabled=${this.disabled}
72 @change=${this._checkedChangeHandler}
73 >
74 <label for="checkbox">
75 <slot></slot>
76 </label>
77 `;
78 }
79
80 /** @override */
81 static get properties() {
82 return {
83 /**
84 * Note: At the moment, this component does not manage its own
85 * internal checked state. It expects its checked state to come
86 * from its parent, and its parent is expected to update the
87 * chops-checkbox's checked state on a change event.
88 *
89 * This can be generalized in the future to support multiple
90 * ways of managing checked state if needed.
91 **/
92 checked: {type: Boolean},
93 /**
94 * Whether the element currently allows checking or not.
95 */
96 disabled: {type: Boolean},
97 };
98 }
99
100 click() {
101 super.click();
102 this.shadowRoot.querySelector('#checkbox').click();
103 }
104
105 _checkedChangeHandler(evt) {
106 this._checkedChange(evt.target.checked);
107 }
108
109 /**
110 * @param {boolean} checked
111 * @fires CustomEvent#checked-change
112 * @private
113 */
114 _checkedChange(checked) {
115 if (checked === this.checked) return;
116 const customEvent = new CustomEvent('checked-change', {
117 detail: {
118 checked: checked,
119 },
120 });
121 this.dispatchEvent(customEvent);
122 }
123}
124customElements.define('chops-toggle', ChopsToggle);