@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
121 lines (111 loc) • 4.2 kB
text/typescript
import { html, PropertyValues } from 'lit'
import { ifDefined } from 'lit/directives/if-defined.js'
import { customElement, property, state } from 'lit/decorators.js'
import { Ref, createRef, ref } from 'lit/directives/ref.js'
import { classMap } from 'lit/directives/class-map.js'
import { live } from 'lit/directives/live.js'
import { PktInputElement } from '@/base-elements/input-element'
import { PktSlotController } from '@/controllers/pkt-slot-controller'
import '@/components/input-wrapper'
import '@/components/icon'
export class PktTextarea extends PktInputElement {
private inputRef: Ref<HTMLTextAreaElement> = createRef()
private helptextSlot: Ref<HTMLElement> = createRef()
value: string = ''
autocomplete: string = 'off'
rows: number | null = null
counterCurrent = 0
constructor() {
super()
this.slotController = new PktSlotController(this, this.helptextSlot)
}
attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
if (name === 'value' && this.value !== _old) {
this.counterCurrent = value ? value.length : 0
this.valueChanged(value, _old)
}
super.attributeChangedCallback(name, _old, value)
}
updated(changedProperties: PropertyValues) {
super.updated(changedProperties)
if (changedProperties.has('value')) {
this.counterCurrent = this.value?.length || 0
this.valueChanged(this.value, changedProperties.get('value'))
}
if (changedProperties.has('id')) {
!this.name && this.id && (this.name = this.id)
}
}
render() {
const inputClasses = classMap({
'pkt-input': true,
'pkt-input--fullwidth': this.fullwidth,
'pkt-input--counter-error':
this.counter &&
this.counterMaxLength &&
this.value.length &&
this.value.length > this.counterMaxLength,
})
const labelledBy = this.ariaLabelledby || `${this.id}-input-label`
return html`<pkt-input-wrapper
label=${this.label}
?counter=${this.counter}
?disabled=${this.disabled}
?hasError=${this.hasError}
?inline=${this.inline}
?optionalTag=${this.optionalTag}
?required=${this.required}
?requiredTag=${this.requiredTag}
?useWrapper=${this.useWrapper}
.ariaDescribedBy=${this.ariaDescribedBy}
.counterCurrent=${this.counterCurrent}
.counterMaxLength=${this.counterMaxLength}
.errorMessage=${this.errorMessage}
.forId="${this.id + '-input'}"
.helptext=${this.helptext}
.helptextDropdown=${this.helptextDropdown}
.helptextDropdownButton=${this.helptextDropdownButton}
.optionalText=${this.optionalText}
.requiredText=${this.requiredText}
.tagText=${this.tagText}
class="pkt-textarea"
>
<div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
<textarea
${ref(this.inputRef)}
class=${inputClasses}
id=${this.id + '-input'}
name=${(this.name || this.id) + '-input'}
placeholder=${ifDefined(this.placeholder)}
.value=${live(this.value)}
minlength=${ifDefined(this.minlength)}
maxlength=${ifDefined(this.maxlength)}
?readonly=${this.readonly}
autocomplete=${this.autocomplete}
aria-labelledby=${labelledBy}
aria-invalid=${this.hasError}
aria-errormessage=${`${this.id}-error`}
rows=${this.rows}
?disabled=${this.disabled}
=${(e: InputEvent) => {
this.value = (e.target as HTMLInputElement).value
this.onInput()
e.stopImmediatePropagation()
}}
=${(e: Event) => {
e.stopImmediatePropagation()
}}
=${(e: FocusEvent) => {
this.onFocus()
e.stopImmediatePropagation()
}}
=${(e: FocusEvent) => {
this.value = (e.target as HTMLInputElement).value
this.onBlur()
e.stopImmediatePropagation()
}}
></textarea>
</pkt-input-wrapper>`
}
}