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/time-range-field/time-range-field.css

93 lines
3.3 KiB

feat(eidos): port time-range-field from soma Eidos wrapper for time range selection — start/end TimeField inputs sharing a single ZonedDateTime range value. Mirrors DateRangeField pattern with `data-time-field` overlay trick so item segments inherit the time-field recipe. ## Feature comparison | Feature | react-aria | Mantine | Eidos | |----------------------|------------|---------|-------| | Range value | ✓ | ✓ | ✓ | | Per-endpoint Input | ✓ | ✓ | ✓ | | Segment editing | ✓ | — | ✓ | | Granularity prop | ✓ | ✓ | ✓ | | Hour cycle (12/24) | ✓ | ✓ | ✓ | | Min/max value | ✓ | ✓ | ✓ | | Placeholder per-end | ✓ | — | ✓ | | Invalid signalling | ✓ | ✓ | ✓ | | Disabled / readOnly | ✓ | ✓ | ✓ | | Form integration | ✓ | ✓ | ✓ | | Size cascade | — | ✓ | ✓ xs–xl | | Variant cascade | — | ✓ | ✓ 3 | | Color cascade | — | — | ✓ 6 | ## Parts Root · Label · Input (type='start' | 'end') · Segment (re-exported from TimeField). Each Input scopes its own TimeField context so segment editing routes to the correct endpoint. ## Recipe Grid `1fr · auto · 1fr` with em-dash separator. Specificity bump on `[data-time-range-field][data-time-field]` to win over the overlay data-time-field rules. ## Demo Canonical 6-tab depth (~530L): Live / API / Morfo / Sema / Recipe / A11y. Variant / size / color / granularity / hour-cycle / min-max / disabled / readOnly / required controls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
/*
* TimeRangeField recipe — layout only.
*
* The chrome of each endpoint input is painted by `time-field.css`
* because:
*
* 1. The eidos `<TimeRangeField>` root overlays `data-time-field=""`
* on top of `data-time-range-field`, so the existing
* `[data-time-field] { --_*: … }` token setup, size cascades,
* variant cascades and color tokens all apply inside the range.
*
* 2. soma's `<TimeRangeField.Input>` overlays `data-time-field-input`
* on each endpoint container (the runtime composes both markers
* on the same element). So `[data-time-field-input]` chrome rules
* paint each endpoint exactly like a standalone TimeField.
*
* Same trick `DateRangeField` uses with `data-date-field`. This recipe
* only adds the range-specific layout:
*
* - Label sits above the inputs, spans the full row
* - Two inputs side-by-side via grid (1fr · auto · 1fr)
* - Em-dash separator in the middle grid cell
* - `data-endpoint='start'` / `data-endpoint='end'` available for
* consumer-side tinting; the default recipe leaves it inert.
*
* [data-time-range-field] → grid wrapper (also data-time-field)
* [data-time-range-field-label] → label, spans the full row
* [data-time-range-field-input] → endpoint container
* (also data-time-field-input)
*/
/*
* Specificity bump (0, 2, 0) so we beat `[data-time-field]`'s base
* rule from `time-field.css` — that rule sets
* `display: inline-flex; flex-direction: column;` which would stack
* the inputs instead of placing them on a 1fr · auto · 1fr grid.
* The eidos wrapper overlays both markers on the same element; this
* recipe makes the grid layout deterministic regardless of CSS
* import order.
*/
[data-time-range-field][data-time-field] {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-rows: auto auto;
column-gap: var(--time-range-field-row-gap, var(--space-3));
row-gap: var(--time-field-stack-gap, var(--space-1-5));
align-items: center;
inline-size: 100%;
min-inline-size: 0;
}
[data-time-range-field-label] {
grid-column: 1 / -1;
grid-row: 1;
font-family: var(--time-field-label-font-family, var(--style-label-font-family));
font-size: var(--time-field-label-font-size, var(--font-size-sm));
font-weight: var(--time-field-label-font-weight, 500);
color: var(--time-field-label-color, var(--color-content-primary));
}
[data-time-range-field-input] {
grid-row: 2;
min-inline-size: 0;
}
[data-time-range-field-input][data-endpoint='start'] {
grid-column: 1;
}
[data-time-range-field-input][data-endpoint='end'] {
grid-column: 3;
}
/* Em-dash separator between the two inputs. Anchored to the grid's
* middle column / second row. */
[data-time-range-field]:has(
[data-time-range-field-input][data-endpoint='start']
):has([data-time-range-field-input][data-endpoint='end'])::before {
content: var(--time-range-field-separator-glyph, '—');
grid-column: 2;
grid-row: 2;
color: var(--time-range-field-separator-color, var(--color-content-muted));
font-family: var(--style-label-font-family, var(--font-ui));
font-size: 0.9em; /* literal: separator scales with the field font-size */
user-select: none;
pointer-events: none;
}
[data-time-range-field][data-disabled] {
opacity: var(--time-field-disabled-opacity, 0.55);
pointer-events: none;
}

Powered by TurnKey Linux.