|
|
4 months ago | |
|---|---|---|
| .. | ||
| README.md | 5 months ago | |
| date-range-field-input.svelte | 5 months ago | |
| date-range-field-label.svelte | 5 months ago | |
| date-range-field.css | 5 months ago | |
| date-range-field.svelte | 4 months ago | |
| index.ts | 5 months ago | |
| types.ts | 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
::beforepseudo, 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/Hintparts. 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
- Bits UI: https://bits-ui.com/docs/components/date-range-field
- Ark UI: https://ark-ui.com/docs/components/date-range-picker
- react-aria-components: https://react-spectrum.adobe.com/react-aria/DateRangePicker.html