fix(containers): only flex-convert Container/Section when vertical-align set (avoid blockifying inline-block children)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-14 06:55:20 -07:00
parent 9750a6c2bf
commit 4a426e3513
4 changed files with 65 additions and 33 deletions
+17 -15
View File
@@ -43,17 +43,19 @@ const flexAlignFromTextAlign = (textAlign: CSSProperties['textAlign']): CSSPrope
return {};
};
// Container is ALWAYS display:flex/flex-direction:column at its root (both
// in the editor render below and in toHtml) so that `style.justifyContent`
// (the new Vertical Alignment control, paired with `style.minHeight`) has an
// axis to act on. This is a no-op visually for existing content: a column
// flex container with default `justify-content:flex-start` and
// `align-items:stretch` reproduces ordinary block-flow stacking (children
// stack top-to-bottom, full width) byte-for-byte, so nothing published
// before this feature shipped changes appearance. `flexAlignFromTextAlign`
// above still supplies `alignItems` (cross-axis, i.e. horizontal position)
// from `textAlign` independently -- the two controls act on orthogonal axes
// and don't conflict.
// Container only becomes display:flex/flex-direction:column at its root
// (both in the editor render below and in toHtml) when the user has
// actually set `style.justifyContent` (the Vertical Alignment control,
// paired with `style.minHeight`) -- i.e. the flex conversion is gated on
// vertical-align actually being in use, not unconditional. In-flow children
// of a flex container get CSS-blockified, which would force components that
// deliberately render `display:inline-block` (ButtonLink, Icon) to stack
// vertically instead of sitting side-by-side -- a real visual regression for
// any container/section that never touches vertical alignment, not a no-op.
// So plain block flow (no `display`/`flex-direction` at all) is preserved
// unless vertical-align is set. `flexAlignFromTextAlign` above still
// supplies its own conditional flex conversion (cross-axis alignItems from
// `textAlign`) independently -- unrelated to this gate.
export const Container: UserComponent<ContainerProps> = ({
style = {},
@@ -70,12 +72,12 @@ export const Container: UserComponent<ContainerProps> = ({
const safeTag = sanitizeContainerTag(tag);
const needsBoxedWrapper = contentWidth === 'boxed';
const flexStyles = flexAlignFromTextAlign(style.textAlign);
const hasVerticalAlign = !!style.justifyContent;
const outerStyle: CSSProperties = {
display: 'flex',
flexDirection: 'column',
minHeight: '40px',
...style,
...(hasVerticalAlign ? { display: 'flex', flexDirection: 'column' } : {}),
...(fullWidth ? { width: '100vw', marginLeft: 'calc(-50vw + 50%)' } : {}),
...(needsBoxedWrapper ? {} : flexStyles),
};
@@ -142,11 +144,11 @@ Container.craft = {
const tag = sanitizeContainerTag(props.tag);
const isBoxed = props.contentWidth === 'boxed';
const flexStyles = flexAlignFromTextAlign(props.style?.textAlign);
const hasVerticalAlign = !!props.style?.justifyContent;
const outerCss: CSSProperties = {
display: 'flex',
flexDirection: 'column',
...props.style,
...(hasVerticalAlign ? { display: 'flex', flexDirection: 'column' } : {}),
...(isBoxed ? {} : flexStyles),
};