-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
components: Add ZStack #31613
components: Add ZStack #31613
Conversation
Size Change: +303 B (0%) Total Size: 1.62 MB
ℹ️ View Unchanged
|
94e32fe
to
4d29795
Compare
import { contextConnect, useContextSystem } from '../ui/context'; | ||
// eslint-disable-next-line no-duplicate-imports | ||
import type { ViewOwnProps } from '../ui/context'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a convention in this package to separate type imports from other imports, even if they come from the same file?
import { contextConnect, useContextSystem } from '../ui/context'; | |
// eslint-disable-next-line no-duplicate-imports | |
import type { ViewOwnProps } from '../ui/context'; | |
import { contextConnect, useContextSystem, ViewOwnProps } from '../ui/context'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! We actually enforce this through the compiler: https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha! It just feels a bit dirty to disable one eslint
rule in order not to fail another ts
rule, but definitely not something in the scope of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. 99% of the time it's contained to these components files and won't matter elsewhere. @gziolo how would you feel about disabling this particular rule (no-duplicate-imports
) for TypeScript files in components
?
I wonder if we should add a placeholder README file with just a little text mentioning that this component is still experimental and should not be used in production? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes LGTM.
Feel free to merge once the pending comments are addressed
} ); | ||
|
||
const classes = cx( | ||
css( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a though: When isLayered: true
, the children elements are set to position: absolute
.
Should we consider setting the parent's position: relative
in that case?
const classes = cx( | ||
isLayered ? styles.positionAbsolute : styles.positionRelative, | ||
css( { | ||
marginLeft: ! isLayered && offset * -1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels a bit counter-intuitive to me that higher (positive) values of the offset
property bring the stacked items closer together, and lower (negative) values push the items further apart
It also looks like the offset
property does not affect the children when isLayered: true
. I would personally expect it to work regardless of the elements being layered or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a better name than offset? Or should the offset start from like... all of the items completely layered together and then as you increase offset it spreads them out? I'll have to think about how to make it work 🤔 It seems like isLayered
should just be the default, and maybe shouldn't exist as an offset of 0
in that case would make it be "layered" I'll fiddle with this a little bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what's difficult about this is that there's no clear way to make the offset just "the width of the item" unless you happent to know the width of the item. Maybe renaming offset
to overlap
would make more sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took some time to tinker around and potentially came up with a way that doesn't rely on the item's width:
- kept the name for the
offset
property, but changed the way it behaves. Anoffset
of 0 means "no changes to how the layout flows". A positive value means that the children are further apart from each other. A negative value means that the children are closer to each other - made the
offset
affect the layout also when theisLayered
and/orisReversed
properties aretrue
- as a consequence, removed the "hover" effect from the Storybook example, as in my opinion it was making it confusing to understand how the offset works (I find that using the knobs is a more clear way)
This is the diff of the changes that I came up with. Happy to discuss this more in details in a call!
diff --git a/packages/components/src/z-stack/component.tsx b/packages/components/src/z-stack/component.tsx
index fd9b90ec52..e38c8035e1 100644
--- a/packages/components/src/z-stack/component.tsx
+++ b/packages/components/src/z-stack/component.tsx
@@ -35,11 +35,11 @@ export interface ZStackProps {
*/
isReversed?: boolean;
/**
- * The amount of overlap between each child element.
+ * The amount of offset between each child element.
*
* @default 0
*/
- overlap?: number;
+ offset?: number;
/**
* Child elements.
*/
@@ -55,20 +55,23 @@ function ZStack(
className,
isLayered = true,
isReversed = false,
- overlap = 0,
+ offset = 0,
...otherProps
} = useContextSystem( props, 'ZStack' );
const validChildren = getValidChildren( children );
- const childrenCount = validChildren.length - 1;
+ const childrenLastIndex = validChildren.length - 1;
const clonedChildren = validChildren.map( ( child, index ) => {
- const zIndex = isReversed ? childrenCount - index : index;
+ const zIndex = isReversed ? childrenLastIndex - index : index;
+ const offsetAmount = offset * index;
const classes = cx(
isLayered ? styles.positionAbsolute : styles.positionRelative,
css( {
- marginLeft: ( ! isLayered && overlap * -1 ) || undefined,
+ ...( isLayered
+ ? { marginLeft: offsetAmount }
+ : { right: offsetAmount * -1 } ),
} )
);
@@ -87,17 +90,10 @@ function ZStack(
);
} );
- const classes = cx(
- css( {
- paddingLeft: ! isLayered ? overlap : undefined,
- } ),
- className
- );
-
return (
<ZStackView
{ ...otherProps }
- className={ classes }
+ className={ className }
ref={ forwardedRef }
>
{ clonedChildren }
diff --git a/packages/components/src/z-stack/stories/index.js b/packages/components/src/z-stack/stories/index.js
index 31d707d5db..52a4549035 100644
--- a/packages/components/src/z-stack/stories/index.js
+++ b/packages/components/src/z-stack/stories/index.js
@@ -1,7 +1,3 @@
-/**
- * WordPress dependencies
- */
-import { useState } from '@wordpress/element';
/**
* External dependencies
*/
@@ -42,20 +38,15 @@ const Avatar = ( { backgroundColor } ) => {
};
const AnimatedAvatars = () => {
- const [ isHover, setIsHover ] = useState( false );
- const overlap = number( 'overlap', 20 );
const props = {
- overlap: isHover ? 0 : overlap,
+ offset: number( 'offset', -20 ),
isLayered: boolean( 'isLayered', false ),
isReversed: boolean( 'isReversed', false ),
};
return (
<HStack>
- <View
- onMouseLeave={ () => setIsHover( false ) }
- onMouseEnter={ () => setIsHover( true ) }
- >
+ <View>
<ZStack { ...props }>
<Avatar backgroundColor="#444" />
<Avatar backgroundColor="#777" />
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As agreed, I committed the changes suggested above (plus changing the default value of isLayered
to true
) in 045d370
Also, noting that some e2e tests are failing, but that the failures don't seem related to the changes in this PR |
Co-authored-by: Marco Ciampini <[email protected]>
045d370
to
437ab9a
Compare
…-take-2 * trunk: (57 commits) Image block: fix cover transform and excessive re-rendering (#32102) compose: Add types to useMergeRefs (#31939) Navigation: Fix collapsing regression. (#32081) components: Promote Elevation (#31614) compose: Add types to useReducedMotion and useMediaQuery (#31941) Update the graphic that appears in the Template Editor welcome guide (#32055) Block Navigation: use CSS for indentation with known max indent instead of spacer divs (#32063) Fix broken template part converter modal styles. (#32097) compose: Add types to `usePrevious` (#31944) components: Add ZStack (#31613) components: Fix Shortcut polymorphism (#31555) compose: Add types to `useFocusReturn` (#31949) compose: Add types to `useDebounce` (#32015) List View: Simplify the BlockNavigation component (#31290) Remove query context leftovers (#32093) Remove filter_var from blocks (#32046) Templates: Remove now-obsolete gutenberg_get_template_paths() (#32066) [RNMobile] Enable reusable block only in WP.com sites (#31744) Rename ViewOwnProps to PolymorphicComponentProps (#32053) Rich text: remove inline display warning (#32013) ...
Description
Adds a new ZStack component.
How has this been tested?
Storybook.
Screenshots
Types of changes
New feature.
Checklist:
*.native.js
files for terms that need renaming or removal).