React.memo alone does nothing here: PaletteTabs built a fresh
`(hex) => setColor(slot, hex)` closure per field on every render, so
memo's prop comparison always saw a "changed" onChange and re-rendered
anyway. Stabilized it properly:
- setColor/setGradient read draft/onChange from a ref (updated in a
useLayoutEffect, not during render -- oxlint's react(refs) rule
correctly flags a ref write in the render body) so they keep a
stable identity (useCallback, empty deps) across edits
- per-slot wrapper closures are built once in a useMemo keyed off
those now-stable functions, not off `draft`
This doesn't change the preset-switch case measured earlier (every
field's value genuinely changes then, so memo correctly re-renders
all of them -- that cost is what startTransition already covers). It
does stop sibling fields re-rendering on interactions that don't
touch them: undo/redo, tab switching, hovering unrelated panel
elements.
Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ