fix(ui-core): the schema editor's swatch shows the colour the class is drawn in (#162) - #168
Merged
Merged
Conversation
…s drawn in (#162) A class with no declared colour showed the two colours it is actually drawn in as two different colours in the same row: the dot beside its name showed the real derived hue, and the Colour swatch immediately to its right showed grey, captioned "Derived from the name." The grey was an empty `<input type="color">` falling back to its own default. `hexOf` passed a value through only when it already matched `#rrggbb` and answered a neutral otherwise — and `classColor`'s derived branch answers `hsl(hash % 360 72% 58%)`, so *every* derived class took the fallback. The class is not grey anywhere: the annotator draws it in that same teal. `hexColor` in `palette.ts` converts instead. It is a **notation change, never a second palette**: `classColor` stays the one spelling of the rule (#128's gate, which `palette.test.ts` still asserts by reference identity), and this only turns its answer into the four hex digits an input can take. `null` for anything it cannot convert — the kernel accepts any CSS spelling in `LabelClass.color`, so a schema authored elsewhere may hold `rgb(255 0 0)`, and shipping a CSS colour parser to fill in one input is not worth it. The neutral survives for exactly that case, which is the one it was always right about. The care is in the second half: **making the input display a colour must not make the class declare it.** An untouched save still sends `color: null` for a derived class, and the test asserts that on the request payload rather than on the control — a version that pinned today's hash output would make every derived class look authored and would change meaning if the palette rule ever moved. "Derive" still clears a declared colour, and the swatch now follows it there too. Verified by mutation: restoring the old `#rrggbb`-or-neutral fallback turns two named tests red. `DESIGN.md` records the conversion beside the palette rule it serves. Frontend only: no Python, no migration, `openapi.json` and the generated client byte-identical, `FORMAT_VERSION` still 12. Closes #162
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #162. Fourth of the
0.0.1-beta.2defect fixes.The defect
A class with no declared colour showed the two colours it is actually drawn in as two different colours in the same row:
pedestrian→ teal,weather→ gold);The grey was an empty
<input type="color">falling back to its own default.hexOfpassed a value through only when it already matched#rrggbband answered a neutral otherwise — andclassColor's derived branch answershsl(hash % 360 72% 58%), so every derived class took the fallback. The class is not grey anywhere: the annotator draws it in the same teal, confirmed by drawing one.So the editor contradicted both the dot two inches to its left and the canvas, in the one control whose entire job is to show what colour something is.
The fix
hexColorinfrontend/ui-core/src/palette.tsconverts rather than giving up. It is a notation change, never a second palette — criterion 4:classColorstays the single spelling of the rule (ui-core: design system foundation — port v1's DESIGN.md visual contract (Tailwind v4 @theme tokens, shadcn/Radix primitives, class palette rule) #128's gate, whichpalette.test.tsstill asserts by reference identity against the annotator's export);#rrggbb,#rgband both spellings ofhsl(...);nullfor anything else, and the caller shows its neutral for that case alone. The kernel accepts any CSS spelling inLabelClass.color, so a schema authored elsewhere may legitimately holdrgb(255 0 0)orrebeccapurple, and shipping a CSS colour parser to fill in one input is not the trade. The dot still shows the truth there.The half worth being careful about
Making the input display a colour must not make the class declare one. A schema version that pinned today's hash output would make every derived class look authored, and would change meaning if the palette rule ever moved.
So the guard is on the payload, not the control (criterion 2): after a save dirtied by something that is not the colour, the POST body still carries
color: nullfor the derived class. "Derive" still clears a declared colour (criterion 3), and the swatch now follows it there too.Verified by mutation: restoring the old
#rrggbb-or-neutral fallback turns two named tests red —previews a derived class in the colour it is actually drawn inandDerive clears a declared colour back to the derived one, in the swatch too.Every expectation is computed from the shipped palette rather than hardcoded, so a change to the rule moves both sides together and only a swatch that stopped reading
classColorfails.screens.test.tsxgained a request-body capture for this —gallery.test.tsxalready had one.Ledger
openapi.jsonand the generated client byte-identical;FORMAT_VERSIONstill 12.DESIGN.mdrecords the conversion beside the palette rule it serves, since that file is the authority on it.Checks run locally
pnpm test— 711 annotator + 123 ui-core vitest, 22 node:testpnpm -r build,pnpm -r lint,pnpm -r typecheck— clean