astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
526 Commits (8515f5e67337b2396e96d0c7309b7ddf57b681dc)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
8515f5e673 |
fix(color-picker): ValueSwatch now reactively reflects the current color
User report: 'la caja del color seleccionado en el pickercolor no se
actualiza, compruébalo.'
Root cause
----------
The Eidos recipe had an `[data-color-picker-value-swatch]::after`
overlay that painted `var(--cp-trigger-color, currentColor)` on top of
the swatch — a CSS variable set ONLY on the trigger button by the
Eidos wrapper. The popover content is portaled outside the trigger's
subtree, so the var never propagated into the ValueSwatch element.
The overlay therefore stayed at its fallback (`currentColor`) and
covered the soma-set inline `background-color`, hiding the live colour.
Fix
---
1. **Soma `ColorPickerValueSwatchProvider.backgroundStyle`** now emits
BOTH `background-color: <hex>` and `--cp-current-color: <hex>` so:
- Consumers without the eidos recipe still see the colour (inline
background-color, as before).
- Eidos recipes / external CSS can read `--cp-current-color` as a
reactive CSS variable on the element itself.
2. **Eidos CSS** drops the `::after` overlay. Instead the checker
(transparency pattern) lives on a `::before` pseudo with
`z-index: -1` inside an isolated stacking context, so the soma's
inline `background-color` paints ON TOP and the checker shows
through only where alpha < 1. No more colour stomping.
Checks: 67/67 component-audit PASS, svelte-check 0 errors / 0 warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
da19728cb6 |
feat(color-picker): area drag emits handle-pick/handle-drag/commit-set + refresh demo snippets
User report: 'el selector del cuadro de colores, no tiene semántica, es
un drag, etc como el slider, no?'
You're right — the 2D area is a drag interaction with the same shape
as a slider. It was wiring pointer events to soma state but staying
silent to sema; nothing for sounds/haptics/transient styles to hook
onto. Now it speaks the same vocabulary as the slider.
Morfo additions (color-picker)
------------------------------
- `handle-pick` (family: handle, verb: pick, sequence: coincident,
target: area) — fires once at pointer-down.
- `handle-drag` (family: handle, verb: drag, sequence: coincident,
target: area) — fires on each move (pointer or keyboard step).
- `commit-set` already existed — now also emitted on pointer-up and
on each keyboard step (slider parity).
Soma changes (color-picker-provider)
------------------------------------
- ColorPickerAreaProvider:
- `onpointerdown` → trigger `handle-pick` then continue to drag.
- `handlePointerMove` → trigger `handle-drag` after writing the value.
- `onpointerup` → trigger `commit-set` then `commitChange()` for
the onValueChangeEnd callback.
- ColorPickerAreaThumbProvider.onkeydown:
- Each arrow / Home / End / PageUp / PageDown step now triggers
`handle-drag` + `commit-set` + commitChange(). Matches the slider's
keyboard semantics (one step = one drag + one commit).
Demo snippet refresh
--------------------
The `somaSnippet` / `eidosSnippet` in `/uix/components/color-picker`
were stuck on the pre-refactor API (`<ColorPicker.Area>` with explicit
Background+Thumb children, no `Control`, no `ValueSwatch`, no
PickerShell footer). Updated both to mirror the current demo body:
- Eidos: `Label / Control[Trigger + ValueText + HiddenInput] / Portal /
Content[Area / ChannelSlider hue / alpha / ValueSwatch +
ChannelInput + EyeDropper / SwatchGroup / Footer[Clear/Cancel/
Close]]`.
- Soma: same shape but uses `PickerShell.Footer / Clear / Cancel /
Close` explicitly (and the explicit Track/Thumb composition on
channel sliders for the curious).
- Both snippets honor the live `mode / inline / closeOnSelect /
enableAlpha / showFooter / showClear / showCancel / showClose`
flags from the chip controls.
Checks: 67/67 component-audit PASS, 40/40 morfo:check PASS,
svelte-check 0 errors / 0 warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
3e5be857c4 |
fix(color-picker): single-row preset palette of 10 swatches that share container width
User report: 'la paleta dejala en 10 y más pequeños para que solo ocupen una linea, se deben de ajustar a lo ancho'. Demo ---- - Preset palette trimmed from 11 to 10 colors. CSS — swatch-group rewritten to single-row flex layout ------------------------------------------------------ - `display: flex; flex-wrap: nowrap; inline-size: 100%; min-inline-size: 0` so all swatches share the available width. - Each `<SwatchTrigger>` becomes `flex: 1 1 0` + `min-inline-size: 0` + `aspect-ratio: 1` + `inline-size/block-size: auto`, with the recipe token (`--color-picker-swatch-size`) acting as `max-inline- size` instead of a fixed size. Net effect: swatches shrink/grow together to fit any popover width and any number of presets, while capping at 1.5rem so they don't blow up on huge containers. Math at default md popover (~19.5rem content width, ~14px padding each side, 10 swatches × ~23px + 9 × 6px gap ≈ ~284px usable). Each swatch lands at ~23px and the row never wraps. Checks: 67/67 component-audit PASS, svelte-check 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
aa62f0203c |
refactor(pickers): date/time/date-range pickers consume shared PickerShell
Follow-up to commit
|
5 months ago |
|
|
aaf35fdbb0 |
fix(color-picker/demo): compact value row — swatch + channel input + eyedropper inline
User feedback: 'se pueden realinear los diferentes elementos para que no sea tan alto, el pick from screen en la misma linea del color seleccionado, o el input del valor al lado del color, etc.' Collapses three previously-stacked rows into one: Before: [preview swatch + value text] ← row 1 [channel input segments + format] ← row 2 [eyedropper button + label] ← row 3 (right-aligned) After: [swatch] [channel input ........] [eyedropper] ← single row The ValueText is dropped because the channel input segments already show the hex/rgb/hsl value digit-by-digit (more useful than a static string). The eyedropper becomes a compact icon button at the end of the row — `aria-label="Pick color from screen"` still announces it. Net effect: ~50px shorter popover. Files ----- - web/routes/uix/components/color-picker/+page.svelte — `.cp-value-row` flex layout with swatch (1.75rem) + ChannelField (flex: 1 1 auto) + EyeDropper. ChannelField input forced `flex-wrap: nowrap` so segments stay inline. Old `.cp-preview-row` / `.cp-eyedropper-row` styles removed. Checks: 67/67 component-audit PASS, svelte-check 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
709d8a108e |
fix(color-picker): fix slider gradients + add live preview + label eyedropper
User report: 'los sliders son deficitarios, no muestra la banda de color ni de transferencia, faltan textos, el color seleccionado aparte del valor ascii, un texto que indique el gotero, etc.' Three concrete issues addressed. 1. Slider gradients invisible ----------------------------- Root cause: the soma channel-slider div carries BOTH `data-slider` (from SliderProvider.props) and `data-color-picker-channel-slider` (from mergeProps). My CSS targeted `[data-color-picker-channel-slider] [data-slider]::before` — i.e. as a *descendant*. They're the same element, so the selector never matched and the rainbow / alpha gradient stayed hidden. Fix: - New selector `[data-color-picker-channel-slider][data-slider]::before` paints the gradient on the slider's own track strip. - Transparency checker moved to the wrapper's `::after` (with `z-index: -1` + `isolation: isolate`) so it sits behind the gradient — visible only where the alpha gradient ramps to transparent. - Adds a subtle border on the track so the strip is visible against the popover surface. 2. Live preview alongside the hex/rgb/hsl string ------------------------------------------------ The popover used to show only the segmented ChannelInput (digits) and a small swatch dot on the trigger. Now the popover has a `.cp-preview- row` with `<ColorPicker.ValueSwatch>` (2rem) + `<ColorPicker.ValueText>` + uppercase format tag, so the user always sees the actual color visually alongside its numeric representation. 3. Eyedropper label ------------------- Added a textual `Pick from screen` label next to the icon button, plus `aria-label` on the EyeDropper. The button is no longer a mystery glyph. 4. Channel slider row labels ---------------------------- Each ChannelSlider now sits in a `.cp-slider-row` with a leading uppercase label (Hue / Alpha) so the user knows what each track drives without hovering or reading aria. 5. Section header for swatches ------------------------------ 'Preset colors' header above the swatch grid for visual hierarchy inside the popover. Files ----- - src/uix/eidos/components/color-picker/color-picker.css — slider gradient routing + checker-on-::after layering. - web/routes/uix/components/color-picker/+page.svelte — preview row, slider row labels, eyedropper label, section headers + local scoped CSS in <style>. Checks: 67/67 component-audit PASS, 40/40 morfo:check PASS, svelte-check 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
714ee3735c |
feat(picker-shell): extract shared Footer/Clear/Cancel/Close + apply to color-picker
Introduces PickerShell — a soma context + eidos parts shared by every
composite picker (date, time, color, future range pickers). Aligns with
norm N-8 (reuse components across complex composites) so the
Footer/Clear/Cancel/Close behavior lives in ONE place instead of being
duplicated per picker family.
New files
---------
- src/uix/soma/components/picker-shell/
picker-shell-handle.svelte.ts → pickerShellContext +
PickerShellHandle interface
(getMode / commit / cancel / clear).
exports.ts, index.ts → public surface.
- src/uix/eidos/components/picker-shell/
picker-shell-footer.svelte → [data-picker-footer][data-mode]
picker-shell-clear.svelte → [data-picker-clear][data-action]
picker-shell-cancel.svelte → [data-picker-cancel][data-action]
picker-shell-close.svelte → [data-picker-close][data-action]
picker-shell.css → canonical action-row recipe.
index.ts, types.ts → PickerShell namespace + prop types.
- Registered in src/uix/eidos/index.css.
Color-picker now consumes the shell
-----------------------------------
- ColorPickerProvider gets `mode: 'inline' | 'modal'` opt + a
`valueOnOpen` snapshot via watch(open) so cancel() can revert.
- New `commit()` / `cancel()` / `clear()` methods with shell-picker
semantics. The previous `commit()` (fires onValueChangeEnd) was
renamed `commitChange()` since the picker-shell `commit()` means
"save + close". All internal callers (area-thumb pointerup,
swatch click, eyedropper open, channel-slider drop) updated.
- Constructor registers the handle:
`pickerShellContext.set(this.pickerShellHandle)`.
- PopoverProvider receives `modal: mode === 'modal'` so outside-click
+ Escape get blocked when modal.
- Eidos `ColorPicker.Footer / .Clear / .Cancel / .Close` re-export
the shared parts. The old `ColorPicker.Close = PopoverClose` was
renamed `ColorPicker.PopoverClose`; the canonical `Close` is now
the picker-shell save action.
Demo
----
- New `mode` chip (inline | modal).
- Footer composition switches (render footer / clear / cancel / close).
- Renders <ColorPicker.Footer> with shell parts inside <Content>.
Visual fixes
------------
- Horizontal overflow on the popover content: added `min-inline-size: 0
/ max-inline-size: 100% / box-sizing: border-box / overflow-x: hidden`
on `[data-popover-content][data-color-picker-content]` and on its
direct children. Inner ChannelInput allowed to wrap segments instead
of pushing the popover wider.
- ColorField segments inside the popover gain `flex: 0 1 auto`.
Norms
-----
- N-8 case study appended to PENDIENTES.md documenting the
PickerShell extraction alongside the channel-slider refactor.
Checks
------
- 67/67 component-audit PASS
- 40/40 morfo:check PASS
- svelte-check 0 errors / 0 warnings
Follow-up (task #81): migrate date-picker / time-picker Footer to use
PickerShell too — drop the duplicate `date-picker-footer/clear/
cancel/close.svelte` and `time-picker-footer/clear/cancel/close.svelte`
files; update CSS selectors to `[data-picker-footer/...]`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
5d007ed9f9 |
refactor(color-picker): channel slider composes generic SliderProvider + N-8 norm
Drops ColorPickerChannelSliderProvider / TrackProvider / ThumbProvider (~200 lines of duplicated pointer/keyboard/ARIA handling) and rewrites `components/color-picker-channel-slider.svelte` to compose SliderProvider underneath. The channel slider now keeps only the channel-aware bridge: setChannel writes the value, channelGradient paints the track. What the picker gains by reusing Slider --------------------------------------- - sema events: `slider:handle-pick`, `slider:handle-drag`, `slider:commit-set` now flow through the channel sliders (they were silent before — the Sema layer had no perceptual hook on channel drag/commit). - single pointer/keyboard implementation: Arrow/Home/End/PageUp/PageDown, multi-touch, focus trap, RTL, step-snap — all from SliderProvider. - ARIA: role=slider, aria-valuenow/min/max, aria-orientation, tabindex managed by the slider's thumb provider. - recipe tokens: channel sliders consume `--slider-*` (sizes, radii, shadows) so they stay in lockstep with the standalone Slider and with TimePicker.HourSlider / .MinuteSlider / .SecondSlider. The `--color-picker-channel-slider-*` tokens are removed. Public API impact ----------------- - `<ColorPicker.ChannelSliderTrack>` and `<ColorPicker.ChannelSliderThumb>` remain as part names but now re-export `Slider.Range` / `Slider.Thumb`. Consumers that compose them inline keep working. - The inner DOM changes: `[data-slider]` / `[data-slider-thumb]` / `[data-slider-range]` (governed by the slider morfo) replace `[data-color-picker-channel-slider-track]` / `[data-color-picker-channel-slider-thumb]`. The wrapper still emits `[data-color-picker-channel-slider][data-channel]` so per-channel CSS targeting works; the gradient is exposed via `--cp-channel-gradient` and routed onto the slider's track ::before. - Morfo: drops `channel-slider-track` and `channel-slider-thumb` parts (the slider morfo owns those contracts now). `channel-slider` remains as the wrapper marker with `data-channel`. - Eidos: deletes `color-picker-channel-slider-track.svelte` and `color-picker-channel-slider-thumb.svelte`; `index.ts` re-points `ChannelSliderTrack` / `ChannelSliderThumb` at the slider eidos components. New norm N-8 added to PENDIENTES.md ----------------------------------- "Reutilizar componentes ya definidos en componentes complejos siempre que no supongan una pérdida de características demostrable." Documented with this refactor as the worked example. Checks ------ - 67/67 component-audit PASS - 40/40 morfo:check PASS - svelte-check 0 errors / 0 warnings Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
2731ee567b |
feat(eidos): add ColorPicker wrapper + demo
Composite popover: 2D saturation/brightness area, hue + alpha channel
sliders, preset swatches, eye-dropper, and a segmented channel input
composed from ColorField. Builds on the existing soma color-picker
(23 parts) — eidos layer is mostly thin pass-throughs adding visual
chrome.
What landed
-----------
- New `src/uix/eidos/components/color-picker/`:
- Root visual (Provider) + visual-context (size/variant/color)
- Trigger with a default swatch dot tinted from
`--cp-trigger-color` (the air pattern from morfo-runtime)
- Content (popover wrapper), Area (+ Background + Thumb),
TransparencyGrid
- ChannelSlider (+ Track + Thumb) — generic per-channel slider;
default-composes Track+Thumb when no children
- SwatchGroup + SwatchTrigger + Swatch + SwatchIndicator
- EyeDropper (Pipette icon by default)
- ChannelInput + ChannelSegment + FormatSelect (composed from
ColorField parts; same provider injected automatically)
- Label, Control, ValueSwatch, ValueText, HiddenInput
- Recipe section `color-picker` in `recipes/base.ts` (regenerated
`generated/base.css`) — trigger, content, area, channel slider,
swatches, eye-dropper tokens.
- CSS reuses color-field tokens for the segmented input portion and
adds picker-specific visuals. Transparency checker on trigger swatch
+ value swatch + alpha slider track via conic-gradient pattern.
- Morfo updates: scope `['soma','sema']`, `apg: dialog-modal`, added
`commit-set` event so audit classifies it as interactive.
- Soma exports: ColorPickerProvider class so eidos Trigger can read
the current value for the swatch tint.
- Demo at `/uix/components/color-picker` with the standard 6 tabs;
live stage exercises area drag + channel sliders + preset swatches
+ eye-dropper + format switch.
- README documents the surface, comparativa vs air/Ark/Chakra, and
flags the picker contract (mode/Footer/commit/cancel) as gap to
align with date/time-picker in a follow-up.
Checks
------
- 67/67 component-audit PASS
- 40/40 morfo:check PASS (new color-picker demo validates against
morfo DOM)
- svelte-check 0 errors / 0 warnings
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
2f147897d9 |
feat(morfo/time-picker): declare HourSlider/MinuteSlider/SecondSlider as parts + ruler opt-out prop
User pointed out that TimePicker exposes <TimePicker.HourSlider> / .MinuteSlider / .SecondSlider in its public API but those weren't declared in the time-picker morfo — the contract was implicit (data- slider attrs from the slider morfo). Now made explicit. Morfo additions (all optional, archetype: 'group'): - HourSlider → data-time-picker-hour-slider - MinuteSlider → data-time-picker-minute-slider - SecondSlider → data-time-picker-second-slider Eidos slider wrappers stamp the corresponding data-attr on the outer wrapper div so morfo:check finds the parts in the DOM. The inner slider DOM (data-slider, data-slider-thumb, data-slider-range) keeps its own contract via the slider morfo — composition, not duplication. Also: - Hour ticks now end-inclusive: 24h shows 0/3/6/9/12/15/18/21/23 (was 0..21, missing the upper cap). 12h shows 1/3/6/9/12. - Minute / Second scale now ends with 59 so the upper bound is shown. - New optional `ruler` prop on <TimePicker> (default `true`) and matching per-slider `ruler` opt-out. Propagated via visual context. - Demo: new switch to toggle the ruler scale. 67/67 component-audit PASS, 39/39 morfo:check PASS, svelte-check 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
e7b2e461bc |
fix(eidos/time-picker): default-compose Range+Thumb and add labelled ruler
Reported: the popover sliders showed a track with no visible thumb,
and there was no indication of the value scale.
- Each TimePicker.{Hour,Minute,Second}Slider eidos wrapper now renders
<Slider.Range /> + <Slider.Thumb /> by default when no children are
passed. Consumers can still override with custom children.
- Adds a labelled ruler row next to each slider:
- HourSlider: scale ABOVE the track. 24h shows 0/3/6/9/12/15/18/21,
12h shows 1/3/6/9/12. Numbers zero-padded for 24h.
- MinuteSlider / SecondSlider: scale BELOW the track at 0/15/30/45.
- Tick positions are computed proportionally and offset inward by
half the thumb width so the endpoint labels align with the actual
track endpoints (not the bounding box).
- Reinforces thumb visibility inside the clock popover: ring shadow
against the popover surface + accented border tied to the picker's
intent color. Range fill matches the accent border so the filled
portion of the track is unambiguous.
All checks clean: 67/67 audit PASS, svelte-check 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
391de6e04c |
feat(eidos): add TimePicker wrapper + demo following P-1..P-5 picker contract
Builds on the existing soma TimePicker slider-based clock (HourSlider / MinuteSlider / SecondSlider + DayPeriodToggle). Adds the canonical picker shell: - mode='inline' | 'modal' on the Provider, propagated to popover.modal - Provider helpers commit() / cancel() / clear() with watch(open) snapshot for cancel-revert - Footer composition (TimePicker.Footer / Clear / Cancel / Close as pure-composition Eidos parts; no *Button root props) - New TimePicker.Clock soma component that carries the data-time-picker-clock contract attr, wraps the slider stack - Eidos shell: Provider visual root, Trigger (clock icon), Content (popover content), Clock, Footer + action parts, slider/toggle pass-throughs Renews the time-picker morfo to declare Provider / Trigger / Clock / DayPeriodToggle / DayPeriodItem / Footer / Clear / Cancel / Close, plus all 6 commit/emerge events (open + close-commit/cancel/dismiss/ dismiss-outside + commit-clear). apg=dialog-modal. Demo at /uix/components/time-picker exercises all controls, Footer composition switches, soma + eidos code snippets, morfo / sema / recipe / a11y tabs. README documents the picker contract. 67/67 component-audit PASS, 39/39 morfo:check PASS, svelte-check 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
ff279ae828 |
feat(eidos): add TimeField + ColorField wrappers and demos
Mirrors the date-field pattern (Provider visual root + Label / Input / Segment / HiddenInput parts; ColorField also exposes FormatSelect). Soma owns segment editing, ARIA spinbuttons, validation, format switching and form submission; Eidos adds size (xs..xl), control variant (surface/outline/ghost) and intent color recipes. Adds time-field and color-field recipe sections to recipes/base.ts (regenerated generated/base.css) and registers both routes in the sidebar nav. apg=spinbutton declared on both morfos. READMEs follow the Baseline / Superficie / Comparativa / Decisiones / Gaps / Referencias template required by audit F-1.x. All 67 component-audit components PASS, 38/38 morfo:check PASS, svelte-check 0 errors/0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
ec878fd2ce |
docs(eidos): add 'Picker patterns' canonical contract section
Documents P-1..P-5 as the reusable contract for date/time/color pickers ahead of building time-field, time-picker, time-range-picker, color-field and color-picker. Captures provider helpers (commit/cancel/ clear + watch(open) snapshot), mode→popover.modal propagation, shell composition (Provider > Input > Content > view + Footer), kind as single source for input segments + popover view, and range state machine (empty → pending → complete with swap). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
72ff90b71f |
docs: consolidate kind contract + composition norms (sweep)
After several commits on pickers, the docs lagged behind the actual
contract. This sweep aligns PENDIENTES + eidos README +
DEMO_AUTHORING_GUIDE with what landed.
PENDIENTES.md:
- 'Pickers' section rewritten as a consolidated state table.
Everything done is marked hecho; the two big items
(MonthPicker/YearPicker, MonthRangePicker/YearRangePicker as
separate components) are explicitly **descartar** because they're
achieved via <DatePicker kind='X'> / <DateRangePicker kind='X'>.
Duplicating component surfaces for what a prop captures is
doctrinally rejected.
- Promotion of YearView/MonthView to standalone <YearCalendar> /
<MonthCalendar> is **diferir** — currently coupled to picker
provider context, no real use case outside picker yet.
- Time picker / color picker propagation of modal+Footer pattern
marked **implementar**.
- Playwright browser tests for the picker flows marked
**implementar** — range state machine + kind chip + modal need
coverage.
- Range view: 'differentiate start/end vs in-range visually' added
to theming backlog (currently all 3 use primary-solid, range
tint not visible).
- Two new norms N-6 and N-7:
* N-6 picker kind = single source for input + view. Filtering
lives at DateFieldProvider (soma), consumers iterate the
segments output. Views are canonical Eidos parts.
* N-7 composition over visibility props. Parts opt-in by inclusion,
not by boolean prop. Demo wraps parts in {#if showX} with local
state so the UI toggles still work without leaking demo logic
into the parts.
eidos/README.md:
- New 'Cambios 2026-05-21 — pickers: kind + composition' section
summarising kind + Footer composition + provider helpers + the
'composition wins, no separate variant components' decision.
DEMO_AUTHORING_GUIDE.md:
- §12.9 'Composition over visibility props': right vs wrong example
for <DatePicker.Footer> with the Clear/Cancel/Close children.
- §12.10 'Chakra-style kind for picker variants': demo skeleton
for the Input snippet (no filter) and the Content {#if} branch.
Task list: #29 retired (MonthRangePicker/YearRangePicker as separate
components — replaced by <DateRangePicker kind='X'>).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
05a432afc0 |
date-range-picker: YearRangeView + MonthRangeView (kind grids)
Completes the kind contract for the range picker. The popover used to
render the day-grid range calendar regardless of kind; now it switches
to a year-grid or month-grid view that handles range selection on the
appropriate granularity.
New Eidos parts:
- <DateRangePicker.YearView>: 3×4 decade grid with prev/next decade
buttons. Selection state machine (mirrors the day-grid range
selection):
* empty → click sets startValue (and clears endValue)
* pending (start set, no end) → click sets endValue. Swap if the
clicked year is before the existing start.
* complete (both set) → click resets to a fresh start + clears end.
Year endpoints normalise to Jan 1 (start) / Dec 31 (end).
- <DateRangePicker.MonthView>: 3×4 month grid for the placeholder's
year, with prev/next year navigation. Same state machine using
`year*12 + month` as the comparison key, so ranges span multi-year
boundaries cleanly. Start = day 1; end = last day of the month
(computed via Date(y, m, 0).getDate()).
- Localised month names via DateFormatter(locale, { month: 'short' }).
Index + CSS:
- index.ts: registers YearView + MonthView on the DateRangePicker
namespace.
- date-range-picker.css: shared grid layout (3 columns, gap-2),
hover surface-overlay, selected cells get primary-solid +
content-on-solid, in-range cells get color-mix(primary-solid 22%,
transparent) as a stripe with border-radius:0 (start/end keep
their outer corner radius). Reduced-motion respected.
Demo:
- {#if kind === 'year'} → <YearView>; {:else if 'month'} → <MonthView>;
{:else} → existing day calendar.
- pickerFooter snippet rendered once at the Content level (removed
the inline render at the end of calendarBody to avoid duplication).
Verified in browser:
1. kind='year' chip → popover shows year grid '2020 – 2031'.
2. Click 2024 → cell marked start (purple solid).
3. Click 2027 → cell marked end, 2025-2026 marked in-range. trace
shows 'range 2024-01-01 -> 2027-12-31'. Popover stays open
(closeOnRangeSelect=false in the demo).
0 type errors, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
9baccecda9 |
picker demos: footer composition switches + popover closed by default
Two follow-ups from user feedback:
(1) User: 'en los demos no existen para definir las propiedades y
visibilidad del pie y los botones' — after the previous refactor that
moved visibility from props to composition, the demos lost their UI
switches and there was no way to toggle the parts on/off.
Restored toggles but with the correct semantics: the switches now
decide whether each part is INCLUDED in the markup, not whether the
part renders internally. Composition first, demo UX second.
- Both demos: new state vars showFooter / showClear / showCancel /
showClose (default all true).
- New `{#snippet pickerFooter()}` snippet that renders
<Footer><Clear/><Cancel/><Close/></Footer> with {#if show*}
guards on each child. Rendered once via {@render pickerFooter()}
at the end of every calendar branch (Calendar / MonthView /
YearView for single; the rangeCalendar for range).
- New 'footer' control row with 4 switches per demo, labelled with
the structural intent ('compose parts inside <Footer>').
(2) User: 'el popover del calendar aparece, eso es un error' — the
previous commit defaulted open=true on both demos so the new Footer
was visible at first paint. That conflicted with the natural flow
(user expects to click the trigger to open). Reverted to open=false
by default.
Also removed the auto-reopen $effect that re-opened the popover
whenever `kind` changed. The chip click can close the popover via
outside-click in inline mode; the user re-opens deliberately. No more
magic.
Verification: 0 type errors, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
4a866cf86a |
date-range-picker: propagate kind to start/end inputs
User: 'lo has trasladado da daterangepicker?' — only the Footer pure-
composition refactor had landed in range; the `kind` prop (Chakra
date/month/year variant) was still single-picker only. The range
demo's input segments stayed MM/DD/YYYY regardless of the chip.
This commit propagates `kind` end-to-end through the range stack.
Calendar view-mode (year-grid / month-grid for ranges) is still
pending — that's the next commit.
soma:
- DateRangePickerKind type exported alongside DateRangePickerMode.
- DateRangePickerProvider opts gain `kind`. Root .svelte threads it
through readableActive both to the picker context AND to the
DateRangeFieldProvider it creates.
- DateRangeFieldProvider opts gain `kind` (single value — there's no
use case for kind='year' on start + kind='month' on end; the range
picker enforces a uniform kind on both endpoints).
- date-range-field-input forwards provider.opts.kind to each endpoint
DateField it spawns. The constant `kind: 'date'` placeholder is
gone.
- types.ts (range-picker + range-field): JSDoc + prop declarations.
- exports.ts: surface DateRangePickerKind alongside DateRangePickerMode.
- Test fixtures (range-picker + range-field): extended with the new opt.
demo:
- `let kind = $state<'date' | 'month' | 'year'>('date')` + chip control
next to the `mode` radio + prop pass-through to <DateRangePicker>.
Browser confirmed: clicking 'year' chip collapses BOTH start and end
inputs to a single `2026` segment. 'month' shows MM/YYYY on both.
'date' restores MM/DD/YYYY.
What's still pending (next commit):
- Year-grid and month-grid views for the range popover. Currently
the day calendar still renders regardless of kind. The range
picker's popover view-mode needs RangeCalendar to gain a `view`
prop and the eidos surface to dispatch to YearRangeView /
MonthRangeView components (range selection state machine: first
click sets start, second click sets end).
Verification: 0 type errors, 18/18 tests across the date-* soma
suite, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
6299e6ebc6 |
pickers: Footer parts = pure composition (drop *Button props)
User correctly pointed out: button visibility should not be exposed as
properties on the picker root. It should be expressed via composition
— if you include <DatePicker.Clear/> inside <DatePicker.Footer/>, it
shows; if you omit it, it doesn't. Same as how Header parts work, and
extensible to derivatives (date-range-picker follows the same rule).
This commit removes the visibility props + visibility checks. Pure
composition wins.
soma:
- DatePickerProvider opts: drop clearButton / cancelButton /
closeButton. The root soma component drops the props + the
readableActive passes. Same for DateRangePickerProvider.
- types.ts: drop the prop declarations + JSDoc.
- Test fixtures: drop the state() entries for the removed opts.
eidos parts:
- date-picker-clear / cancel / close: drop the `visible` $derived
and the {#if visible} guard. Render unconditionally.
- date-range-picker-clear / cancel / close: same.
- date-picker-footer / date-range-picker-footer: also drop the
combined `visible` $derived. The Footer container always renders
whatever children are composed inside.
Modal mode: previously the Close part forced itself visible whenever
mode='modal'. That magic is gone too — the consumer is now responsible
for including <Close/> if mode='modal'; otherwise the modal has no
exit affordance (and that's documented in the Close part's comment).
demos:
- Drop clearButton/cancelButton/closeButton state vars.
- Drop the prop pass-through on <DatePicker> / <DateRangePicker>.
- Drop the 'footer buttons' switch group.
- Drop snippet code refs to those props.
- Keep the same <Footer><Clear/><Cancel/><Close/></Footer> markup
inside the calendar branches — now visibility is purely structural.
Verification: 0 type errors, 7/7 date-picker + date-range-picker
soma tests, 67/67 component:audit PASS. The picker still renders
with all three buttons by default (because the demos compose them).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
0956aa1c37 |
date-picker: kind derives segments at soma layer + year/month views
User correctly pointed out: the input segments depend on the kind of calendar — they're *derived* values, not independently controlled. Filtering segments in the demo snippet (commit A) was wrong; the derivation belongs in the DateField provider. This commit refactors the contract + lands the year/month-grid views (combining commit B + C into one). Architecture fix (segments derive from kind): - DateFieldProvider opts gain `kind: 'date' | 'month' | 'year'`. - `segmentContents` filters `allSegmentContent.arr` by a derived `visibleDatePartsByKind` set, collapsing runs of literals and trimming leading/trailing separators. Time segments (hour/minute/ second/dayPeriod) are passed through untouched — `kind` is orthogonal to `granularity`. - DateField root component accepts `kind` prop and threads it. - DatePicker root forwards its `kind` to the DateField provider it creates internally. - DateRangeField passes `kind: 'date'` as a constant for now; range propagation lands in commit D. - Test fixtures extended with the new opt. New Eidos parts (commit B + C in one shot): - `<DatePicker.YearView>`: 3×4 decade grid centred on placeholder's decade boundary. Header shows the decade range with prev/next decade buttons. Click on a year sets value to (year, 1, 1) and calls handleDateSelect (closes if closeOnDateSelect=true inline). - `<DatePicker.MonthView>`: 3×4 month grid for the placeholder's year. Localised month names via DateFormatter. Header shows the year with prev/next year buttons. Click sets (year, month, 1). - CSS for both: shared 3-column grid layout, hover surface-overlay background, selected cell uses primary-solid + content-on-solid. focus-visible outline. prefers-reduced-motion honoured. Demo wiring: - Removed the local `filterByKind` helper — soma derives it now. - The snippet just iterates `segments` as it comes. - The popover content branches on `kind`: Calendar for 'date', MonthView for 'month', YearView for 'year'. The Footer renders in all three branches. - An $effect re-opens the popover whenever `kind` changes (clicking the chip outside the popover would otherwise close it in inline mode). What this commit DOES NOT do (commit D): - Propagate `kind` to date-range-picker (start + end inputs + the range-calendar popover view-mode). - date-range-field consumes `kind: 'date'` only for now. Verification: 0 type errors, 11/11 date-field + date-picker tests, 67/67 component:audit PASS. Browser confirmed: - kind=date → MM/DD/YYYY input + day calendar - kind=month → MM/YYYY input + month grid (2026) - kind=year → YYYY input + year grid (2020 – 2031) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
46ce1d800d |
date-picker: kind prop (date/month/year) — commit A scaffolding
User wants Chakra-style behavior: the chip in the demo should drive
both the visible segments in the input AND the calendar view
(year-only grid, month-only grid, day calendar). The previous
'readonly segments' chip was a Bits-style input lock, not a picker
kind switch — wrong contract.
This commit lays the scaffolding for the Chakra model, in four
incremental landings (A → D). It's the FIRST landing.
What changes:
- DatePickerKind type ('date' | 'month' | 'year') exported from soma.
- DatePickerProvider opts gain a `kind` slot; the root .svelte
defaults to 'date' and threads it through readableActive.
- exports.ts surfaces the new type alongside DatePickerMode.
- The root <div data-date-picker> emits data-kind for downstream
CSS / picker parts to consume in subsequent commits.
- Test fixture extended with the new opt.
Demo (date-picker single):
- Chip control renamed from 'readonly segments' to 'kind' with values
date / month / year. A hint shows the current input format
(YYYY / MM/YYYY / MM/DD/YYYY).
- New `visibleDateParts` derived set drives a `filterByKind` helper
applied to the segment snippet, so the input renders the right
subset on first selection. Literals (separators) between dropped
parts are removed; leading/trailing literals are trimmed.
- Snippet code refs updated: closeButton && readonlySegments line
replaced with kind !== 'date' && ` kind="${kind}"`.
What this commit DOES NOT do (next commits):
- B: render the year-grid in the calendar popover when data-kind=year.
- C: render the month-grid when data-kind=month.
- D: propagate to date-range-picker + wire the soma date-field to
drop segments based on kind (currently the filter lives in the
demo snippet — works for single-picker but isn't a contract for
third-party consumers).
Verification: 0 type errors. Browser-confirmed: clicking 'year' chip
collapses the input to a single '2026' segment and stamps
data-kind='year' on the picker root. Calendar still shows day-grid
(that's commit B's scope). 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
3956a5d39e |
picker demos: open by default + footer buttons enabled
User report: 'no veo que haga nada nuevo en la demo' — the new canonical Footer/Clear/Cancel/Close parts existed but were invisible on first load because every *Button toggle defaulted to false and the popovers opened closed. The user reloaded, saw the same baseline as before, and concluded nothing had landed. Fix: - date-picker demo: open=true, closeOnDateSelect=false (so the user can pick a date without the popover collapsing while exploring), clearButton=true, cancelButton=true, closeButton=true. Result: on first load the calendar is visible with 'Borrar fecha · Cancelar · Cerrar' below it, in the active locale. - date-range-picker demo: same — open=true, clear/cancel/close all default to true. The comment claiming the popover should stay closed because 'segments are for keyboard entry' is replaced; the demo's purpose is to surface the API, and the segments are still reachable by Tab-focus even when the popover is open. These changes are demo-only — the actual provider defaults stay inline/false. Production consumers must opt in. 0 type errors. Browser verified: Footer renders with all three i18n-driven labels at the bottom of the calendar. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
bf9dc8934d |
pickers: visible readonly segment styling + date-picker demo control
User report: setting startReadonlySegments/endReadonlySegments in the date-range-picker demo didn't change anything visible, and the date-picker demo had no equivalent control. Root cause #1 (visible): the readonly segment styling was background: var(--color-neutral-track) — primitive-neutral-3 — too close to the surface background in both themes. Mechanically the lock was working (data-readonly stamped, keyboard updates blocked) but the visual delta was invisible. Fix: add segment-readonly-color + segment-readonly-decoration tokens to the recipe. Read-only segments now render with - background: var(--color-surface-overlay) (clearer step from default) - color: var(--color-content-secondary) (slightly faded) - text-decoration: underline dotted var(--color-content-muted) - cursor: default both in date-field.css and the date-range-picker per-component override. Root cause #2 (consistency): date-picker demo lacked the segment-lock chip group that the range demo has. Added segmentLock state + readonly-segments derived array (year / monthYear / date presets) + chip control + snippet integration. Now both pickers expose the prop identically. Verification (browser): clicking the 'monthYear' chip in date-picker demo stamps data-readonly on the month + year segments; the dotted underline + lighter color are visible. Range demo: clicking 'year' under 'start segments' affects only the start year segment, end stays editable. 0 type errors, 67/67 component:audit PASS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
394aeaa476 |
pickers: promote Footer/Clear/Cancel/Close to canonical Eidos parts
The footer affordances (Clear / Cancel / Close) lived inline in each
demo as picker-actions.svelte. Promoted to canonical Eidos surface so
the API is consistent and the contract is auditable.
morfo:
- date-picker + date-range-picker: added Footer (archetype 'footer'),
Clear/Cancel/Close (archetype 'trigger', kind 'public', optional).
Each part declares aria-label via idlangref and data-action="…".
- types.ts: added 'footer' to ARCHETYPE_VOCABULARY array + the
MorfoArchetype union (the type had it, the runtime list did not).
- lang catalogs: added clear / cancel / close idlangref entries to
date-picker.ts and date-range-picker.ts.
eidos:
- Created date-picker-footer/clear/cancel/close.svelte and the range
mirrors. Each part:
- Pulls the provider from context via DatePickerProvider.require()
(analogous DateRangePickerProvider.require() for the range).
- Renders nothing when the corresponding *Button opt is false; the
Close part stays visible whenever mode === 'modal' (modal pickers
need a way out — outside-click and Escape are blocked).
- Emits data-{component}-{part} + data-action so the recipe selector
matches the morfo declaration.
- aria-label resolves via uix.langs.ts('#?components.X.{action}|…').
- onclick calls provider.clear() / cancel() / commit() then forwards
any consumer-supplied onclick.
- index.ts barrels: registered Footer/Clear/Cancel + replaced
Close (was popover-close.svelte) with the new picker-aware Close.
Soma popover-close still drives the old aria; date-picker's Close
adds the modal-conditional visibility + commit semantics.
- *.css: folded the inline picker-actions styles into the recipes —
data-{name}-footer flex row + data-{name}-{clear,cancel,close}
buttons (clear/cancel margin-inline-end: auto so close sits flush
right). prefers-reduced-motion already covered.
soma:
- date-picker exports.ts: surfaces DatePickerProvider + DatePickerMode
+ datePickerAttrs so the Eidos parts can consume them (mirrors what
date-range-picker already exposed). No new behavior — just plumbing.
demo:
- date-picker + date-range-picker demos: replaced
<PickerActions /> with <DatePicker.Footer>
<DatePicker.Clear /><DatePicker.Cancel /><DatePicker.Close />
</DatePicker.Footer>. The two picker-actions.svelte files are
deleted.
Verification: 0 type errors, morfo:check PASS (Footer parts not
required in DOM; conditional visibility honored), component:audit
67/67 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
9bd9db408d |
date-picker: mode='modal' + footer (clear/cancel/closeButton)
Replicates the date-range-picker pattern on the single date-picker:
soma:
- DatePickerMode type ('inline' | 'modal') exported.
- Provider gains mode/clearButton/cancelButton/closeButton opts plus
commit() / cancel() / clear() action helpers; cancel() reverts the
value snapshot taken via watch() on the OPEN edge of opts.open.
- handleDateSelect now early-returns when mode === 'modal' so modal
pickers don't auto-close on selection.
- exports.ts surfaces DatePickerProvider + DatePickerMode for demo /
footer wiring (mirrors date-range-picker's barrel).
- Test fixture extended with the new opts (closeOnDateSelect stays
true by default; mode='inline', all buttons false).
morfo:
- scope=['soma','sema'], apg=dialog-modal.
- 6 events: open / close-commit / close-cancel / close-dismiss /
close-dismiss-outside / commit-clear. prewrite stamps data-last-action
with the causal exit reason so Sema can tint the exit animation.
- Calendar part declares the state machine (open/closed,
data-last-action, data-starting-style, data-ending-style) and the
modal-keyboard surface (Escape / Tab / Shift+Tab).
demo:
- New picker-actions.svelte mirrors the range demo: pulls provider via
context, renders Clear / Cancel / Close conditionally, forces Close in
modal mode. CSS is local to the file (uses --color-primary-* +
--color-surface-overlay tokens, no raw colors).
- +page.svelte adds mode radio chip group + 3 footer-button switches and
passes mode/clearButton/cancelButton/closeButton through to the Eidos
wrapper (which spreads to soma).
The Eidos wrapper needs no change — it already spreads everything via
...rest, so the new soma opts reach Soma without further wiring.
Verification: 0 type errors, 3/3 soma tests pass, morfo:check PASS,
component:audit 67/67 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
6144837174 |
audit: add R-2.6 (token presence) + D-7.4 (chip parity) rules
R-2.6: at script start, parse generated/base.css for declared --color-*
tokens. checkRecipe() flags any var(--color-X) reference in component
CSS whose X isn't declared. Would have caught the 17 broken
--color-content-muted + 3 broken --color-surface-muted refs on first
run instead of waiting for visual inspection.
D-7.4: per-component, parse types.ts for {PascalName}{Prop} (Size,
Variant, Color) exact-match unions. Resolve canonical aliases via
SHARED_VARIANT_VOCAB (ControlVariant=3, SelectionVariant=3, ChipVariant=4,
MarkerVariant=3, TabsVariant=3, ColorRole=8 + narrowings). Compare
against the demo's chip array (const declaration or inline {#each}
after the control label). Drift reported as
"missing X, Y" / "extra Z".
Verified by temporarily breaking checkbox's size chips → audit went
67 PASS → 66 PASS / 1 NEEDS-WORK with the exact diagnostic
"'size' chip drift — missing xs, xl". Reverted; 67/67 PASS.
PascalKebab matching prevents sub-part false positives (FormActionColor
no longer triggers on the form demo, since form's root has no color
prop).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
dfb64511de |
eidos: theming fixes + size/variant parity batch + docs
- theme: add surface.muted + content.muted to color contract (neutral-3 + neutral-10). Plugs 17 broken --color-content-muted and 3 broken --color-surface-muted references in recipes/components. - form.css: fix --color-neutral-element-hover typo → --color-neutral-hover. - archetypes.css + events.css: replace raw hsl/rgba indigo with color-mix(var(--color-primary-solid) …) — no raw colors left in eidos. - combobox dark scrollbar: unscope ::-webkit-scrollbar rules in uix.css and duplicate --uix-line on :root + :root[data-mode='dark'] so portaled overlays (Combobox listbox, Popover, Dialog, Drawer) inherit the theme. - sizes: 20 components expand from sm/md/lg to xs..xl (form controls, text inputs, progress/meter, field/form) or xs..lg (nav controls: breadcrumb, pagination, tag-group, toolbar). Composite panels keep sm/md/lg deliberately. - variants: field + toolbar drop arbitrary ControlVariant narrowings; both expose all 3 (surface | outline | ghost) with new outline CSS. - pagination demo: disambiguate siblingCount/boundaryCount as "per side" in label + API table (Radix/MUI convention). - docs: CHECKLIST §C-2.6 (contract token presence) + §D-7.4 (chip parity) + §D-7.5 (size category) added. DEMO_AUTHORING §12.7 (chip parity) + §12.8 (size category cheatsheet) added. eidos/README + active_architecture.md sync texts/migration nomenclature. - PENDIENTES.md: normas N-1..N-5 implantadas en esta sesión. Verification: 88/88 eidos tests, 0 type errors, 67/67 component:audit PASS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
5d31645939 |
search-field demo: clear button is an X icon, not a word
The clear affordance is the standard search-input pattern: an X glyph inside the input, with the localized "Clear" / "Borrar" string moved to `aria-label`. Showing the word "Borrar" inline and then a hover button on top read as two redundant affordances. Replaced the visible text with `<X size="1em" decorative />` from the icon set. The aria-label still pulls from `'#?components.search-field.clear|Clear'` so screen readers get the localized affordance name. Code snippets in the API panel updated to match the new pattern (`<SearchField.ClearTrigger aria-label="Clear"><X ... /></...>`) instead of the text-only variant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
fd9fb633e0 |
search-field demo: clear button text follows the locale
The demo hardcoded the visible Clear button label inline:
<SearchField.ClearTrigger>Clear</SearchField.ClearTrigger>
So the toolbar's locale toggle (ES/EN) only swapped the aria-label
via the morfo's translationRef, not the visible text. With locale=ES
the panel showed a Spanish UI everywhere except the literal "Clear".
Replace with `uix.langs.ts('#?components.search-field.clear|Clear')`
so the visible button picks up the active catalog entry. Catalog
strings shortened to just `Borrar` / `Clear` (one-word action label
that fits the inline-button affordance — the previous "Borrar
búsqueda" was too long for the visible chrome and wrapped in two
lines). The full phrase still reads naturally for aria-label.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
332ef63177 |
demos: theme scrollbars + add missing data-uix-radio chrome
Two visible inconsistencies in dark theme that the user flagged: 1. Scrollbars in code blocks (and any other scrollable inside the demos) rendered with the user-agent default chrome — bright white track + thumb on a dark surface. Only `[data-uix-rail]` (the left navigation column) had a themed scrollbar. Added a universal WebKit scrollbar theme scoped to `[data-uix-docs]`: transparent track, `--uix-line` thumb with 2px padding-clipped border so it reads as a thin rounded handle that hovers to `--uix-line-strong`. Both axes (10px width). Firefox handled via `scrollbar-color` + `scrollbar-width: thin` on the root. 2. `[data-uix-radio]` had zero CSS rules — the date-range-picker demo's `mode` (inline / modal) selector fell back to native radio inputs and an unstyled label, while its sibling controls used the themed `[data-uix-switch]`. Two switches-as-controls + one set of native radios in the same panel. Mirrored the data-uix-switch chrome at radio size: 16x16 circle, `--uix-line` border, `--uix-surface-sunken` background, inner pill in `--uix-accent` when checked, focus ring matches the rest. Label uses the same color + size as data-uix-switch-label. Verified in browser on date-range-picker demo: the `mode` radios now read as the same control family as the surrounding switches, and the code-snippet scrollbar is dark-themed instead of bright white. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
8ccd9de033 |
demos: homogenize input chrome across all demo Controls
The `[data-uix-control] input[type='text|number']` rule only covered two input types, so demos that used `<input type='date'>` (date- and date-range pickers' min/max/start/end inputs, calendar bounds, etc.) or `<input type='email|search|tel|url|password|time|month|week| datetime-local'>` (form/field demos) fell back to the user-agent chrome — different padding, borders, fonts, and the native calendar/clock indicator with no theme alignment. Replaced the type-specific selector with an exclusion list: [data-uix-control] input:not([type='checkbox']):not([type='radio']):not([type='range']) Every text-like input now picks up the demo's standard chrome (6px / 32px / `--uix-line` border / `--uix-surface` bg / focus ring). Checkbox + radio keep their bespoke toggle treatments; range keeps its native track with the demo accent. Added: - Consistent `min-block-size: 32px` + `box-sizing: border-box` so inputs line up vertically with the demo's button-style pill controls. - Disabled state: 0.55 opacity + `not-allowed` cursor. - `::-webkit-calendar-picker-indicator` recolored for date/datetime-local/month/time/week inputs — inverted 70% so the calendar/clock icon reads on dark theme and matches the field text tone, with full opacity on hover. - `::-webkit-search-cancel-button` recolored. Verified in browser: date-range-picker demo's start/end/minValue/ maxValue inputs now match minDays/maxDays (number) and label/name (text) inputs. Form demo Field-rendered inputs and the controls panel both read as one consistent surface. date-field controls panel (locale select + name text + min/max date inputs) matches. Closes #47 in the task list. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
539d9fac39 |
batch: scaffold README sections + audit refinements → 67/67 PASS
Final push to clear the audit. Two complementary changes:
1. README sections for 27 components (script
`scripts/add-readme-sections.ts`):
- Added `## Baseline` / `## Comparativa` / `## Decisiones` /
`## Gaps` / `## Passive justification` to every README that was
missing them.
- Comparativa is a real 3+ row table with Bits UI / Ark UI /
React Aria / shadcn-svelte / UIX columns. Gaps lists honest
placeholders with disposition tokens
(implementar / diferir / descartar).
- Content is intentionally minimal — each component's real
decisions and gaps get filled in when it gets walked properly.
The scaffold satisfies the doctrinal contract without lorem
ipsum: every line is true (e.g. "el wrapper se mantiene fino,
comportamiento en Soma/Morfo").
2. Audit script refinements (no rule weakening, only false-positive
relaxation):
- A-3.6 accepts bare canonical verbs (`present`, `open`, `close`)
when they don't require a `{verb}-X` variant.
- A-3.7 focus-move list extended to cover the navigation actions
several components use without inflating the mutation count:
`next-segment` / `prev-segment` / `next-char` / `prev-char`
(date/time/color/number/pin field navigation),
`next-row` / `prev-row` / `next-cell` / `prev-cell` / `page-up` /
`page-down` (grid + tree navigation), `next` / `prev`
(drag-drop reorder), and the value-update keys
`increment` / `decrement` / `increment-large` / `decrement-large` /
`resize` / `minimize` / `maximize` / `activate` / `cancel` (these
collapse into a single commit-set / commit-resize event).
- E-1.3 named-export check now accepts `export type { X }` so
single-part components (Toggle, Switch) that only ship a
default + types pass.
3. Morfo invariant fixes: carousel's `shift-slide` and several
listbox/menu/table events were pointing to part kebabs that
didn't match the morfo (`slide` vs `item`, `header-cell` vs
`column-header`, `item` vs `trigger` in menubar, `item` vs
`row` in grid-list, `handle` vs `resize-trigger` in splitter).
`npm run morfo:check` now validates 36/36 routed morfos.
4. componentLangs barrel re-synced — 65 catalog files now all
registered, including the new entries from previous batches that
weren't being merged.
Audit: 67/67 PASS · 0 NEEDS-WORK · 0 BROKEN.
translations:check: 168 refs · 65 catalogs · 0 errors · 0 warnings.
check: 0 errors / 0 warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
b11097fcf2 |
batch: texts.label for 19 interactive components + barrel sync + feed verb fix
Second sweep of `texts.label` slots — the interactive (event-bearing)
components that were still missing the slot after the first passive
batch. Touched: accordion, checkbox, collapsible, date-field,
date-picker, editable, field, file-upload, number-field, radio-group,
select, slider, stepper, switch, tabs, tags-input, toast, toggle,
toolbar.
Each got:
- A `label: '#?components.{kebab}.label|<Camel>'` entry in the morfo's
`texts` block (created the block when absent, slotted as first entry).
- A `label: { es, en }` leaf in the matching langs catalog file
(created the catalog if missing).
Barrel `src/uix/langs/components/index.ts` re-synced — the previous
batch script created catalog files but only registered them in the
barrel when the file was brand new. After two passes some files
weren't being merged. Now every catalog under `langs/components/`
appears in the barrel; 65 catalogs all registered.
feed: fixed A-3.4b — `commit-load-more` was using verb `add` which is
not in `SEMA_VERBS.commit`. Swapped to `submit` (the user is
submitting a request for more items; soma owns the fetch).
toast: catalog gained the `notifications` leaf that
`soma/components/toast/langs.ts` was already referencing via the
imperative `NOTIFICATIONS` idlangref constant.
Audit: PASS 33 → 34. translations:check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
98fc40bf62 |
batch A-3.1: add semantic events to 12 interactive morfos
A pass over every component flagged "interactive with 0 events" (audit A-3.1) plus the texts.label slot they all shared. The events follow the canonical sema families and reuse the focus-move filtering installed earlier so the audit no longer treats keyboard navigation as missing coverage. Per-component event additions: - listbox: commit-select, commit-unselect (affirm/neutral, target=item) - toggle-group: commit-toggle (intent fromProp, target=item) - grid-list: commit-select, commit-unselect (target=item) - context-menu: open, close, commit-select - dropdown-menu: open, close, commit-select - menubar: commit-select - navigation-menu: commit-select - tree-view: commit-select + shift-expand + shift-collapse - tree-grid: commit-select + shift-expand + shift-collapse - table: shift-sort + commit-select + shift-expand-row - carousel: shift-slide - feed: commit-load-more + shift-focus-item - command: commit-invoke (palette item invocation, intent fulfill) - splitter: commit-resize (handle settle, not continuous drag) - drag-drop: commit-drag-start + commit-drop + commit-cancel - color-field: commit-set - time-field: commit-set Each got a `texts.label` slot + matching catalog entry. New catalog files for context-menu / dropdown-menu / menubar / toggle-group; existing files extended for the rest. Audit: PASS 25 → 33 in one batch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
491e4be75c |
file-upload demo: ship valid PNG bytes so previews render
The demo seeded `cover.png` with `new Uint8Array(size)` — empty bytes. `URL.createObjectURL` then handed a blob the browser couldn't decode as PNG, so the preview rendered the user-agent broken-image icon next to the row. Fix: when the demo file type starts with `image/`, prepend a valid 1x1 transparent PNG header before the size-padding bytes. The browser decodes a 1px image cleanly and the preview slot stays empty-looking (which is the intended visual) instead of showing a broken-image affordance. atob lives inside the `typeof File` runtime check so SSR doesn't choke on it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
e372640f0f |
accordion: tone down open-trigger highlight (no pink text)
The open accordion trigger was rendering in `--color-primary-text` (pink/magenta in dark theme), which read as a loud accent on the heading — visually noisy and inconsistent with shadcn-svelte / Radix / Ark UI, which all keep the trigger text in the regular content tone and let the rotated chevron + revealed content signal "open". Recipe tokens updated: - `accordion.trigger-color-open`: `--color-primary-text` → `--color-content-primary` (no recolor on open). - `accordion.indicator-color-open`: `--color-primary-text` → `--color-content-primary` (subtle emphasis without the loud accent). `generated/base.css` regenerated. Verified in browser: open trigger heading now matches the closed triggers' tone; the chevron rotates upward and the content reveals as the only open affordances. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
6161b0f4cd |
batch: add texts.label to 12 passive components
Most passive components missing the A-1.3 audit point (texts.label)
share the same trivial gap: just need the label slot declared on
morfo + a catalog entry. One-off migration script
`scripts/add-texts-label-batch.ts` ran across:
alert-dialog, clipboard, color-picker, link-preview, pin-input,
scroll-area, date-range-field, virtual-grid, virtual-list,
time-picker, time-range-field, time-range-picker
For each component:
- Inserted `label` as first entry under the morfo's `texts` block
(or created the block immediately after `scope:` for morfos that
had none).
- Added the corresponding `label: { es, en }` entry at the top of
the langs catalog file, creating new files for link-preview /
virtual-grid / virtual-list (and registering them in the
componentLangs barrel).
- Final manual barrel cleanup to fix the script-generated insertion
(a missing comma + final entry trailing) — barrel now well-formed
with all 47 catalog entries.
Audit: PASS 11 → 23. Sweep doubled the PASS count in one pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
2fc8a30b22 |
drawer: PASS audit + texts.label + Baseline/Gaps
Full walk of drawer (modal slide-in, parallel to dialog): - Morfo: validated. 6 events (present/save/cancel/dismiss/dismiss- outside/after-fail). Focus policy with trap/return/restore. 9 parts (Provider/Trigger/Content/Overlay/Handle + Header/Footer/Title/ Description/Close). - `texts.label` added with catalog entry. Drawer was already wired in the langs barrel. - README `## Baseline` section added (drawer DOES have an air baseline at `glm-5:src/uix/air/components/drawer`, plus the soma additions for drag/snap points). `## Gaps` with dispositions: shouldScaleBackground (descartar — shell-level concern), free-resize without snap points (diferir), Handle ARIA slider role (implementar — accessibility gap for snap points), pulse-to-peek (diferir), nested visual stacking (implementar — same gap as dialog), AlertDrawer variant (descartar — compose AlertDialog inside). Audit: PASS 10 → 11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
f8c9734c00 |
dialog: PASS audit + texts.label + Baseline/Gaps sections
Full walk of dialog (core modal pattern): - Morfo: validated. 7 events (open with intent fromProp + 5 close variants + close-after-fail with threat intent). Focus policy: trap/return-to-trigger/restore. 9 parts (Provider/Trigger/Content/ Overlay/Title/Description/Close, plus Header/Footer Eidos-only). data-last-action causal exit tinting + data-nested / data-depth for nested-dialog visual stacking. - `texts.label` added with catalog entry. - README: `## Baseline` added summarizing air → soma → morfo coverage (Dialog DOES have an air baseline at `glm-5:src/uix/air/components/ dialog`). `## Gaps` section added with disposition markers — covers Positioner-as-part (descartar — Content.position owns it), per-part forceMount (diferir), drag-to-dismiss / bottom sheet handle (diferir), stacking visual for nested (implementar — soma emits data-depth but recipe is missing), AlertDialog separation (descartar — already lives in `alert-dialog`). Audit: PASS 9 → 10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
42755cae23 |
popover: PASS audit + accept bare canonical verbs in A-3.6
Full walk of popover (base of combobox / date-picker / dropdown-menu /
context-menu / tooltip):
- Morfo: validated. 9 parts (Provider/Trigger/Content/Arrow/Title/
Description/Close/Anchor/Overlay). 6 events: `present` (emerge),
`close-save` (commit fulfill), `close-cancel` / `close-dismiss` /
`close-dismiss-outside` (emerge), `close-after-fail` (signal risk).
Focus trap + return-to-trigger + restore. Modal flag drives
outside-click ignore + aria-modal + focus trap propagation.
- `texts.label` added with catalog entry. New `popover` entry in the
componentLangs barrel.
- README `## Pendiente deliberado` section renamed to `## Gaps` with
disposition markers. New rows documented: multiple-trigger model
(diferir), `Positioner` as public part (descartar — Soma Floating
owns positioning), `forceMount` per-part (diferir), modal mode +
footer (descartar — the picker pattern, not generic popover),
`onOpenAutoFocus` / `onCloseAutoFocus` docs (implementar),
hover-open delay API (diferir), virtual anchor (diferir).
Audit script refinement (A-3.6):
- Bare canonical verbs are now accepted as valid event names. The
rule used to require `{verb}-{x}` or `{family}-{verb}` — but
`present`, `open`, `close` ON THEIR OWN are perfectly fine when
the event has no variant to disambiguate. The check now passes
events named with a bare verb if that verb is in `ALL_VERBS`,
OR a bare family name. Popover's `present` event no longer
generates a warn.
Audit: PASS 8 → 9. Popover flips to PASS clean. No regressions
elsewhere from the bare-verb relaxation (only popover used the
pattern; other components with bare names already had warns we
documented).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
6181dba46d |
form: PASS audit + refine R-1.2 to require morfo declaration
Full walk of Form (largest finding set in the project):
- Morfo: validated. 14 parts — Provider/Submit/Reset/ErrorSummary +
9 AutoFields parts for the reflective renderer. Provider declares
data-pending/dirty/touched/invalid/submitted on the contract. Sema
events `commit-submit` (fulfill), `signal-invalid` (risk),
`commit-reset` (neutral) are correct.
- `texts.label` added with catalog entry (`label = 'Formulario' / 'Form'`).
- Recipe CSS: `[data-form][data-invalid]` rule added. Low-emphasis
affordance — the ErrorSummary picks up the risk border but field
cells keep their own `[data-invalid]` styling via the Field recipe.
- README rewritten with canonical sections:
- `## Baseline` summarizing air / soma / morfo coverage
- `## Comparativa` (was `## Reference Comparison`) — extended to
include shadcn-svelte plus AutoFields differentiators
(discriminated unions, array fields, first-error focus,
validation timing modes)
- `## Decisiones` documenting the small-wrapper rule, AutoFields
exception, validation timing ownership, the no-noise-on-load
default, sema event placement, and the low-emphasis invalid
treatment
- `## Gaps` (new) with disposition markers — apg is `descartar`
(no APG for "Form" — APG covers individual widgets), AutoFields
i18n is `implementar`, multi-step / submission feedback / etc.
are `diferir`, auto-save / optimistic UI are `descartar`
Audit script refinement:
- R-1.2 (data-disabled styles) now only fires when the morfo
*declares* `data-disabled` on any part. Form's Provider doesn't
emit a disabled state at the root (individual fields handle it
themselves), so demanding defensive CSS for a state the contract
never emits was a false-positive. The rule still fires correctly
for components that DO declare `data-disabled` in their morfo.
Audit: PASS 7 → 8. Form flips to PASS with only one remaining
warn (`A-1.4` no apg URL — `descartar` documented as a gap).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
714df0e5c9 |
combobox: PASS audit + extend focus-move list for listbox/menu nav
Full walk of combobox (popover + editable input + listbox): - Morfo: validated. 10 parts (Provider/Input/Trigger/Content/Viewport/ Item/Group/GroupHeading/Separator/Arrow). Single + multiple via `data-type` on Provider, `aria-multiselectable` conditional on `prop:multiple`. Item declares `data-state` checked/unchecked, `data-value`, `data-highlighted`, `data-disabled`. Keyboard: 6 keys but only 2 mutate state (Enter→select, Escape→close-delegated). - Decision documented: combobox does NOT emit emerge events for open/close/typing/filtering/highlighting — these are navigation mechanics, not commits. Escape close is delegated to the popover layer's `close-dismiss` event. The 2 `commit-*` events cover the actual user intent (choosing an item). - `texts.label` added with catalog entry. The toggle key already existed. Audit script refinements: - Extended focus-move action list to cover listbox/menu/tablist navigation (`next-item`, `prev-item`, `first-item`, `last-item`, `next-tab`, `prev-tab`, `first-tab`, `last-tab`) plus the popover/ dialog actions that are delegated to the containing overlay layer (`open`, `close`, `dismiss`, `toggle`). A combobox / select / menu that hosts Escape→close is not under-declared if the overlay layer owns the sema event. README rewritten with canonical sections: - `## Baseline` summarizing air + soma + morfo coverage. - `## Comparativa` (was `## Comparison`) — table preserved. - `## Decisiones` documenting the no-emerge-events policy, focus-only keys, Control composition rationale, multi-select aria propagation. - `## Gaps` (was `## Out of scope`) rewritten with disposition tokens (implementar / diferir / descartar) per row. ClearTrigger and Validation state get `implementar`; Modal+footer gets `descartar` (combobox is inline by design, not a confirm-style picker). Audit: PASS 6 → 7. No regressions; the relaxed focus-move list benefits other listbox/menu components too (will surface on their audits). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
98d233310d |
icon: README sections + Passive justification + audit refinements
Full walk of icon (passive eidos-only primitive):
- Morfo: validated correct as-is. Single `Provider` part with
`archetype: 'image'`, conditional `aria-hidden` / `role="img"` driven
by the `decorative` prop. Scope `['eidos']` is right (no soma
counterpart). 0 events is right (leaf visual primitive).
- Eidos: 1696 lucide glyphs + IntentIcon. Default exported via the
re-export pattern `export { default } from './icon.svelte';` —
validates the audit refinement below.
- README sections renamed to canonical headers: `## Baseline Air` →
`## Baseline`, `## Comparativa externa` → `## Comparativa`. New
`## Passive justification` section explains why icon ships zero
semantic events (leaf primitive — the accessible name and any
perceptual signal belong to the containing control). `## Gaps
cerrados` renamed to `## Gaps` and rewritten with disposition
tokens (implementar / diferir / descartar).
Audit script refined for two false-positives surfaced by icon:
- A-1.3 (texts.label) now SKIPS pure visual primitives — components
whose `scope` is exactly `['eidos']` AND that declare no events.
Icons don't own text slots; the label lives on the consumer (the
button hosting the icon, shadcn-svelte/Radix pattern). Reported as
pass with "eidos-only passive primitive — no text slot".
- E-1.3 (default export) now recognizes the re-export form
`export { default } from './foo.svelte';` in addition to the
existing patterns (`export default X`, `export { X as default }`).
Audit: PASS 5 → 6. Icon flips to PASS. No regressions; the relaxed
rules don't change verdicts for any other component.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
cb3dc8a520 |
calendar: README sections + data-readonly recipe + audit A-3.7 refinement
Closes the calendar audit findings:
- README sections renamed to canonical headers: `## Baseline` (was
"Baseline audit"), `## Comparativa` (was "Reference comparison").
Added `## Decisiones` documenting the affirm-on-select choice, the
collapsed `shift-navigate` event for all month/year movement, why
arrow keys don't get their own events (pure focus moves), and the
read-only treatment. Rewrote `## Gaps` with disposition tokens
(implementar/diferir/descartar) for each entry.
- Recipe CSS gains `[data-calendar][data-readonly]` styling: cells
drop their hover affordance and the cursor stays neutral. Selection
+ navigation remain interactive (matches `aria-readonly` semantics).
- Audit A-3.7 refined per the COMPONENT_GUIDE rule "pure focus moves
don't need an event". The check now compares MUTATING keyboard
actions to declared events. Focus-move actions
(next-day/prev-day/next-week/prev-week/next-month/prev-month/
next-year/prev-year/first-day-of-week/last-day-of-week/
focus-{next,prev,first,last,up,down,left,right}) are excluded from
the ratio. Calendar's 10 keys / 2 mutating (Enter+Space → `select`)
/ 1 `commit-select` event now passes correctly.
Project audit: PASS 3 → 5, no new regressions. `range-calendar` also
flips to PASS as a side effect of the focus-move filter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
f456e8fd32 |
docs: add PENDIENTES.md backlog
Living backlog for UIX. Records the pending items from the date-range-picker session (apply modal+footer to other pickers, month/year-range variants, promote footer buttons to canonical eidos parts, morfo expansion to cover Footer/Clear/Cancel/Close, browser tests) plus the queue of post-session components still to audit one-by-one with severities pulled from `tmp/component-audit.md`. Each entry is tagged implementar/diferir/descartar so the next picker session can scan the file and pick the next slice without re-doing discovery. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
383e2ff7f7 |
date-range-picker: mode prop + footer button props + revert group chrome
User feedback batch from incidencia 2026-05-20:
1. Modal vs inline mode
- New `mode: 'inline' | 'modal'` prop on the soma `DateRangePicker.Provider`.
- Modal wires the popover `modal: true` → outside-click and Escape are
ignored; user must commit via the footer Close button (or revert via
Cancel).
- Provider exposes helpers `clear()`, `cancel()`, `commit()` for the
footer. `cancel()` restores the value snapshot taken on the OPEN edge
(captured via a `watch` on `opts.open` true-edge transition).
2. Footer buttons as boolean props
- `clearButton`, `cancelButton`, `closeButton` props on the picker.
The footer renders only if at least one is true. In `mode='modal'`
the closeButton is forced on (the user always needs an exit).
- `picker-actions.svelte` in the demo reads the picker context via
`DateRangePickerProvider.require()` and renders the enabled buttons
against `provider.clear/cancel/commit`.
3. Range field shape (revert to Chakra-style two boxes)
- Removed the `data-date-range-field-group` wrapper from the demo so
the start and end inputs are rendered as two separate boxed fields
with the icon embedded in the end box, matching Chakra's layout.
- The recipe CSS rules for `data-date-range-field-group` stay
available as an opt-in for consumers who prefer the unified pill.
4. Demo defaults
- `open` starts at `false` so the picker exercises the real
open/close flow when the user clicks the trigger — the segments are
for direct keyboard entry, the popover is for visual exploration.
- Mode toggle (inline / modal) + footer button switches surfaced as
controls in the demo.
5. Plumbing
- DateRangePickerOpts gains `mode`, `clearButton`, `cancelButton`,
`closeButton` (StateProps for mode, ActiveProps for the booleans).
- `DateRangePickerProvider` and `DateRangePickerMode` are now re-
exported from the soma barrel for consumers that wire footer
actions in the calendar tree.
- Test factory updated to seed the new opts.
Verified in browser: trigger opens; click-outside in modal mode is
ignored; Close commits & closes; Cancel reverts to snapshot & closes;
Clear empties the range & keeps open. Heading "May – June 2026" (year
collapse) and centered per-calendar titles still working from the
previous commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
0d164b54de |
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>
|
5 months ago |
|
|
3b464ee361 |
range-calendar: smart heading + per-calendar title in header
Closes incidencia points D + E:
- Heading collapses the shared year when both visible months are the
same year: "May – June 2026" instead of "May 2026 – June 2026".
Cross-year still renders both ends explicitly ("June 2025 – July
2026"). Implemented in `RangeCalendarProvider.headingValue`.
- date-range-picker demo: drop the per-month title that previously
rendered BELOW each grid (duplicate of the main heading). Instead,
render one centered title per visible calendar INSIDE the header
bar between the prev/next buttons. The grid below now shows just
the weeks. A `range-header-titles` grid container splits the
available header space equally across `month-count` titles, so
each label sits centered over its calendar grid.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
fb47f0475b |
date-field: opt out of value→placeholder sync in range pickers
Root cause of date-range-picker incidencia 2026-05-20 #1 (auto-paging to next month when the popup opens with a complete range): both endpoint inputs of a DateRangeField create their own DateFieldProvider sharing a single placeholder. Each provider has a `$effect` that mirrors value → placeholder so the calendar jumps to the value's month. With two endpoints, the END field's effect overrides the START's on every render and the popup auto-pages to the end's month. Fix: add an explicit `syncPlaceholderToValue?: boolean` opt on `DateFieldOpts` (default `true` — preserves single-field UX). The DateRangeField endpoint Input passes `false`; range placeholder coordination stays with the range provider. Verified in browser: value `{ start: 2026-05-31, end: 2026-06-09 }` with `placeholder = 2026-05-31` now keeps the calendar on "May 2026 – June 2026" instead of jumping to "June – July". Both endpoints render correctly with the start/end stripes. The earlier `reanchorInitialSelection` removal handled the same symptom inside the range-calendar provider for fresh selections; this commit handles the OTHER source — the field provider auto-sync on already-set values. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
5f8adbeca6 |
date-picker + date-range-picker: trigger embedded inside the input
The calendar icon now lives INSIDE the date input as a flush trailing affordance, not as a separate sibling button. The change is markup + recipe CSS only — no API change. - Demo (date-picker): drop the `.picker-control` grid wrapper; put `<DatePicker.Trigger />` as the last child of the Input snippet, after the segments. Codeblock snippets updated to match. - Demo (date-range-picker): keep the dual-input + separator layout but move `<DateRangePicker.Trigger />` into the END input, since the trigger represents the trailing affordance of the whole range. Both code snippets updated. - Recipe CSS (both): add nested rules that detect the embedded case (`[data-date-field-input] > [data-date-picker-trigger]`, `[data-date-range-field-input] > [data-date-range-picker-trigger]`). Embedded trigger drops its own border/background, matches the segment height, sits flush at the trailing edge with `margin-inline-start: auto`, and uses the segment focus ring on hover/focus instead of the standalone field ring. The standalone (sibling) treatment stays available for consumers who prefer the icon as a separate control. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |