From ed50732d58159e55fc090b6dbe59c7b98c4440ed Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Sun, 1 Nov 2026 16:43:01 -0800 Subject: [PATCH] sitesmith: readable form inputs on dark sections + sRGB color-mix() in contrast repair Eval 2026-11-01 (ttm-likes): a ContactForm on a dark band had dark typed text and UA-grey placeholders on a color-mix() input surface, and its inputBorder "1px solid X" came out as the invalid "1px solid 1px solid X". - ContactForm: new inputTextColor prop (typed text); placeholders now follow the input's own text colour via a scoped form[data-wsb-form] ::placeholder rule (export + editor canvas); an inputBorder that is a whole border is used as-is. Without inputTextColor the legacy derivation is unchanged. - contrast repair: resolves opaque color-mix(in srgb, A p%, B) surfaces (the brief prescribes these tints; translucent / other spaces stay unchecked), checks ContactForm labelColor against its section and the derived input text colour against an explicitly set inputBg, writing inputTextColor on failure. - catalog generator: (rebased onto main 01a78c9, which already omits the clock-derived Countdown.targetDate default via VOLATILE_DEFAULTS + the date-frozen drift test; this commit's duplicate inline check was dropped.) Co-Authored-By: Claude Opus 5.5 --- .../forms/ContactForm.toHtml.test.ts | 24 +++++++++ craft/src/components/forms/ContactForm.tsx | 23 +++++++-- craft/src/styles/editor.css | 3 ++ craft/src/utils/contrast-repair.test.ts | 51 +++++++++++++++++-- craft/src/utils/contrast-repair.ts | 47 +++++++++++++++-- 5 files changed, 137 insertions(+), 11 deletions(-) diff --git a/craft/src/components/forms/ContactForm.toHtml.test.ts b/craft/src/components/forms/ContactForm.toHtml.test.ts index 210dbcb..05149ed 100644 --- a/craft/src/components/forms/ContactForm.toHtml.test.ts +++ b/craft/src/components/forms/ContactForm.toHtml.test.ts @@ -311,3 +311,27 @@ describe('ContactForm.toHtml design tokens (#44)', () => { for (const hex of ["#ef4444", "#374151", "#d1d5db", "#ffffff"]) expect(lower, `old ${hex}`).not.toContain(hex); }); }); + +describe('ContactForm.toHtml dark-aware inputs (eval 2026-11-01)', () => { + const fields = [{ type: 'text', label: 'Name', name: 'name', placeholder: 'Your name', required: true }]; + test('inputTextColor sets the typed text colour; placeholders follow it (currentColor) via a scoped rule', () => { + const { html } = toHtml({ fields, inputBg: '#1b1530', inputTextColor: '#f5f3ff' }, '', 'n1'); + expect(html).toMatch(/]*style="[^"]*color:#f5f3ff/); + expect(html).toMatch(/]*data-wsb-form/); + expect(html).toContain(''); + }); + test('without inputTextColor the old derivation stays (light stored surface -> legacy dark text)', () => { + expect(toHtml({ fields, inputBg: '#ffffff' }, '').html).toMatch(/]*color:#1f2937/); + expect(toHtml({ fields }, '').html).toMatch(/]*color:var\(--wsb-text\)/); + }); + test('an inputBorder written as a whole border ("1px solid X") is used as-is, not doubled into "1px solid 1px solid X"', () => { + const { html } = toHtml({ fields, inputBorder: '1px solid color-mix(in srgb, var(--wsb-secondary) 45%, transparent)' }, ''); + expect(html).not.toContain('1px solid 1px solid'); + expect(html).toContain('border:1px solid color-mix(in srgb, var(--wsb-secondary) 45%, transparent)'); + expect(toHtml({ fields, inputBorder: '#334155' }, '').html).toContain('border:1px solid #334155'); + }); + test('a hostile inputTextColor cannot break out of the style attribute', () => { + const { html } = toHtml({ fields, inputTextColor: 'red;}">' }, ''); + expect(html).not.toContain('