From 34f432e824e9a7412aa94aadd45f2ba85f43114c Mon Sep 17 00:00:00 2001 From: Nalla Prakash <81852531+prakashNalla@users.noreply.github.com> Date: Thu, 29 Oct 2026 03:57:40 +0530 Subject: [PATCH] fix(editor): keep a cleared color field editable --- src/components/editor/ColorPicker.tsx | 9 ++++--- src/components/editor/CustomizePanel.tsx | 2 +- tests/editor/color-picker.test.ts | 30 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 tests/editor/color-picker.test.ts diff --git a/src/components/editor/ColorPicker.tsx b/src/components/editor/ColorPicker.tsx index 413e82a..984618b 100644 --- a/src/components/editor/ColorPicker.tsx +++ b/src/components/editor/ColorPicker.tsx @@ -1,4 +1,5 @@ -import { useId } from 'react'; +import { useId, useRef } from 'react'; +import { normalizeHexColor } from '@/templates/utils'; interface ColorPickerProps { label: string; @@ -10,7 +11,9 @@ export function ColorPicker({ label, value, onChange }: ColorPickerProps) { const id = useId(); const colorId = `${id}-color`; const hexId = `${id}-hex`; - const displayValue = value.startsWith('#') ? value : `#${value}`; + const displayValue = value && !value.startsWith('#') ? `#${value}` : value; + const lastValid = useRef('#000000'); + lastValid.current = normalizeHexColor(value, lastValid.current); return (
@@ -23,7 +26,7 @@ export function ColorPicker({ label, value, onChange }: ColorPickerProps) { id={colorId} type="color" className="editor-color-swatch" - value={displayValue} + value={lastValid.current} onChange={(e) => onChange(e.target.value)} /> diff --git a/src/components/editor/CustomizePanel.tsx b/src/components/editor/CustomizePanel.tsx index 8e1e1eb..a781bb5 100644 --- a/src/components/editor/CustomizePanel.tsx +++ b/src/components/editor/CustomizePanel.tsx @@ -113,7 +113,7 @@ function renderField( onChange(field.key, v)} /> ); diff --git a/tests/editor/color-picker.test.ts b/tests/editor/color-picker.test.ts new file mode 100644 index 0000000..9f6fcdf --- /dev/null +++ b/tests/editor/color-picker.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect } from 'vitest'; +import { renderToString } from 'react-dom/server'; +import React from 'react'; +import { CustomizePanel } from '@/components/editor/CustomizePanel'; +import type { TemplateField } from '@/templates/types'; + +const fields: TemplateField[] = [{ key: 'bgColor', label: 'Background', type: 'color', defaultValue: '#0f172a', group: 'Style' }]; + +function inputs(bgColor: unknown) { + const html = renderToString( + React.createElement(CustomizePanel, { fields, params: { bgColor }, onParamChange: () => {}, onReset: () => {} }), + ); + const value = (type: string) => html.match(new RegExp(`]*type="${type}"[^>]*value="([^"]*)"`))?.[1]; + return { swatch: value('color'), text: value('text') }; +} + +describe('ColorPicker', () => { + it('leaves a cleared hex field empty instead of filling in #000000', () => { + expect(inputs('').text).toBe(''); + }); + + it('shows what was typed and gives the swatch a full #rrggbb color', () => { + expect(inputs('#fff')).toEqual({ swatch: '#ffffff', text: '#fff' }); + expect(inputs('ff8800')).toEqual({ swatch: '#ff8800', text: '#ff8800' }); + }); + + it('keeps a partial value in the text field', () => { + expect(inputs('#ff88').text).toBe('#ff88'); + }); +});