From 777d73ff89b010a3cc1358719571b6e36f3b3831 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Mon, 26 Jun 2023 12:45:57 +0200 Subject: [PATCH] ZStack: fix component bounding box to match children (#51836) * ZStack: rewrite using CSS grid * Use first-of-type instead of fist-child * CHANGELOG * Improve comment * Apply styles once in the parent wrapper * Avoid each child view from expanding to all available space * Remove unnecessary wrapeprs in storybook exmaple --- packages/components/CHANGELOG.md | 1 + packages/components/src/z-stack/component.tsx | 6 ++- .../components/src/z-stack/stories/index.tsx | 19 +++----- packages/components/src/z-stack/styles.ts | 47 +++++++++---------- 4 files changed, 34 insertions(+), 39 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index da0ba4d1b3ff3..01db98978c108 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -17,6 +17,7 @@ - `Button`: Remove unnecessary margin from dashicon ([#51395](https://github.com/WordPress/gutenberg/pull/51395)). - `Autocomplete`: Announce how many results are available to screen readers when suggestions list first renders ([#51018](https://github.com/WordPress/gutenberg/pull/51018)). - `ConfirmDialog`: Ensure onConfirm isn't called an extra time when submitting one of the buttons using the keyboard ([#51730](https://github.com/WordPress/gutenberg/pull/51730)). +- `ZStack`: ZStack: fix component bounding box to match children ([#51836](https://github.com/WordPress/gutenberg/pull/51836)). ### Internal diff --git a/packages/components/src/z-stack/component.tsx b/packages/components/src/z-stack/component.tsx index 1cbcac56e4fb7..e087f8536e340 100644 --- a/packages/components/src/z-stack/component.tsx +++ b/packages/components/src/z-stack/component.tsx @@ -35,13 +35,14 @@ function UnconnectedZStack( const clonedChildren = validChildren.map( ( child, index ) => { const zIndex = isReversed ? childrenLastIndex - index : index; - const offsetAmount = offset * index; + // Only when the component is layered, the offset needs to be multiplied by + // the item's index, so that items can correctly stack at the right distance + const offsetAmount = isLayered ? offset * index : offset; const key = isValidElement( child ) ? child.key : index; return ( { clonedChildren } diff --git a/packages/components/src/z-stack/stories/index.tsx b/packages/components/src/z-stack/stories/index.tsx index b04e19962aed1..9b0b080378033 100644 --- a/packages/components/src/z-stack/stories/index.tsx +++ b/packages/components/src/z-stack/stories/index.tsx @@ -8,7 +8,6 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react'; * Internal dependencies */ import { Elevation } from '../../elevation'; -import { HStack } from '../../h-stack'; import { View } from '../../view'; import { ZStack } from '..'; @@ -55,18 +54,12 @@ const Avatar = ( { const Template: ComponentStory< typeof ZStack > = ( args ) => { return ( - - - - - - - - - - - - + + + + + + ); }; diff --git a/packages/components/src/z-stack/styles.ts b/packages/components/src/z-stack/styles.ts index d0bf20d38b1f4..186f268e64366 100644 --- a/packages/components/src/z-stack/styles.ts +++ b/packages/components/src/z-stack/styles.ts @@ -4,36 +4,35 @@ import { css } from '@emotion/react'; import styled from '@emotion/styled'; -/** - * Internal dependencies - */ -import { rtl } from '../utils'; - -export const ZStackView = styled.div` - display: flex; - position: relative; -`; - export const ZStackChildView = styled.div< { - isLayered: boolean; offsetAmount: number; zIndex: number; } >` - ${ ( { isLayered, offsetAmount } ) => - isLayered - ? css( rtl( { marginLeft: offsetAmount } )() ) - : css( rtl( { right: offsetAmount * -1 } )() ) } + &:not( :first-of-type ) { + ${ ( { offsetAmount } ) => + css( { + marginInlineStart: offsetAmount, + } ) }; + } - ${ ( { isLayered } ) => - isLayered ? positionAbsolute : positionRelative } - - ${ ( { zIndex } ) => css( { zIndex } ) } -`; - -const positionAbsolute = css` - position: absolute; + ${ ( { zIndex } ) => css( { zIndex } ) }; `; -const positionRelative = css` +export const ZStackView = styled.div< { + isLayered: boolean; +} >` + display: inline-grid; + grid-auto-flow: column; position: relative; + + & > ${ ZStackChildView } { + position: relative; + justify-self: start; + + ${ ( { isLayered } ) => + isLayered + ? // When `isLayered` is true, all items overlap in the same grid cell + css( { gridRowStart: 1, gridColumnStart: 1 } ) + : undefined }; + } `;