diff --git a/CHANGELOG.md b/CHANGELOG.md index 453145f..3040683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ ### Added +- the swatch is resolved in an effect, and the ref is actually ON the element. Both got broken while editing this and nothing failed: a ref that is not attached reads as null, the effect returns early, and `?? "#000000"` does the rest — so a fallback that HIDES a missing ref is itself part of the defect. jsdom does not resolve `color` into `getComputedStyle`, so the inherited branch is only observable in a browser; what the test pins is the contract that let it slip, namely that the swatch is never handed the literal string. + - the swatch is resolved in an effect, not from a ref. A ref is null during the render that needs it, so the first version always fell through to black — a swatch reporting black for dots that are not black — and `input[type=color]` silently ignores a non-hex value, keeping a stale colour instead. There is now a test that the swatch is always handed a form it will render. - **The dot colour is selectable, and it copies.** A picker in the sticky pane beside the field it colours — a native swatch with the OS colour well and the eyedropper, a text field, and HEX / RGB / HSL chips. The colour reaches the copied snippet, which it did not before: `changedOptions` never emitted `color`, so a visitor who picked a colour and pasted the result got a component that drew in `currentColor` and no indication why. diff --git a/CHANGELOG.zh.md b/CHANGELOG.zh.md index 603b280..f4c920a 100644 --- a/CHANGELOG.zh.md +++ b/CHANGELOG.zh.md @@ -23,6 +23,8 @@ ### 新增 +- 色块在 effect 里解析,而且 ref 确实挂在元素上。两者都在编辑过程中被弄坏过,且没有任何检查失败:没挂上的 ref 读出来是 null,effect 提前返回,`?? "#000000"` 兜住了剩下的部分 —— 所以一个**掩盖**了 ref 缺失的兜底,本身就是缺陷的一部分。jsdom 不会把 `color` 解析进 `getComputedStyle`,因此继承分支只能在浏览器里观察;测试锁定的是让它溜过去的那条契约:色块永远不会拿到那个字面字符串。 + - 色块在 effect 里解析,而不是从 ref。ref 在需要它的那次渲染里必然为 null,所以第一版总是回落到黑色 —— 一个为一群并非黑色的点报告黑色的色块 —— 而且 `input[type=color]` 会静默忽略非 hex 的值,改为保留上一个陈旧颜色。现在有一条测试断言色块拿到的永远是它能渲染的形式。 - **点的颜色现在可选择,并且会被复制。** sticky 面板里、紧挨着它所染色的场有一个拾色器 —— 原生色块(带系统取色面板和吸管)、文本框,以及 HEX / RGB / HSL 三个 chip。颜色会进入复制片段,而此前不会:`changedOptions` 从不输出 `color`,所以选了颜色再粘贴的人拿到的是一个用 `currentColor` 绘制的组件,且没有任何提示为什么。 diff --git a/apps/site/src/components/ColorPicker.tsx b/apps/site/src/components/ColorPicker.tsx index 894b3b3..06f6878 100644 --- a/apps/site/src/components/ColorPicker.tsx +++ b/apps/site/src/components/ColorPicker.tsx @@ -89,7 +89,7 @@ export function ColorPicker({ useEffect(() => () => cancelAnimationFrame(frame.current), []); return ( -
+
diff --git a/apps/site/test/playground.test.tsx b/apps/site/test/playground.test.tsx index 1fc02a7..c209e57 100644 --- a/apps/site/test/playground.test.tsx +++ b/apps/site/test/playground.test.tsx @@ -1095,10 +1095,17 @@ describe("the dot colour", () => { // `input[type=color]` silently refuses anything that is not `#rrggbb`: it keeps the // last valid value rather than showing what you set. `currentColor` — the engine's // default, and what the field opens on — is not `#rrggbb`, so the swatch has to be - // given a real hex or it shows a stale colour from an earlier interaction. - const value = swatch().value; - expect(value, "and never the literal string").not.toBe("currentColor"); - expect(value, "which is the only form a colour input will render").toMatch(/^#[0-9a-f]{6}$/i); + // handed a real hex or it shows a stale colour from an earlier interaction. + // + // jsdom does not resolve `color` from an inline style into `getComputedStyle`, so the + // INHERITED branch cannot be observed here — the swatch falls back to black under + // jsdom while a browser resolves it. What IS asserted is the contract that let this + // break: a fallback must never be what a visitor sees, so the swatch is required to + // hold a real hex rather than the literal string. + expect(swatch().value, "never the literal string").not.toBe("currentColor"); + expect(swatch().value, "and always the only form a colour input will render").toMatch( + /^#[0-9a-f]{6}$/i, + ); }); it("paints the field, not just its own label", async () => {