From 28c2af68250090b66777aa3fbcee99238afc1e15 Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Thu, 4 Jun 2026 15:45:34 +0600 Subject: [PATCH 1/7] fix(radio-group): enhance styling for RadioImageCard component --- src/components/ui/radio-group.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx index 3b9d7dc..89d201b 100644 --- a/src/components/ui/radio-group.tsx +++ b/src/components/ui/radio-group.tsx @@ -143,7 +143,7 @@ function RadioImageCard({ return ( @@ -153,18 +153,18 @@ function RadioImageCard({ className="flex flex-col p-0!" data-testid={`settings-field-${props.id}`} > -
+
- + {typeof label === 'string' ? {label} : label}
- -
+ +
{description && ( {description} From 18a036b9c4d10110005bf8de45f1cc6618d84fd4 Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Thu, 4 Jun 2026 16:46:26 +0600 Subject: [PATCH 2/7] fix(settings): resolve id-keyed dependencies regardless of values keying evaluateDependencies looked up values[dep.key] directly. When the flat values map is keyed by the reconstructed dot-path instead of the plain field id, that lookup misses and every dependency-gated field collapses to hidden. Add layered resolution: direct id, then optional idIndex, then last dot-path-segment match. Makes the previously-dormant idIndex param useful and keeps plain-id dependencies working under either keying. --- src/components/settings/settings-formatter.ts | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/components/settings/settings-formatter.ts b/src/components/settings/settings-formatter.ts index 4d09b9b..90fc0fa 100644 --- a/src/components/settings/settings-formatter.ts +++ b/src/components/settings/settings-formatter.ts @@ -334,12 +334,13 @@ export function buildIdIndex( /** * Evaluates whether a field should be displayed based on its dependencies. * - * Dependency keys are plain field ids (post-dependency_key cleanup). The - * value is read directly from the flat `values` map keyed by id. - * - * `idIndex` is kept as an optional parameter for backwards compatibility with - * call sites that still pass it; it's unused now that dependency_key is - * gone and `dep.key` always equals the field id. + * Dependency keys are authored as plain field ids. The flat `values` map is + * keyed by field id (current contract), so a direct lookup normally resolves. + * For resilience against older/alternate payloads that key `values` by the + * reconstructed dot-path (e.g. `page.section.field`), the lookup falls back to: + * 1. an explicit `idIndex` mapping (field id → stored key), when supplied; then + * 2. matching a stored key whose last dot-path segment equals the field id. + * This keeps id-keyed dependencies working regardless of how `values` is keyed. */ export function evaluateDependencies( element: SettingsElement, @@ -353,7 +354,18 @@ export function evaluateDependencies( return element.dependencies.every((dep) => { if (!dep.key) return true; - const currentValue = values[dep.key]; + let currentValue = values[dep.key]; + if (currentValue === undefined) { + const mapped = idIndex?.[dep.key]; + if (mapped !== undefined && values[mapped] !== undefined) { + currentValue = values[mapped]; + } else { + const match = Object.keys(values).find( + (k) => k === dep.key || k.split('.').pop() === dep.key + ); + if (match !== undefined) currentValue = values[match]; + } + } const comparison = dep.comparison || '=='; const expectedValue = dep.value; From d17ac1c97e4b16782adac3a70470be6b027c615e Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Thu, 4 Jun 2026 17:28:04 +0600 Subject: [PATCH 3/7] style(radio-group): remove RadioImageCard body padding for flush image --- src/components/ui/radio-group.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx index 89d201b..2dd0e37 100644 --- a/src/components/ui/radio-group.tsx +++ b/src/components/ui/radio-group.tsx @@ -163,7 +163,7 @@ function RadioImageCard({ {typeof label === 'string' ? {label} : label}
- +
{description && ( From 1fdc9071ce443a0a45cfd67bad80d16db2878f74 Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Thu, 4 Jun 2026 17:37:47 +0600 Subject: [PATCH 4/7] fix(rich-text): stop caret jumping to start on every keystroke MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contentEditable was bound with dangerouslySetInnerHTML={value}, so React re-applied innerHTML on each keystroke-driven re-render and collapsed the selection to the start — every typed char appeared to prepend (reversed/RTL effect). Make it uncontrolled: drop dangerouslySetInnerHTML and only sync the DOM from value/defaultValue when content differs and the editor isn't focused. --- src/components/ui/rich-text-editor.tsx | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/components/ui/rich-text-editor.tsx b/src/components/ui/rich-text-editor.tsx index 709a68d..6ae38c3 100644 --- a/src/components/ui/rich-text-editor.tsx +++ b/src/components/ui/rich-text-editor.tsx @@ -52,12 +52,22 @@ function RichTextEditor({ const [fontFamily, setFontFamily] = React.useState("Sans Serif"); const [textStyle, setTextStyle] = React.useState("Paragraph"); - // Sync internal content with value prop if it changes and is different + // Sync the contentEditable DOM with the value/defaultValue prop. + // + // The contentEditable is intentionally NOT bound via dangerouslySetInnerHTML: + // React would re-apply innerHTML on every keystroke-driven re-render and + // collapse the selection to the start, so each typed character appears to + // prepend (the "reversed / RTL" typing effect). Here we only write innerHTML + // when the incoming content actually differs AND the editor is not focused, + // so external/programmatic updates still land but active typing keeps its caret. React.useEffect(() => { - if (value !== undefined && editorRef.current && value !== editorRef.current.innerHTML) { - editorRef.current.innerHTML = value; - } - }, [value]); + const el = editorRef.current; + if (!el) return; + const next = value ?? defaultValue ?? ""; + if (next === el.innerHTML) return; + if (document.activeElement === el) return; + el.innerHTML = next; + }, [value, defaultValue]); const executeCommand = (command: string, value?: string) => { document.execCommand(command, false, value); @@ -315,7 +325,6 @@ function RichTextEditor({ ref={editorRef} contentEditable className="w-full h-full px-3 py-2 text-sm outline-none bg-transparent prose prose-sm max-w-none" - dangerouslySetInnerHTML={{ __html: value ?? defaultValue }} suppressContentEditableWarning data-placeholder={placeholder} onInput={(e) => { From 63c421db8f239261751bd5b30be6fe4a05639c69 Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Thu, 4 Jun 2026 17:51:50 +0600 Subject: [PATCH 5/7] style(radio-group): make RadioImageCard illustration fill card width Image rendered at intrinsic size and was centered, leaving asymmetric whitespace that read as padding. Make the image block w-full and drop the centering wrapper so the illustration spans the full card width flush. --- src/components/ui/radio-group.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx index 2dd0e37..15dc57b 100644 --- a/src/components/ui/radio-group.tsx +++ b/src/components/ui/radio-group.tsx @@ -163,8 +163,8 @@ function RadioImageCard({ {typeof label === 'string' ? {label} : label}
- -
+ +
{description && ( {description} @@ -172,7 +172,7 @@ function RadioImageCard({ )} {image && ( typeof image === 'string' ? ( - {typeof + {typeof ) : ( image ) From 09eec2f9bf5e97e0c0c1f335b8ea555eef2f2c36 Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Fri, 5 Jun 2026 09:02:59 +0600 Subject: [PATCH 6/7] fix(radio): make RadioImageCard illustration flush to card edges The base FieldLabel injects `*:data-[slot=field]:p-3` which targets the child Field with higher specificity than a `p-0!` on the Field itself, so under the global !important strategy it could not be overridden there. Neutralise it at the root via the same child-targeting utility (`*:data-[slot=field]:p-0`); twMerge collapses p-3 -> p-0 so the illustration sits flush. --- src/components/ui/radio-group.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx index 15dc57b..054e72e 100644 --- a/src/components/ui/radio-group.tsx +++ b/src/components/ui/radio-group.tsx @@ -143,14 +143,19 @@ function RadioImageCard({ return ( p-0 so the illustration sits flush to the card edges. + "transition-colors has-data-checked:bg-transparent dark:has-data-checked:bg-transparent p-0 *:data-[slot=field]:p-0 group cursor-pointer rounded-xl overflow-hidden", currentValue === props.value && 'border-primary!', !disabled && "hover:border-primary" )}>
From afed675b41e913320659de23257f022eb9d08256 Mon Sep 17 00:00:00 2001 From: Kamruzzaman Date: Fri, 5 Jun 2026 09:07:14 +0600 Subject: [PATCH 7/7] fix(radio): pad RadioImageCard content to match the card header FieldContent now uses the same px-5 py-4 padding as the header row, so the illustration is inset consistently with the title instead of bleeding flush. --- src/components/ui/radio-group.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx index 054e72e..f8432e9 100644 --- a/src/components/ui/radio-group.tsx +++ b/src/components/ui/radio-group.tsx @@ -168,7 +168,7 @@ function RadioImageCard({ {typeof label === 'string' ? {label} : label}
- +
{description && (