blob: b8be2eecfd06654476219597ccc64574bb4c9d53 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {LitElement, html, css} from 'lit-element';
/**
* `<chops-checkbox>`
*
* A checkbox component. This component is primarily a wrapper
* around a native checkbox to allow easy sharing of styles.
*
*/
export class ChopsCheckbox extends LitElement {
/** @override */
static get styles() {
return css`
:host {
--chops-checkbox-color: var(--chops-primary-accent-color);
/* A bit brighter than Chrome's default focus color to
* avoid blending into the checkbox's blue. */
--chops-checkbox-focus-color: hsl(193, 82%, 63%);
--chops-checkbox-size: 16px;
--chops-checkbox-check-size: 18px;
}
label {
cursor: pointer;
display: inline-flex;
align-items: center;
}
input[type="checkbox"] {
/* We need the checkbox to be hidden but still accessible. */
opacity: 0;
width: 0;
height: 0;
position: absolute;
top: -9999;
left: -9999;
}
label::before {
width: var(--chops-checkbox-size);
height: var(--chops-checkbox-size);
margin-right: 8px;
box-sizing: border-box;
content: "\\2713";
display: inline-flex;
align-items: center;
justify-content: center;
border: 2px solid #222;
border-radius: 2px;
background: #fff;
font-size: var(--chops-checkbox-check-size);
padding: 0;
color: transparent;
}
input[type="checkbox"]:focus + label::before {
/* Make sure an outline shows around this element for
* accessibility.
*/
box-shadow: 0 0 5px 1px var(--chops-checkbox-focus-color);
}
input[type="checkbox"]:checked + label::before {
background: var(--chops-checkbox-color);
border-color: var(--chops-checkbox-color);
color: #fff;
}
`;
}
/** @override */
render() {
return html`
<!-- Note: Avoiding 2-way data binding to futureproof this code
for LitElement. -->
<input id="checkbox" type="checkbox"
.checked=${this.checked} @change=${this._checkedChangeHandler}>
<label for="checkbox">
<slot></slot>
</label>
`;
}
/** @override */
static get properties() {
return {
label: {type: String},
/**
* Note: At the moment, this component does not manage its own
* internal checked state. It expects its checked state to come
* from its parent, and its parent is expected to update the
* chops-checkbox's checked state on a change event.
*
* This can be generalized in the future to support multiple
* ways of managing checked state if needed.
**/
checked: {type: Boolean},
};
}
/**
* Clicks the checkbox. Helpful for automated testing.
*/
click() {
super.click();
/** @type {HTMLInputElement} */ (
this.shadowRoot.querySelector('#checkbox')).click();
}
/**
* Listens to the native checkbox's change event and runs internal
* logic based on changes.
* @param {Event} evt
* @private
*/
_checkedChangeHandler(evt) {
this._checkedChange(evt.target.checked);
}
/**
* @param {boolean} checked Whether the box was checked or unchecked.
* @fires CustomEvent#checked-change
* @private
*/
_checkedChange(checked) {
if (checked === this.checked) return;
const customEvent = new CustomEvent('checked-change', {
detail: {
checked: checked,
},
});
this.dispatchEvent(customEvent);
}
}
customElements.define('chops-checkbox', ChopsCheckbox);