blob: d75234751b8a147b4439c453cb12939cfea78517 [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-checkbox>`
9 *
10 * A checkbox component. This component is primarily a wrapper
11 * around a native checkbox to allow easy sharing of styles.
12 *
13 */
14export class ChopsCheckbox extends LitElement {
15 /** @override */
16 static get styles() {
17 return css`
18 :host {
19 --chops-checkbox-color: var(--chops-primary-accent-color);
20 /* A bit brighter than Chrome's default focus color to
21 * avoid blending into the checkbox's blue. */
22 --chops-checkbox-focus-color: hsl(193, 82%, 63%);
23 --chops-checkbox-size: 16px;
24 --chops-checkbox-check-size: 18px;
25 }
26 label {
27 cursor: pointer;
28 display: inline-flex;
29 align-items: center;
30 }
31 input[type="checkbox"] {
32 /* We need the checkbox to be hidden but still accessible. */
33 opacity: 0;
34 width: 0;
35 height: 0;
36 position: absolute;
37 top: -9999;
38 left: -9999;
39 }
40 label::before {
41 width: var(--chops-checkbox-size);
42 height: var(--chops-checkbox-size);
43 margin-right: 8px;
44 box-sizing: border-box;
45 content: "\\2713";
46 display: inline-flex;
47 align-items: center;
48 justify-content: center;
49 border: 2px solid #222;
50 border-radius: 2px;
51 background: #fff;
52 font-size: var(--chops-checkbox-check-size);
53 padding: 0;
54 color: transparent;
55 }
56 input[type="checkbox"]:focus + label::before {
57 /* Make sure an outline shows around this element for
58 * accessibility.
59 */
60 box-shadow: 0 0 5px 1px var(--chops-checkbox-focus-color);
61 }
62 input[type="checkbox"]:checked + label::before {
63 background: var(--chops-checkbox-color);
64 border-color: var(--chops-checkbox-color);
65 color: #fff;
66 }
67 `;
68 }
69
70 /** @override */
71 render() {
72 return html`
73 <!-- Note: Avoiding 2-way data binding to futureproof this code
74 for LitElement. -->
75 <input id="checkbox" type="checkbox"
76 .checked=${this.checked} @change=${this._checkedChangeHandler}>
77 <label for="checkbox">
78 <slot></slot>
79 </label>
80 `;
81 }
82
83 /** @override */
84 static get properties() {
85 return {
86 label: {type: String},
87
88 /**
89 * Note: At the moment, this component does not manage its own
90 * internal checked state. It expects its checked state to come
91 * from its parent, and its parent is expected to update the
92 * chops-checkbox's checked state on a change event.
93 *
94 * This can be generalized in the future to support multiple
95 * ways of managing checked state if needed.
96 **/
97 checked: {type: Boolean},
98 };
99 }
100
101 /**
102 * Clicks the checkbox. Helpful for automated testing.
103 */
104 click() {
105 super.click();
106 /** @type {HTMLInputElement} */ (
107 this.shadowRoot.querySelector('#checkbox')).click();
108 }
109
110 /**
111 * Listens to the native checkbox's change event and runs internal
112 * logic based on changes.
113 * @param {Event} evt
114 * @private
115 */
116 _checkedChangeHandler(evt) {
117 this._checkedChange(evt.target.checked);
118 }
119
120 /**
121 * @param {boolean} checked Whether the box was checked or unchecked.
122 * @fires CustomEvent#checked-change
123 * @private
124 */
125 _checkedChange(checked) {
126 if (checked === this.checked) return;
127 const customEvent = new CustomEvent('checked-change', {
128 detail: {
129 checked: checked,
130 },
131 });
132 this.dispatchEvent(customEvent);
133 }
134}
135customElements.define('chops-checkbox', ChopsCheckbox);