Forms · TimeRangeField

TimeRangeField

Companion of TimeField for time ranges ({`{ start, end }`}). Two endpoint inputs share one Label and the same Segment component; soma's TimeRangeField provider creates a separate TimeField context per endpoint so segment editing routes to the correct boundary. Visual chrome is reused 1:1 from time-field.css — the eidos root overlays data-time-field on top of data-time-range-field so the entire size / variant / color cascade applies inside the range without recipe duplication. This recipe only adds the 1fr · auto · 1fr grid layout + em-dash separator.

parts{compiled.parts.order.length} events{events.length} sizes5 value {valueLabel}
{#if showLabel} {labelText} {/if} {#snippet children({ segments })} {#each segments as { part, value }, i (`${part}-${i}`)} {value} {/each} {/snippet} {#snippet children({ segments })} {#each segments as { part, value }, i (`${part}-${i}`)} {value} {/each} {/snippet}
trace {#if trace.length === 0} tab into a segment and arrow up/down to edit {:else} {#each trace.slice(0, 3) as entry (entry.at)} {entry.event} · {entry.family}{entry.intent ? ' · ' + entry.intent : ''} {fmtTime(entry.at)} {/each} {/if} value {valueLabel}
{#if tab === 'live'}

Controls

soma format
eidos visual props
Composition
eidos visual · grid layout, em-dash separator, chrome from time-field.css svelte
{eidosSnippet}
{/if} {#if tab === 'api'}

API reference

4 parts: Provider, Label, Input (start/end), Segment.

Provider
PropTypeDefaultDescription
value bindableTimeRange | null—{`{ start, end }`} time pair.
placeholderTimeValue—Used to seed segments before any value is set.
granularity'hour' | 'minute' | 'second''minute'Smallest segment.
hourCycle12 | 24locale12h vs 24h presentation.
hideTimeZonebooleanfalseSuppress timezone segment for ZonedDateTime values.
minValue · maxValueTimeValue—Validation range applied to BOTH endpoints.
disabled · readonly · requiredbooleanfalseOR-merged with enclosing Field.Provider.
locale · dirBCP47 · 'ltr' | 'rtl'soma prefs—
size eidos'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Visual size cascade (reuses TimeField tokens).
variant eidosControlVariant'surface'Input chrome treatment.
color eidosColorRole'primary'Focus + selection accent.
Input
PropTypeDefaultDescription
type'start' | 'end'requiredWhich endpoint this input represents.
namestring—Hidden form input name (per endpoint).
aria-labelstring—Override accessible name.
Label · Segment

Label sits above the two inputs (grid row 1, full width). Segment is re-exported from TimeField — each endpoint's Input scopes its own TimeField context so segment editing routes to the right endpoint without ambiguity.

{/if} {#if tab === 'morfo'}

morfo · declarative contract

Source: src/uix/morfo/components/time-range-field.ts.

FieldValue
name"{timeRangeFieldMorfo.name}"
kebab"{timeRangeFieldMorfo.kebab}"
parts.length{timeRangeFieldMorfo.parts.length}
events.length{events.length}
Parts
{#each partsList as part (part.kebab)} {/each}
PartMarkerElementRoleArchetypeStatesOptional
{part.kebab} [{part.marker}] <{part.defaultElement}> {part.role ?? '—'} {part.archetype ?? '—'} {part.states.length ? part.states.join(' | ') : '—'} {part.optional ? 'yes' : 'no'}
{/if} {#if tab === 'sema'}

sema · events

Events fire on segment commit (per endpoint).

{#each events as action (action.name)} {@const sem = action.semantic} {@const intentDecl = 'intent' in sem ? sem.intent : undefined} {@const intentStr = typeof intentDecl === 'string' ? intentDecl : intentDecl ? `fromProp:${(intentDecl as { fromProp?: string }).fromProp ?? '?'}` : '—'} {/each}
NameFamilyVerbSequenceIntent
{action.name} {sem.family} {sem.verb ?? '—'} {sem.sequence ?? 'pre'} {intentStr}
{/if} {#if tab === 'recipe'}

Eidos recipe

Layout-only at src/uix/eidos/components/time-range-field/time-range-field.css. Chrome on each endpoint Input comes from time-field.css because the eidos root overlays data-time-field="" on top of data-time-range-field — the entire size / variant / color cascade applies inside the range without duplicating any rules.

SelectorSourceWhat it paints
[data-time-range-field][data-time-field]eidosGrid wrapper (1fr · auto · 1fr).
[data-time-range-field-label]morfoLabel spanning full row.
[data-time-range-field-input][data-endpoint='start' | 'end']morfoEndpoint container — grid columns 1 / 3.
[data-time-range-field]::beforeeidosEm-dash separator in middle column.
[data-time-field-input], [data-time-field-segment]eidosInherited from time-field.css — each endpoint paints like a standalone TimeField.
{/if} {#if tab === 'a11y'}

Accessibility

Same ARIA contract as TimeField, applied per endpoint. Each segment is a role="spinbutton" with aria-valuemin / aria-valuemax / aria-valuenow driven by the resolved value; Tab moves across segments AND across the start↔end boundary.

Keyboard
KeyAction
ArrowUp / ArrowDownIncrement / decrement the focused segment.
ArrowLeft / ArrowRightMove focus to previous / next segment (crosses start↔end).
Home / EndFirst / last editable segment of the focused endpoint.
DigitType to fill the segment; auto-advances on overflow.
BackspaceClear digit-by-digit.
TabAdvance focus across endpoint segments.
{/if}