diff --git a/craft/src/components/layout/Container.dropZone.test.tsx b/craft/src/components/layout/Container.dropZone.test.tsx new file mode 100644 index 0000000..3621b4e --- /dev/null +++ b/craft/src/components/layout/Container.dropZone.test.tsx @@ -0,0 +1,33 @@ +import { describe, test, expect, afterEach } from 'vitest'; +import { renderEditorHarness, EditorHarness } from '../../test-utils/editorHarness'; + +// The 40px min-height is an editor-only DROP ZONE for EMPTY containers. A container that has +// content must lay out like the published page (no injected min-height). +const node = (type: string, props: Record, nodes: string[] = [], extra: Record = {}) => ({ + type: { resolvedName: type }, isCanvas: type === 'Container' || type === 'Text', props, displayName: type, custom: {}, hidden: false, nodes, linkedNodes: {}, ...extra, +}); +let h: EditorHarness | null = null; +afterEach(() => { h?.unmount(); h = null; }); +const mount = (inner: Record, withChild: boolean) => { + h = renderEditorHarness({ + initialState: JSON.stringify({ + ROOT: node('Container', { tag: 'div', style: {} }, ['c1']), + c1: node('Container', { tag: 'section', ...inner }, withChild ? ['t1'] : [], { parent: 'ROOT' }), + ...(withChild ? { t1: node('TextBlock', { text: 'hi', style: {} }, [], { parent: 'c1' }) } : {}), + }), + }); + return h.container.querySelector('section') as HTMLElement; +}; + +describe('Container empty-only drop zone', () => { + test('empty container keeps the 40px drop zone', () => { + expect(mount({ style: {} }, false).style.minHeight).toBe('40px'); + }); + test('non-empty container does NOT get an injected min-height', () => { + expect(mount({ style: {} }, true).style.minHeight).toBe(''); + }); + test('an explicit style.minHeight always wins', () => { + expect(mount({ style: { minHeight: '100px' } }, true).style.minHeight).toBe('100px'); + expect(mount({ style: { minHeight: '100px' } }, false).style.minHeight).toBe('100px'); + }); +}); diff --git a/craft/src/components/layout/Container.tsx b/craft/src/components/layout/Container.tsx index 44ec28d..4797f83 100644 --- a/craft/src/components/layout/Container.tsx +++ b/craft/src/components/layout/Container.tsx @@ -95,8 +95,11 @@ export const Container: UserComponent = ({ // follows the current device's Alignment / Vertical alignment. const layout = containerLayout(style, needsBoxedWrapper); + // 40px min-height = editor-only DROP ZONE, so only an EMPTY container gets it. A container with + // content must size like the published page (toHtml adds no min-height). + const isEmpty = React.Children.count(children) === 0; const outerStyle: CSSProperties = { - minHeight: '40px', + ...(isEmpty ? { minHeight: '40px' } : {}), ...style, ...(fullWidth ? { width: '100vw', marginLeft: 'calc(-50vw + 50%)' } : {}), ...layout.outer,