UNPKG

@3mo/field

Version:

A set of field web components.

156 lines (154 loc) 4.26 kB
import { __decorate } from "tslib"; import { html, property, event, Component, state, css } from '@a11d/lit'; import { SlotController } from '@3mo/slot-controller'; import { FocusController } from '@3mo/focus-controller'; /** * @attr value - The field's value * @attr label - The field's label * @attr readonly - Whether the field is readonly * @attr disabled - Whether the field is disabled * @attr required - Whether the field is required * * @slot - The field's content * @slot start - Content to be placed at the start of the field * @slot end - Content to be placed at the end of the field * * @csspart container - Field's container * * @fires change * @fires input * @fires validityChange */ export class FieldComponent extends Component { constructor() { super(...arguments); this.label = ''; this.readonly = false; this.disabled = false; this.required = false; this.invalid = false; this.focused = false; this.slotController = new SlotController(this); this.focusController = new FocusController(this, { handleChange: (focused, bubbled, method) => { this.focused = focused; focused ? this.handleFocus(bubbled, method) : this.handleBlur(bubbled, method); } }); } update(changedProperties) { if (changedProperties.has('value')) { this.valueUpdated(); } super.update(changedProperties); } valueUpdated() { this.inputValue = this.value; this.validate(); } handleFocus(bubbled, method) { bubbled; method; } handleBlur(bubbled, method) { bubbled; method; } handleInput(value, e) { e?.stopPropagation(); this.inputValue = value; this.input.dispatch(this.inputValue); this.validate(); } handleChange(value, e) { e?.stopPropagation(); this.value = value; this.change.dispatch(this.value); this.validate(); } get isPopulated() { return this.inputValue !== undefined; } get isActive() { return this.focused; } get isDense() { return false; } static get styles() { return css ` :host { display: block; } mo-field { width: 100%; } `; } get template() { return html ` <mo-field id='field' exportparts='container' label=${this.label} ?populated=${this.isPopulated} ?disabled=${this.disabled} ?readonly=${this.readonly} ?required=${this.required} ?dense=${this.isDense} ?invalid=${this.invalid} ?active=${this.isActive} > ${this.startSlotTemplate} ${this.inputTemplate} ${this.endSlotTemplate} </mo-field> `; } get startSlotTemplate() { return !this.slotController.hasAssignedElements('start') ? html.nothing : html ` <slot slot='start' name='start'></slot> `; } get endSlotTemplate() { return !this.slotController.hasAssignedElements('end') ? html.nothing : html ` <slot slot='end' name='end'></slot> `; } async validate() { const validity = await this.checkValidity(); this.invalid = !validity; this.validityChange.dispatch(validity); } } (() => { property({ type: Object, bindingDefault: true })(FieldComponent.prototype, 'value'); })(); __decorate([ event() ], FieldComponent.prototype, "change", void 0); __decorate([ event() ], FieldComponent.prototype, "input", void 0); __decorate([ event() ], FieldComponent.prototype, "validityChange", void 0); __decorate([ property() ], FieldComponent.prototype, "label", void 0); __decorate([ property({ type: Boolean }) ], FieldComponent.prototype, "readonly", void 0); __decorate([ property({ type: Boolean }) ], FieldComponent.prototype, "disabled", void 0); __decorate([ property({ type: Boolean }) ], FieldComponent.prototype, "required", void 0); __decorate([ property({ type: Boolean }) ], FieldComponent.prototype, "invalid", void 0); __decorate([ state() ], FieldComponent.prototype, "focused", void 0); __decorate([ state() ], FieldComponent.prototype, "inputValue", void 0);