UNPKG

vira

Version:

A simple and highly versatile design system using element-vir.

135 lines (128 loc) 5.01 kB
import { randomString } from '@augment-vir/common'; import { extractEventTarget } from '@augment-vir/web'; import { calculateRelativeDate, createUtcFullDate, FullDatePart, getNowInUtcTimezone, parseInputElementValue, toHtmlInputString, userTimezone, } from 'date-vir'; import { css, defineElementEvent, html, ifDefined, listen } from 'element-vir'; import { viraDisabledStyles } from '../styles/disabled.js'; import { viraFormCssVars } from '../styles/form-styles.js'; import { defineViraElement } from '../util/define-vira-element.js'; import { ViraAbsoluteTime } from './vira-absolute-time.element.js'; /** * A native date picker input that emits `FullDate` values. Fires `valueChange` whenever the user * selects (or clears) a date. * * @category Input * @category Elements * @see https://electrovir.github.io/vira/book/elements/vira-date-input */ export const ViraDateInput = defineViraElement()({ tagName: 'vira-date-input', events: { /** Fires whenever the user selects or clears a date. */ valueChange: defineElementEvent(), }, state() { return { /** Used to couple the label and input together. Not applied when no label is provided. */ randomId: randomString(32), }; }, hostClasses: { 'vira-date-input-error': ({ inputs }) => !!inputs.hasError, 'vira-date-input-disabled': ({ inputs }) => !!inputs.isDisabled, }, styles: ({ hostClasses }) => css ` :host { display: inline-block; width: 224px; color: ${viraFormCssVars['vira-form-foreground-color'].value}; } label { display: flex; flex-direction: column; gap: 2px; width: 100%; } .input-label { font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value}; text-align: left; } input { box-sizing: border-box; width: 100%; padding: 4px 8px; font-size: inherit; border: 1px solid ${viraFormCssVars['vira-form-border-color'].value}; border-radius: ${viraFormCssVars['vira-form-radius'].value}; background-color: ${viraFormCssVars['vira-form-background-color'].value}; color: ${viraFormCssVars['vira-form-foreground-color'].value}; } ${hostClasses['vira-date-input-error'].selector} input { border-color: ${viraFormCssVars['vira-form-error-color'].value}; } ${hostClasses['vira-date-input-disabled'].selector} { cursor: not-allowed; & input { ${viraDisabledStyles}; } } `, render({ inputs, state, dispatch, events }) { if (inputs.isReadonly) { const readonlyTemplate = inputs.value ? html ` <${ViraAbsoluteTime.assign({ time: inputs.value, showDateOnly: inputs.showDateOnly, showTimeOnly: inputs.showTimeOnly, timezone: inputs.timezone, })}></${ViraAbsoluteTime}> ` : html ` <span class="readonly-value">&nbsp;</span> `; if (inputs.label) { return html ` <label> <span class="input-label">${inputs.label}</span> ${readonlyTemplate} </label> `; } else { return readonlyTemplate; } } const inputValue = inputs.value ? toHtmlInputString(inputs.value, FullDatePart.Date) : ''; const minDate = toHtmlInputString(inputs.min || createUtcFullDate('1800-01-01'), FullDatePart.Date); const maxDate = toHtmlInputString(inputs.max || calculateRelativeDate(getNowInUtcTimezone(), { years: 10, }), FullDatePart.Date); const inputTemplate = html ` <input id=${ifDefined(inputs.label ? state.randomId : undefined)} aria-label=${ifDefined(inputs.label || undefined)} type="date" min=${minDate} max=${maxDate} ?disabled=${inputs.isDisabled} .value=${inputValue} ${listen('input', (event) => { const element = extractEventTarget(event, HTMLInputElement); dispatch(new events.valueChange(parseInputElementValue(element, inputs.timezone || userTimezone))); })} /> `; if (inputs.label) { return html ` <label for=${state.randomId}> <span class="input-label">${inputs.label}</span> ${inputTemplate} </label> `; } else { return inputTemplate; } }, });