-
Notifications
You must be signed in to change notification settings - Fork 51
fix(Button): icon colors and layout #135
Changes from 2 commits
7689f77
f81b239
aeded91
05fe3fc
66dab28
cc35644
7627b6c
a048e8e
a4f5d32
94a0606
c1d5714
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,10 +92,20 @@ class Button extends UIComponent<any, any> { | |
| accessibility: ButtonBehavior as Accessibility, | ||
| } | ||
|
|
||
| public renderComponent({ ElementType, classes, accessibility, rest }): React.ReactNode { | ||
| public renderComponent({ | ||
| ElementType, | ||
| classes, | ||
| accessibility, | ||
| variables, | ||
| rest, | ||
| }): React.ReactNode { | ||
| const { children, content, disabled, iconPosition } = this.props | ||
| const hasChildren = childrenExist(children) | ||
|
|
||
| if (hasChildren) { | ||
| return children | ||
| } | ||
|
|
||
| return ( | ||
| <ElementType | ||
| className={classes.root} | ||
|
|
@@ -104,21 +114,27 @@ class Button extends UIComponent<any, any> { | |
| {...accessibility.attributes.root} | ||
| {...rest} | ||
| > | ||
| {hasChildren && children} | ||
| {!hasChildren && iconPosition !== 'after' && this.renderIcon()} | ||
| {!hasChildren && content} | ||
| {!hasChildren && iconPosition === 'after' && this.renderIcon()} | ||
| {iconPosition !== 'after' && this.renderIcon(variables)} | ||
| {content && <span className={classes.content}>{content}</span>} | ||
| {iconPosition === 'after' && this.renderIcon(variables)} | ||
| </ElementType> | ||
| ) | ||
| } | ||
|
|
||
| public renderIcon = () => { | ||
| public renderIcon = variables => { | ||
| const { disabled, icon, iconPosition, content, type } = this.props | ||
|
|
||
| return Icon.create(icon, { | ||
| defaultProps: { | ||
| xSpacing: !content ? 'none' : iconPosition === 'after' ? 'before' : 'after', | ||
| variables: { color: type === 'primary' && !disabled ? 'white' : undefined }, | ||
| variables: { | ||
| color: | ||
| type === 'primary' | ||
| ? variables.typePrimaryColor | ||
| : type === 'secondary' | ||
| ? variables.typeSecondaryColor | ||
| : variables.color, | ||
| }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any variables or styles used directly in a component's logic implicitly become part of a global theming interface. All themes will have to implement I think all theming values and theming logic should live in the theme's files. This way, each theme is free to choose the values and logic behind their styles. The question is how? Proposal 1 - Component part variablesComponent variables files could define variables for each component parts as well. Then, variable values and logic for component parts can be left to the theme and not dictated to all themes by the component. Here's an example of the Button theme defining an // themes/teams/components/Button/buttonVariables.tsx
export default (siteVariables) => {
const variables = {
color: undefined,
typePrimaryColor: siteVariables.white,
typeSecondaryColor: siteVariables.black,
}
variables.icon = {
color:
type === "primary"
? variables.typePrimaryColor
: type === "secondary"
? variables.typeSecondaryColor
: variables.color
}
return variables
}Now, the component simply implements a contract that says "we pass variables[part] to each component part": // Button.tsx
Icon.create(icon, {
defaultProps: {
variables: variables.icon
}
})This would also allow us to do this consistently for all components, including the styles for each component part. That then would allow us to write a conformance test for it. This would make the API easier to understand and work with as well since there is only one concept, "components pass variables/styles to each component part". Proposal 2 - A high-level theme interfaceThis proposal would introduce a new concept. Something like a lightweight theme interface that is allowed to pass between components. It would consist of The Button in this case would define these three values for its bounds. Then, they would passed to the Icon. There are a lot more considerations here, but I'm less in favor of this pattern for the problem at hand so I'll leave it here for now. Thoughts?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, agree with the reasons provided above, thanks - this goes in line with the exactly the same discussion we've had with Miro. For the sake of avoiding to introduce additional complexity at that moment we've decided to move forward with the simplest approach that would indicate our intent to pass variables to child component, and after that introduce changes in a way that theming aspects will be completely separated from logic. Speaking of the options suggested - I would definitely support the first one, as it suggest clear path that not changes but extends approach we are using now - and, thus, it is not associated with significant complexity increase. Also, with this one we will be able to address quite broad set of scenarios we are currently struggling with (or using the approach where variables are coupled with implementation) Not saying 'no' to the second option, though - but would rather wait once this concept will solidify in our minds, for the sake of us being absolutely sure about what we are buying for additional efforts laid in this direction, as well as whether this concept is able to cover the cases we are interested in (and how flexible it would be to cover potentially emerged edge-cases)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for the sake of progressing with that, let me suggest the following steps:
This will allow us to progress with fixes, as well as split these subsequent changes so that it would be easier to review them. Please, let me know what do you think about it. Thanks!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed, let's merge this |
||
| }, | ||
| }) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ export interface IButtonVariables { | |
| height: string | ||
| minWidth: string | ||
| maxWidth: string | ||
| color: string | ||
| backgroundColor: string | ||
| backgroundColorHover: string | ||
| circularRadius: string | ||
|
|
@@ -25,6 +26,7 @@ export default (siteVars: any): IButtonVariables => { | |
| height: pxToRem(32), | ||
| minWidth: pxToRem(96), | ||
| maxWidth: pxToRem(280), | ||
| color: undefined, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems strange to have an undefined variable that is also never set to a value. Is there not a siteVariable available for this value? In either case, what is the motivation for this variable?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the motivation for this variable is to allow to customize Button's color (where 'color' comes in general sense, not something that is tied to corresponding CSS property only). This will open way for the following customization scenarios, as well as allow to customize this aspect of <Button variables={{ color: 'red' }} ... />
Yes, let me initialise it with an appropriate site variable - the reason haven't done it before is because it was unclear to me at this moment which ones will be provided by teams theme |
||
| backgroundColor: siteVars.gray08, | ||
| backgroundColorHover: siteVars.gray06, | ||
| circularRadius: pxToRem(999), | ||
|
|
||
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.
If I now do:
Won't this result in rendering the text "Click me" only? We'd still want to wrap the text in an
ElementTypeand apply our classes/accessibility/rest props.