Introduce a common API to style Button from both web and mobile#19104
Introduce a common API to style Button from both web and mobile#19104
Conversation
|
@dratwas I know you just started this. Just wanted to say that I'm really excited to see this happening :D |
f8b4bf3 to
d9b7907
Compare
|
There are notes made by @pinarol during our conversation about that PR. We will add the PrimitiveButtonStatesWe’ll have a defined set of states:
Each should be documented for each platform, not every one of them has to be available for both mobile and web but they should be limited to what has defined. We should:
This can be similar to: additionalStyles={[{ states: 'focus:hovered:visited', styles: {...} }]}State changesWe’ll provide event handlers to state changes if possible. Needs investigation. Icons & LabelsIcons or labels won’t be part of classnameWe should have the ::after ::before VisibilityThis component will be public as it has some use cases in some plugins: https://github.com/Automattic/jetpack/blob/master/_inc/client/components/button/style.scss CSS propThere won’t be any css prop since it is violating x-platform usage. components/Button
<Button link marginLeft={5} height={50} >
<Text>Some text </Text>
</Button>...will render a link button with 2 difference only:
|
|
|
||
| export default function BlockBreadcrumbButton( { children, ...props } ) { | ||
| const theme = useTheme(); | ||
| const additionalStyles = [ |
There was a problem hiding this comment.
Is this for things that don't translate to mobile?
There was a problem hiding this comment.
Since we don't want to expose the css prop in public API, there is no way to set styles for i.e hover, focus states. Our first idea was to use props like hoverStyle, activeStyle ... but these styles can be mixed so we will end with hoverFocusActiveEnabledStyle and that would be hard to use. So we decided to add additionalStyles prop where we can set styles for different states.
There was a problem hiding this comment.
So these work for mobile too?
There was a problem hiding this comment.
The short answer is “yes”, but not all of them. For example “hover” is invalid for mobile as there’s no cursor. We should have done a better job documenting these states. I’ll add it to this PR.
| border={ 'none' } | ||
| outline={ 'none' } | ||
| padding={ 'medium' } | ||
| margin={ 0 } |
There was a problem hiding this comment.
I get that we want these props for a primitive but I don't feel very good having these leak to a higher-level abstraction (UI components) I'd rather have variations in the component itself.
There was a problem hiding this comment.
I think we can really use your and other reviewers’ guidance at this point about how to make this better. We also had concerns about overwriting styles for variants like isPrimary, isSecondary, however, we found in many places that Button style is overridden in CSS in addition to using variants, like here or here. The idea behind this is, being able to meet the same need in an x-platform way. Otherwise, those kinds of customizations will not work on mobile. We could refactor these Buttons that have overridden styles to use PrimitiveButton instead but it will require a lot of extra work. I really like what @pinarol suggested to put all styling params like margin, padding (not sure about additionalStyles) etc. to one and call it experimentalStyles, in that way we will expose only one prop in public API, WDYT about it?
There was a problem hiding this comment.
however, we found in many places that Button style is overridden in CSS in addition to using variants, like here or here.
For me instead of doing that, I prefer if we should be looking at why we did these overrides in the first place and avoid them entirely with better abstractions/components/variations. These overrides quickly lead to bugs anyway.
There was a problem hiding this comment.
This was something we were questioning as well, “should we allow overriding the styles already defined in variants”? The ideal answer to this is actually “no”, this is also how syled-system variants page recommends: https://styled-system.com/variants given that you are sharing a similar opinion I think we can remove the props that are already defined by variants. However, we’ll still need to provide some props to be able to position the Button in a x-platform way like here or here. Positioning/layout related props need to be available among all x-platform components not just Button, and those are: space, layout, flexbox, position from https://styled-system.com/api Otherwise we won’t be able to provide an x-platform component, wdyt?
There was a problem hiding this comment.
I'm not certain I understand exacly why we need the positionning props absolutely. There are alternatives, Layout components (flex containers aware of their children,toolbars...). I'm not saying we won't ever need these but I believe it's better to start with no CSS props at all and consider use-case per use-case if there are better alternatives.
There was a problem hiding this comment.
There are alternatives, Layout components (flex containers aware of their children,toolbars...).
Agree, but sometimes it's not enough and the 'margin', 'width' etc are needed. At this moment they are set in CSS like here but we are not able to do the same on mobile. So we would need to wrap the button into some container (View) and add the margins to the container which is not performant and adds one more nesting level.
I'm not saying we won't ever need these but I believe it's better to start with no CSS props at all and consider use-case per use-case if there are better alternatives.
That's actually a good idea to do less in that PR. We could get rid of these props and then add them if needed during refactoring. However, I still feel like adding the spacing props will be one of the first things that will happen. There is a small part of the list of components that overrides these styles:
I also checked for example the rebassjs lib that is UI component library and they allow to set i.e margin to button that is primary https://rebassjs.org/button/
There was a problem hiding this comment.
Actually, we referred to the already existing css customizations for Button component while adding the new style props. However I am now discovering that we actually don't quite approve most of those customizations either. What I am confused about is, isn't this a good reason to lean towards to a more encapsulated API design?
If we hide the css inside the component and manage styles via props we’ll have a possibility to deprecate/remove those which we don't want to be overridden.
Currently we are discussing what to “expose” in the API and I think it is a very valuable discussion to have. But doesn’t current state already expose every overriding possibility by providing the className publicly in the API? Also as far as I see we are already tied to a specific class name(components-button), just to provide overriding capabilities I assume?
If we look at it this way this PR actually isn’t extending what is already exposed. On the contrary I think it can be a first step to be in control of what to expose in the future.
Having said that, I think it’d be good to group style related props under one experimental prop at this stage, that would make us more free about trying different possibilities.
There was a problem hiding this comment.
About having margins/width/height in the API: I am thinking what can be the alternative approach?
- Designing the Button in such a way that always fills the container?
This requires putting a container per every Button just to be able to set margins/width/height, thus, doesn’t feel right.
- Determining margins/width/height inside the implementation, so nobody would be able to override?
And this doesn’t look like a realistic goal considering almost every usage of Button sets a different margin. Plus, I believe it’s a fair need to change the margins/width/height of the component.
packages/components/src/index.js
Outdated
| G, | ||
| HorizontalRule, | ||
| BlockQuotation, | ||
| PrimitiveButton, |
There was a problem hiding this comment.
I left these exports here only for Backward compatibility, ideally we should just consume the primitives from the primitives package.
Let's not expose other primitives here.
packages/components/src/index.js
Outdated
| export { default as withNotices } from './higher-order/with-notices'; | ||
| export { default as withSpokenMessages } from './higher-order/with-spoken-messages'; | ||
| export * from './text'; | ||
| export { useTheme, default as ThemeProvider } from './theme-provider'; |
There was a problem hiding this comment.
This probably needs more time to mature as it's the first CSS in JS public API, can we start with experimental APIs?
|
|
||
| export default ( { theme, children } ) => ( | ||
| <ThemeProvider theme={ getTheme( theme ) }>{ children }</ThemeProvider> | ||
| ); |
There was a problem hiding this comment.
Since this introduces theming, I'd like to know more (and maybe even document) how do we build themable components, how are we planning to update our UI components to be themable and how to use these APIs in general.
youknowriad
left a comment
There was a problem hiding this comment.
Nice work here.
Let's give this PR more visibility in the next #core-js #core-css chats and among the @WordPress/gutenberg-core team as it can be impactful.
|
Hey @gziolo, unfortunately, I do not know the status of this proposal since we were waiting for the decision from gutenberg/core team. I started doing other tasks and we never got answers to our questions ;( I believe it is still valid even though it was a year ago. What I can suggest is to start from resolving conflicts then revisit all button styles (web and mobile) as I did previously and add new variants if any. There is also an important discussion about props that can be passed to the components: #19104 (comment) |
|
cc @chipsnyder |
|
@dratwas, thank you for the update. It looks like this topic didn't get enough attention. @ItsJonQ is leading efforts to create a new component system designed with the goal to become the primary way to build UIs. He is working on an official proposal to have it included in the WordPress core. At the moment, it's web-only, but it uses the architecture which should make it possible to integrate it with mobile in a similar way as here. @ItsJonQ and @sarayourfriend should move the code that abstracts styles to the repository quite soon. All the code for the component system is located in the following folder |
|
Thanks for the mention @gziolo ! For added context, the Style system for the new component system can be found here: As @gziolo mentioned, it will be moved over to Under the hood, it's using Emotion (v10), just like our current solution. It's not something I've explored yet. My personal RN experience has been limited to the Expo development experience. |
Description
This is an exploration of x-platform style system. wordpress-mobile/gutenberg-mobile#1411
This is the second iteration on wordpress-mobile/gutenberg-mobile#1386
Mobile side PR: #19179
In this PR I used
styled-systemwithemotionto create a primitive Button component that could be used in web and mobile and could be styled via props.Aandbuttoncomponents since both of them are used in@components/Button. They acceptclassNameas a prop to be backward compatibility ( we need to support already existing themes ) and all style props that are supported bystyled-systemPrimitiveButtonthat is described here - Introduce a common API to style Button from both web and mobile #19104 (comment)Boxcomponent to replacediv#17614 )@components/Button(after that all buttons uses the primitives)BlockBreadcrumbButtoncomponents that use PrimitiveButton instead of@components/Buttonjust to demonstrate.How has this been tested?
BlockBreadcrumbButtonlooks correct with and without hover/focusScreenshots
The

BreadcrumbButtoncomponent that usesPrimitiveButtonwithadditionalStylesprop to addhover,focusedstyles - https://github.com/WordPress/gutenberg/pull/19104/files#diff-21bd8baf92167b81915be200a8dd9eb8:hover
:hover:focus
:hover:focus:active
The
Inserterbutton that uses@components/Buttonwith some changed styles byadditionalStylesandstyled-systemprops - https://github.com/WordPress/gutenberg/pull/19104/files#diff-c6139f159c9b2b79af303587407aea51:hover
:hover:focus
:hover:focus:active
Types of changes
Experimenting with
emotionandstyled-systemPrimitiveButton checklist
onFocus,onBlurto determine thefocusstate. MouseEvents to determine theactiveandhoverstate. We specify whether the button is enabled or disabled by prop so we don't need to listen to that change. The only state left isvisitedbut I'm not sure if we can get that information somehow and also if thevisitedis also applicable to button or only to theaelement.components/Button checklist
marginLeftin theinserterbutton, this is not applied because of styles that are declared in a different place and are more specific (i think it should work like that because of themes that can override styles) but they override styles that are declared incomponents/ButtonChecklist: