date-range-picker: unify start + end into a single input chrome

Closes incidencia point B (range field shouldn't show two separate
boxes). New CSS contract: `[data-date-range-field-group]` on the
wrapper element collapses the chrome around its descendants:

- The group owns the border, background, focus ring, invalid state,
  variant/ghost treatment, and disabled opacity.
- Each `[data-date-range-field-input]` inside loses its own border,
  background, and padding; it just contributes its segments to the
  shared row.
- The "to" separator (.range-separator or `[data-range-separator]`)
  picks up the field's literal tone.
- The embedded trigger from the previous commit sits flush at the
  trailing edge of the group, since `data-date-field-input` already
  detects the embedded case.

Demo: add `data-date-range-field-group` to the `.range-field-row`
wrapper. Visually now reads as one input pill: `05 / 20 / 2026 to
06 / 03 / 2026 📅`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
active-uix
dev 5 months ago
parent 3b464ee361
commit 0d164b54de

@ -191,6 +191,73 @@
box-shadow: var(--date-field-focus-shadow); box-shadow: var(--date-field-focus-shadow);
} }
/* ── Group treatment: single input chrome around start + end ────────────────
* When the consumer wraps both endpoints (and optional separator + trigger)
* in `<div data-date-range-field-group>`, the chrome moves to the group:
* a single border, a single focus ring, a single background. Each endpoint
* input loses its own box and the trigger lives flush inside. */
[data-date-range-field-group] {
display: inline-flex;
align-items: center;
gap: var(--_date-field-gap);
flex: 1 1 24rem;
min-inline-size: 0;
min-block-size: var(--_date-field-height);
padding-inline: var(--_date-field-px);
border: var(--date-field-border-width) solid var(--date-field-border);
border-radius: var(--date-field-radius);
background: var(--date-field-bg);
color: inherit;
transition:
background var(--date-field-transition-duration) var(--date-field-transition-ease),
border-color var(--date-field-transition-duration) var(--date-field-transition-ease),
box-shadow var(--date-field-transition-duration) var(--date-field-transition-ease);
}
[data-date-range-field-group]:has([data-date-field-segment]:focus-visible) {
border-color: var(--_date-field-accent-border);
box-shadow: var(--date-field-focus-shadow);
}
[data-date-range-picker][data-variant='outline'] [data-date-range-field-group] {
background: transparent;
}
[data-date-range-picker][data-variant='ghost'] [data-date-range-field-group] {
border-color: transparent;
background: transparent;
padding-inline: 0;
}
[data-date-range-picker][data-invalid] [data-date-range-field-group] {
border-color: var(--date-field-border-invalid);
}
[data-date-range-field-group] [data-date-range-field-input] {
flex: 0 1 auto;
min-block-size: auto;
padding-inline: 0;
border: none;
border-radius: 0;
background: transparent;
box-shadow: none;
}
[data-date-range-field-group] [data-date-range-field-input]:has([data-date-field-segment]:focus-visible) {
border: none;
box-shadow: none;
}
/* Separator span ("to", "/", "→") inside the group inherits the field tone
and stays vertically aligned. */
[data-date-range-field-group] > .range-separator,
[data-date-range-field-group] [data-range-separator] {
color: var(--date-field-literal-color);
flex: 0 0 auto;
user-select: none;
}
[data-date-range-picker][data-invalid] [data-date-range-field-input], [data-date-range-picker][data-invalid] [data-date-range-field-input],
[data-date-range-field-input][data-invalid] { [data-date-range-field-input][data-invalid] {
border-color: var(--date-field-border-invalid); border-color: var(--date-field-border-invalid);

@ -503,7 +503,7 @@
calendarLabel="Booking date range" calendarLabel="Booking date range"
> >
<DateRangePicker.Label>{labelText}</DateRangePicker.Label> <DateRangePicker.Label>{labelText}</DateRangePicker.Label>
<div class="range-field-row"> <div class="range-field-row" data-date-range-field-group>
<DateRangePicker.Input type="start" name={startName} aria-label="Start date"> <DateRangePicker.Input type="start" name={startName} aria-label="Start date">
{#snippet children({ segments }: DateRangePickerInputSnippetProps)} {#snippet children({ segments }: DateRangePickerInputSnippetProps)}
{#each segments as { part, value }, index (`start-${part}-${index}`)} {#each segments as { part, value }, index (`start-${part}-${index}`)}

Loading…
Cancel
Save

Powered by TurnKey Linux.