fix(words): color picker uses applyCommand (no sema) + onchange instead of oninput

Two related fixes to the color picker UX:

1. Swatches now call applyCommand({type:'toggleMark', mark:'color:#x'})
   directly instead of runCommand('color:#x'). runCommand emits the
   'commit-set-format' sema event (which fires sound + visual feedback
   on the editor surface). For discrete color picks the sema event is
   noise — applyCommand bypasses the trigger and just mutates the doc.

2. Native <input type=color> uses `onchange` instead of `oninput`.
   `oninput` fires continuously while the user drags the OS color
   picker — each fire was queueing a separate command + sema event,
   producing a horror cascade of sound / visual flashes on every
   pixel of the slider drag. `onchange` only fires when the user
   releases / commits the picker (closes the OS popup), so we get
   exactly one command per intent.

Same pattern applied to both Foreground and Background pickers
+ the clear (×) buttons.

Sema events are still emitted by the rest of the drawer's action
chips (run via runCommand) because those are user-facing intent
actions (Bold, Italic, etc.) where the perceptual feedback aligns
with the user's notion of "I just did a thing". Color slider drags
are NOT in that category — they're continuous parameter tuning.

Verified: clicking the red swatch on selected "ActiveUI" produces
the expected red <span> in the document AND the trace shows no new
commit-set-format event (was previously firing on every swatch
click, drowning audio + animation).

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

@ -305,7 +305,7 @@
title={preset} title={preset}
aria-label={`Set foreground to ${preset}`} aria-label={`Set foreground to ${preset}`}
onmousedown={(e) => e.preventDefault()} onmousedown={(e) => e.preventDefault()}
onclick={() => s.runCommand(`color:${preset}` as never)} onclick={() => s.applyCommand({ type: 'toggleMark', mark: `color:${preset}` as never })}
></button> ></button>
{/each} {/each}
<input <input
@ -313,9 +313,9 @@
data-words-drawer-color-input data-words-drawer-color-input
value={currentParametricMark(s.activeMarks, 'color') || '#000000'} value={currentParametricMark(s.activeMarks, 'color') || '#000000'}
aria-label="Pick custom foreground color" aria-label="Pick custom foreground color"
oninput={(e) => { onchange={(e) => {
const v = (e.currentTarget as HTMLInputElement).value; const v = (e.currentTarget as HTMLInputElement).value;
s.runCommand(`color:${v}` as never); s.applyCommand({ type: 'toggleMark', mark: `color:${v}` as never });
}} }}
/> />
{#if currentParametricMark(s.activeMarks, 'color')} {#if currentParametricMark(s.activeMarks, 'color')}
@ -325,7 +325,7 @@
title="Clear foreground" title="Clear foreground"
aria-label="Clear foreground color" aria-label="Clear foreground color"
onmousedown={(e) => e.preventDefault()} onmousedown={(e) => e.preventDefault()}
onclick={() => s.runCommand('color:' as never)} onclick={() => s.applyCommand({ type: 'toggleMark', mark: 'color:' as never })}
>×</button> >×</button>
{/if} {/if}
</div> </div>
@ -341,7 +341,7 @@
title={preset} title={preset}
aria-label={`Set background to ${preset}`} aria-label={`Set background to ${preset}`}
onmousedown={(e) => e.preventDefault()} onmousedown={(e) => e.preventDefault()}
onclick={() => s.runCommand(`bgcolor:${preset}` as never)} onclick={() => s.applyCommand({ type: 'toggleMark', mark: `bgcolor:${preset}` as never })}
></button> ></button>
{/each} {/each}
<input <input
@ -349,9 +349,9 @@
data-words-drawer-color-input data-words-drawer-color-input
value={currentParametricMark(s.activeMarks, 'bgcolor') || '#ffff00'} value={currentParametricMark(s.activeMarks, 'bgcolor') || '#ffff00'}
aria-label="Pick custom background color" aria-label="Pick custom background color"
oninput={(e) => { onchange={(e) => {
const v = (e.currentTarget as HTMLInputElement).value; const v = (e.currentTarget as HTMLInputElement).value;
s.runCommand(`bgcolor:${v}` as never); s.applyCommand({ type: 'toggleMark', mark: `bgcolor:${v}` as never });
}} }}
/> />
{#if currentParametricMark(s.activeMarks, 'bgcolor')} {#if currentParametricMark(s.activeMarks, 'bgcolor')}
@ -361,7 +361,7 @@
title="Clear background" title="Clear background"
aria-label="Clear background color" aria-label="Clear background color"
onmousedown={(e) => e.preventDefault()} onmousedown={(e) => e.preventDefault()}
onclick={() => s.runCommand('bgcolor:' as never)} onclick={() => s.applyCommand({ type: 'toggleMark', mark: 'bgcolor:' as never })}
>×</button> >×</button>
{/if} {/if}
</div> </div>

Loading…
Cancel
Save

Powered by TurnKey Linux.