From da19728cb6f460427e549fb5d017468547514a96 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 21 May 2026 23:03:42 +0200 Subject: [PATCH] feat(color-picker): area drag emits handle-pick/handle-drag/commit-set + refresh demo snippets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (`` 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) --- src/uix/morfo/components/color-picker.ts | 24 ++++++++++ .../color-picker-provider.svelte.ts | 11 +++++ .../uix/components/color-picker/+page.svelte | 45 ++++++++++++++++--- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/uix/morfo/components/color-picker.ts b/src/uix/morfo/components/color-picker.ts index ee4edc9d8..3c58b8978 100644 --- a/src/uix/morfo/components/color-picker.ts +++ b/src/uix/morfo/components/color-picker.ts @@ -7,6 +7,30 @@ export const colorPickerMorfo = { scope: ['soma', 'sema'], apg: 'https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/', events: [ + // Area drag — same shape as the slider's `handle-*` events so sema + // consumers can hook the family/verb uniformly (sounds, haptics, + // transient styling) regardless of which dragger emitted. + { + name: 'handle-pick', + semantic: { + family: 'handle', + verb: 'pick', + target: v.partRef('area'), + sequence: 'coincident' + } + }, + { + name: 'handle-drag', + semantic: { + family: 'handle', + verb: 'drag', + target: v.partRef('area'), + sequence: 'coincident' + } + }, + // Value commit — fires on pointer release (area thumb / channel + // slider / swatch click / eyedropper pick). `commit-set` is the + // canonical "save" signal. { name: 'commit-set', semantic: { diff --git a/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts b/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts index 1164a96dc..9212e01c9 100644 --- a/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts +++ b/src/uix/soma/components/color-picker/color-picker-provider.svelte.ts @@ -692,6 +692,8 @@ export class ColorPickerAreaProvider { const withX = setColorChannel(this.provider.effectiveColor, this.xChannel, xValue); const withBoth = setColorChannel(withX, this.yChannel, yValue); this.provider.opts.value.current = withBoth; + // Sema: emit `handle-drag` so consumers can stream tactile feedback. + void this.provider.runtime.trigger('handle-drag'); } readonly onpointerdown = (e: PointerEvent): void => { @@ -699,6 +701,8 @@ export class ColorPickerAreaProvider { const target = e.currentTarget as HTMLElement; target.setPointerCapture(e.pointerId); this.pointerId = e.pointerId; + // Sema: emit `handle-pick` at drag start (mirrors slider semantics). + void this.provider.runtime.trigger('handle-pick'); this.handlePointerMove(e.clientX, e.clientY, target.getBoundingClientRect()); e.preventDefault(); }; @@ -712,6 +716,8 @@ export class ColorPickerAreaProvider { readonly onpointerup = (e: PointerEvent): void => { if (this.pointerId !== e.pointerId) return; this.pointerId = null; + // Sema: fire `commit-set` on release (canonical save signal). + void this.provider.runtime.trigger('commit-set'); this.provider.commitChange(); }; @@ -837,6 +843,11 @@ export class ColorPickerAreaThumbProvider { if (nextX !== x) next = setColorChannel(next, this.area.xChannel, nextX); if (nextY !== y) next = setColorChannel(next, this.area.yChannel, nextY); this.provider.opts.value.current = next; + + // Sema: each keypress is one drag-step + commit (slider parity). + void this.provider.runtime.trigger('handle-drag'); + void this.provider.runtime.trigger('commit-set'); + this.provider.commitChange(); }; readonly props = $derived.by(() => { diff --git a/web/routes/uix/components/color-picker/+page.svelte b/web/routes/uix/components/color-picker/+page.svelte index 0bf0270f7..fc06f332a 100644 --- a/web/routes/uix/components/color-picker/+page.svelte +++ b/web/routes/uix/components/color-picker/+page.svelte @@ -131,6 +131,7 @@ [ "