fix(site-builder): hero gradient blank on editor canvas - shorthand + undefined longhands
HeroSimple emitted 'background' together with backgroundImage/Size/Position that were undefined. React assigns '' for those on first render and Chromium and Firefox then wipe the shorthand's gradient (background-image: none), so the canvas hero rendered white. Build the style with only the relevant keys (shared by render and toHtml); exported HTML is byte-identical. Adds a real-browser (Chromium+Firefox) regression test: npm run test:browser:bg, and toHtml byte-identity assertions. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
76f0ba9ca1
commit
dbf3dda3e4
5 files changed
+129
-13
No files matched your search
@@ -0,0 +1,21 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { HeroSimple } from './HeroSimple';
|
||||
|
||||
// Exported section tag captured BEFORE the shorthand/longhand fix; must stay byte-identical.
|
||||
const toHtml = (HeroSimple as any).toHtml;
|
||||
const cases: Array<[any, string]> = [
|
||||
[{"bgType":"gradient"}, "<section style=\"background:linear-gradient(135deg, var(--wsb-primary), var(--wsb-secondary));min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px\">"],
|
||||
[{"bgType":"color","bgColor":"#123456"}, "<section style=\"background:#123456;min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px\">"],
|
||||
[{"bgType":"image","bgImage":"a.jpg"}, "<section style=\"background-image:url('a.jpg');background-size:cover;background-position:center;min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px\">"],
|
||||
[{"bgType":"image","bgImage":"a.jpg","bgPosition":"top"}, "<section style=\"background-image:url('a.jpg');background-size:cover;background-position:top;min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px\">"],
|
||||
[{"bgType":"image"}, "<section style=\"background-size:cover;background-position:center;min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px\">"],
|
||||
[{"bgType":"video","bgVideo":"v.mp4"}, "<section style=\"background:var(--wsb-text);min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px\">"],
|
||||
[{"bgType":"gradient","style":{"backgroundColor":"red"}}, "<section style=\"background:linear-gradient(135deg, var(--wsb-primary), var(--wsb-secondary));min-height:500px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding:60px 20px;background-color:red\">"],
|
||||
];
|
||||
|
||||
describe('HeroSimple.toHtml background output is unchanged by the longhand fix', () => {
|
||||
test.each(cases)('%j', (props, expected) => {
|
||||
const tag = toHtml(props, '').html.match(/<section[^>]*>/)[0];
|
||||
expect(tag).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -49,6 +49,24 @@ function buildBackground(props: HeroProps): string {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Background style keys for the hero section. Emits EITHER the `background`
|
||||
* shorthand (color/gradient/video) OR the image longhands -- never the
|
||||
* shorthand together with a longhand that may be undefined. React assigns ''
|
||||
* for undefined style values on the initial render, and in Chromium assigning
|
||||
* a background longhand '' AFTER the `background` shorthand wipes the
|
||||
* shorthand's gradient (background-image -> none), leaving the editor canvas
|
||||
* hero blank. jsdom does not reproduce this; see scripts/e2e-background.mjs.
|
||||
*/
|
||||
function heroBackgroundStyle(props: HeroProps): React.CSSProperties {
|
||||
if (props.bgType !== 'image') return { background: buildBackground(props) };
|
||||
return {
|
||||
...(props.bgImage ? { backgroundImage: `url('${props.bgImage}')` } : {}),
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: cssValue(props.bgPosition) || 'center',
|
||||
};
|
||||
}
|
||||
|
||||
export const HeroSimple: UserComponent<HeroProps> = ({
|
||||
heading = 'Build Something Amazing',
|
||||
subtitle = 'Create beautiful websites without writing a single line of code.',
|
||||
@@ -78,10 +96,6 @@ export const HeroSimple: UserComponent<HeroProps> = ({
|
||||
}) => {
|
||||
const { connectors: { connect, drag } } = useNode();
|
||||
|
||||
const bg = buildBackground({
|
||||
bgType, bgColor, bgGradientFrom, bgGradientTo, bgGradientAngle, bgImage,
|
||||
} as HeroProps);
|
||||
|
||||
const justifyMap = { top: 'flex-start', center: 'center', bottom: 'flex-end' };
|
||||
|
||||
const effectiveCtas = normalizeCtas({ ctas, buttonText, buttonHref, secondaryButtonText, secondaryButtonHref });
|
||||
@@ -97,10 +111,7 @@ export const HeroSimple: UserComponent<HeroProps> = ({
|
||||
id={anchorId || undefined}
|
||||
style={{
|
||||
...style,
|
||||
background: bgType !== 'image' ? bg : undefined,
|
||||
backgroundImage: bgType === 'image' && bgImage ? `url('${bgImage}')` : undefined,
|
||||
backgroundSize: bgType === 'image' ? 'cover' : undefined,
|
||||
backgroundPosition: bgType === 'image' ? (cssValue(bgPosition) || 'center') : undefined,
|
||||
...heroBackgroundStyle({ bgType, bgColor, bgGradientFrom, bgGradientTo, bgGradientAngle, bgImage, bgPosition } as HeroProps),
|
||||
minHeight: minHeight === '100vh' ? '100vh' : minHeight,
|
||||
display: 'flex',
|
||||
alignItems: justifyMap[verticalAlign] || 'center',
|
||||
@@ -205,14 +216,10 @@ HeroSimple.craft = {
|
||||
/* ---------- HTML export ---------- */
|
||||
|
||||
(HeroSimple as any).toHtml = (props: HeroProps, _childrenHtml: string) => {
|
||||
const bg = buildBackground(props);
|
||||
const justifyMap: Record<string, string> = { top: 'flex-start', center: 'center', bottom: 'flex-end' };
|
||||
|
||||
const sectionStyle = cssPropsToString({
|
||||
background: props.bgType !== 'image' ? bg : undefined,
|
||||
backgroundImage: props.bgType === 'image' && props.bgImage ? `url('${props.bgImage}')` : undefined,
|
||||
backgroundSize: props.bgType === 'image' ? 'cover' : undefined,
|
||||
backgroundPosition: props.bgType === 'image' ? (cssValue(props.bgPosition) || 'center') : undefined,
|
||||
...heroBackgroundStyle(props),
|
||||
minHeight: props.minHeight || '500px',
|
||||
display: 'flex',
|
||||
alignItems: justifyMap[props.verticalAlign || 'center'],
|
||||
|
||||
Reference in new issue
Block a user