You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/components/date-range-field
dev 725f7abe37
perf(eidos): code-split 16 picker-family recipes (Phase 3, batch 4)
4 months ago
..
README.md feat(date-range-field): port from soma to eidos (Tier 2 sprint, 1/3) 5 months ago
date-range-field-input.svelte feat(date-range-field): port from soma to eidos (Tier 2 sprint, 1/3) 5 months ago
date-range-field-label.svelte feat(date-range-field): port from soma to eidos (Tier 2 sprint, 1/3) 5 months ago
date-range-field.css fix(date-range-field): canonical demo + recipe specificity + DateField overlay 5 months ago
date-range-field.svelte perf(eidos): code-split 16 picker-family recipes (Phase 3, batch 4) 4 months ago
index.ts feat(date-range-field): port from soma to eidos (Tier 2 sprint, 1/3) 5 months ago
types.ts feat(date-range-field): port from soma to eidos (Tier 2 sprint, 1/3) 5 months ago

README.md

<DateRangeField> — eidos

Two-endpoint date entry, segment-by-segment. Mirrors <DateField> × 2 with shared validation (min/max/validate) and a single label that names the whole range.

Usage

<script lang="ts">
  import { DateRangeField } from '$uix/eidos/components/date-range-field';
  import { CalendarDate } from '$libs/days';
  let value = $state({
    start: new CalendarDate(2026, 1, 1),
    end: new CalendarDate(2026, 1, 15)
  });
</script>

<DateRangeField bind:value variant="surface" size="md">
  <DateRangeField.Label>Period</DateRangeField.Label>
  <DateRangeField.Input type="start">
    {#snippet children({ segments })}
      {#each segments as seg}
        <DateRangeField.Segment part={seg.part}>{seg.value}</DateRangeField.Segment>
      {/each}
    {/snippet}
  </DateRangeField.Input>
  <DateRangeField.Input type="end">
    {#snippet children({ segments })}
      {#each segments as seg}
        <DateRangeField.Segment part={seg.part}>{seg.value}</DateRangeField.Segment>
      {/each}
    {/snippet}
  </DateRangeField.Input>
</DateRangeField>

Parts

Part Notes
DateRangeField (root) Provider; bind:value DateRange.
Label Single label naming the whole range.
Input One per endpoint (type='start' / type='end'). Each scopes its own DateField context internally.
Segment Re-export of DateField.Segment — same recipe.

Eidos-layer props

Prop Type Default Notes
variant 'surface' | 'outline' | 'ghost' 'surface' Inherits DateField vocabulary.
color primary | secondary | neutral | affirm | risk | threat 'primary' Active endpoint tint.
size 'xs' | 'sm' | 'md' | 'lg' | 'xl' (responsive) 'md' Cascaded to both inputs + segments.

Headless props (soma)

value, placeholder, onValueChange, onStartValueChange, onEndValueChange, validate, onInvalid, minValue, maxValue, disabled, readonly, startReadonlySegments, endReadonlySegments, required, kind, granularity, hideTimeZone, hourCycle, locale, dir, errorMessageId. See src/uix/soma/components/date-range-field/types.ts.

Passive justification

Passive at the morfo level — the range-field morfo declares parts (Provider, Label, Input) but no events. Sema events (segment commits, value changes) are emitted by the two composed DateField runtimes scoped per endpoint, where they belong; the range provider itself owns no event vocabulary beyond what soma synthesizes from its endpoint listeners.

The component IS interactive from the user's perspective — "passive" here is the same contract-layer classification used for <AlertDialog> and <PinInput>.

Baseline

WAI-ARIA Spinbutton pattern (per segment): https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/

Soma owns: segment focus / arrow stepping per endpoint, paste distribution, validation, hidden form inputs (ISO date strings).

Comparativa

Lib Two endpoints Shared validate Segment scoping Range tint
react-aria DateRangePicker ✓ ✓ per endpoint —
Bits UI DateRangeField ✓ ✓ per endpoint —
Ark UI ✓ ✓ per endpoint —
Eidos (this) ✓ ✓ per endpoint ✓ active endpoint border

Functional parity with the strongest references; range-tint affordance keeps focus visible across two-input layouts.

Decisiones

  • Segment re-uses DateField's wrapper — each endpoint Input scopes a DateField context, so the existing date-field segment recipe applies without duplication.
  • Separator rendered via ::before pseudo, not as a <span> child. Consumers don't have to ship <span>—</span> between Inputs; the recipe handles it via :has([data-type='end']).
  • No Description / Hint parts. This is the field primitive; description belongs to the enclosing <Field> shell. Composers wrap with <Field> for the full form pattern.

Gaps

Gap Disposición Detalle
Hidden form inputs styling diferir Soma emits two ISO hidden inputs; not visible by recipe. Demo doesn't expose.
data-color='risk' cascade for invalid endpoints implementar próximo turno Soma exposes invalid at provider level; would benefit from per-endpoint coloring.
RTL separator glyph swap diferir Currently uses — for all locales; some RTL locales prefer إلى etc. Wait for actual i18n need.

Reference

Powered by TurnKey Linux.