UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

210 lines (187 loc) 7.07 kB
import { customElement, property } from 'lit/decorators.js' import { PktInputElement } from '@/base-elements/input-element' import { Ref, createRef, ref } from 'lit/directives/ref.js' import { html, nothing, PropertyValues } from 'lit' import { classMap } from 'lit/directives/class-map.js' import { ElementProps } from '@/types/typeUtils' type Props = ElementProps< PktCheckbox, | 'checkHelptext' | 'defaultChecked' | 'hasTile' | 'isSwitch' | 'labelPosition' | 'hideLabel' | 'tagText' | 'optionalTag' | 'optionalText' | 'requiredTag' | 'requiredText' > export class PktCheckbox extends PktInputElement<Props> { inputRef: Ref<HTMLInputElement> = createRef() @property({ type: String, reflect: true }) value: string = '' @property({ type: String }) checkHelptext: string | null = null @property({ type: Boolean }) defaultChecked: boolean = false @property({ type: Boolean }) hasTile: boolean = false @property({ type: Boolean }) isSwitch: boolean = false @property({ type: String }) labelPosition: 'right' | 'left' = 'right' @property({ type: Boolean }) hideLabel: boolean = false @property({ type: Boolean, reflect: true }) checked: boolean | string | null = null @property({ type: Boolean, reflect: true }) indeterminate: boolean | 'true' | 'false' | '' = false @property({ type: String, reflect: true }) type: string = 'checkbox' @property({ type: String }) tagText: string | null = null @property({ type: Boolean }) optionalTag: boolean = false @property({ type: String }) optionalText: string = 'Valgfritt' @property({ type: Boolean }) requiredTag: boolean = false @property({ type: String }) requiredText: string = 'Må fylles ut' connectedCallback() { super.connectedCallback() } attributeChangedCallback(name: string, _old: string | null, value: string | null): void { if (name === 'defaultChecked' && !this.checked) { this.checked = this.defaultChecked } if (name === 'checked') { this.checked = this.checked === '' || this.checked === 'true' || this.checked === true if (this.inputRef.value) this.inputRef.value.checked = this.checked as boolean } if (name === 'indeterminate') { this.indeterminate = this.indeterminate === '' || this.indeterminate === 'true' || this.indeterminate === true if (this.inputRef.value) this.inputRef.value.indeterminate = this.indeterminate as boolean } super.attributeChangedCallback(name, _old, value) } protected firstUpdated(_changedProperties: PropertyValues): void { if (_changedProperties.has('defaultChecked') && !this.checked) { this.checked = this.defaultChecked } if (this.inputRef.value) { this.inputRef.value.indeterminate = this.indeterminate === '' || this.indeterminate === 'true' || this.indeterminate === true } super.firstUpdated(_changedProperties) } protected updated(changedProperties: PropertyValues): void { if (changedProperties.has('defaultChecked') && !this.checked) { this.checked = this.defaultChecked } if (changedProperties.has('checked') && this.inputRef.value) { this.inputRef.value.checked = this.checked === '' || this.checked === 'true' || this.checked === true } if (changedProperties.has('indeterminate') && this.inputRef.value) { this.inputRef.value.indeterminate = this.indeterminate === '' || this.indeterminate === 'true' || this.indeterminate === true } super.updated(changedProperties) } render() { const inputTileClasses = classMap({ 'pkt-input-check__input': true, 'pkt-input-check__input--tile': this.hasTile, 'pkt-input-check__input--tile-disabled': this.disabled && this.hasTile, }) const inputCheckBoxClasses = classMap({ 'pkt-input-check__input-checkbox': true, 'pkt-input-check__input-checkbox--error': this.hasError, }) const labelClasses = classMap({ 'pkt-input-check__input-label': true, 'pkt-input-check__input-label--disabled': this.disabled, 'pkt-input-check__input-label--left': this.labelPosition === 'left', 'pkt-input-check__input-label--right': this.labelPosition === 'right', 'pkt-sr-only': this.hideLabel, }) const tagClasses = 'pkt-tag pkt-tag--small pkt-tag--thin-text' const tags = () => { return html` ${this.tagText ? html`<span class=${tagClasses + ' pkt-tag--gray'}>${this.tagText}</span>` : nothing} ${this.optionalTag ? html`<span class=${tagClasses + ' pkt-tag--blue-light'}>${this.optionalText}</span>` : nothing} ${this.requiredTag ? html`<span class=${tagClasses + ' pkt-tag--beige'}>${this.requiredText}</span>` : nothing} ` } const labelAndHelptext = () => { return html` <label class=${labelClasses} for=${this.id + '-internal'}> ${this.label} ${tags()} ${this.checkHelptext ? html`<div class="pkt-input-check__input-helptext">${this.checkHelptext}</div>` : nothing} </label> ` } return html` <div class="pkt-input-check"> <div class=${inputTileClasses}> ${this.labelPosition === 'left' ? labelAndHelptext() : nothing} <input id=${this.id + '-internal'} class=${inputCheckBoxClasses} type="checkbox" ?disabled=${this.disabled} name=${this.name + '-internal'} ${ref(this.inputRef)} @change=${this.handleChange} @click=${this.handleClick} @blur=${this.onBlur} @focus=${this.onFocus} ?checked=${this.checked} role=${this.isSwitch ? 'switch' : 'checkbox'} /> ${this.labelPosition === 'right' ? labelAndHelptext() : nothing} </div> </div> ` } private handleClick(e: Event) { // Prevent click on disabled checkbox if (this.disabled) { e.preventDefault() e.stopImmediatePropagation() return false } } private handleChange(e: Event) { // Don't process change if disabled if (this.disabled) { e.preventDefault() e.stopImmediatePropagation() return false } this.toggleChecked(e) } private toggleChecked(e: Event) { // Don't toggle if disabled if (this.disabled) { e.preventDefault() e.stopImmediatePropagation() return } // Also check if the input element itself is disabled const target = e.target as HTMLInputElement if (target && target.disabled) { e.preventDefault() e.stopImmediatePropagation() return } e.stopImmediatePropagation() this.touched = true if (this.inputRef.value) { this.checked = this.inputRef.value.matches(':checked') this.valueChecked(this.checked) } } } try { customElement('pkt-checkbox')(PktCheckbox) } catch (e) { console.warn('Forsøker å definere <pkt-checkbox>, men den er allerede definert') }