refactor(builder): use shared escaper everywhere, drop 26 local copies

Replace divergent, buggy local esc/escapeHtml helpers across 26 files with
imports from src/utils/escape (escapeHtml/escapeAttr). Attribute call sites use
escapeAttr, text-content sites use escapeHtml. Several toHtml outputs now
correctly escape & where old local escapers omitted it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 11:49:10 -07:00
parent cce984508f
commit fad1882117
26 changed files with 101 additions and 119 deletions
+4 -9
View File
@@ -2,6 +2,7 @@ import React, { CSSProperties, useCallback, useRef, useState } from 'react';
import { useNode, UserComponent } from '@craftjs/core';
import { cssPropsToString } from '../../utils/style-helpers';
import { useSiteDesign } from '../../state/SiteDesignContext';
import { escapeHtml, escapeAttr } from '../../utils/escape';
/* ---------- Types ---------- */
@@ -37,12 +38,6 @@ async function uploadToWhp(file: File): Promise<string | null> {
} catch { return null; }
}
/* ---------- Helper: escape HTML ---------- */
function esc(str: any): string {
str = String(str ?? "");
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
/* ---------- Component ---------- */
export const Logo: UserComponent<LogoProps> = ({
@@ -394,7 +389,7 @@ Logo.craft = {
let innerHtml: string;
if (props.type === 'image' && props.imageSrc) {
const imgStyle = cssPropsToString({ width: props.imageWidth || '120px', height: 'auto', display: 'block' });
innerHtml = `<img src="${esc(props.imageSrc)}" alt="${esc(props.text || 'Logo')}"${imgStyle ? ` style="${imgStyle}"` : ''} />`;
innerHtml = `<img src="${escapeAttr(props.imageSrc)}" alt="${escapeAttr(props.text || 'Logo')}"${imgStyle ? ` style="${imgStyle}"` : ''} />`;
} else {
const spanStyle = cssPropsToString({
fontWeight: props.fontWeight || '700',
@@ -402,7 +397,7 @@ Logo.craft = {
fontFamily: props.fontFamily || 'Inter, sans-serif',
color: props.color || '#1f2937',
});
innerHtml = `<span${spanStyle ? ` style="${spanStyle}"` : ''}>${esc(props.text || 'MySite')}</span>`;
innerHtml = `<span${spanStyle ? ` style="${spanStyle}"` : ''}>${escapeHtml(props.text || 'MySite')}</span>`;
}
const aStyle = cssPropsToString({
@@ -414,6 +409,6 @@ Logo.craft = {
});
return {
html: `<a href="${esc(href)}"${aStyle ? ` style="${aStyle}"` : ''}>${innerHtml}</a>`,
html: `<a href="${escapeAttr(href)}"${aStyle ? ` style="${aStyle}"` : ''}>${innerHtml}</a>`,
};
};