-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
refactor(theme): update config for extendBaseTheme
#9681
refactor(theme): update config for extendBaseTheme
#9681
Conversation
const { | ||
Accordion: accordionDefaultTheme, | ||
Avatar: avatarDefaultTheme, | ||
Badge: badgeDefaultTheme, | ||
Breadcrumb: breadcrumbDefaultTheme, | ||
Button: buttonDefaultTheme, | ||
Checkbox: checkboxDefaultTheme, | ||
CloseButton: closeButtonDefaultTheme, | ||
Code: codeDefaultTheme, | ||
Divider: dividerDefaultTheme, | ||
Drawer: drawerDefaultTheme, | ||
Form: formDefaultTheme, | ||
FormLabel: formLabelDefaultTheme, | ||
Heading: headingDefaultTheme, | ||
Input: inputDefaultTheme, | ||
Link: linkDefaultTheme, | ||
List: listDefaultTheme, | ||
Menu: menuDefaultTheme, | ||
Modal: modalDefaultTheme, | ||
Select: selectDefaultTheme, | ||
Spinner: spinnerDefaultTheme, | ||
Switch: switchDefaultTheme, | ||
Table: tableDefaultTheme, | ||
Tabs: tabsDefaultTheme, | ||
Tag: tagDefaultTheme, | ||
} = theme.components |
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.
Import aliases used for consistency, as some of these defaults are exported to custom component configs.
The rest are imported to retain the current UI with all Chakra components used that have themes, and includes themes for components that may be used later as the UI migration continues and other refactoring needs.
It is possible that this list could be trimmed down with any discovery of themes that are not actually needed.
export function defineMergeStyles( | ||
defaultTheming?: SystemStyleObject, | ||
...styleObjs: SystemStyleObject[] | undefined[] | ||
) { | ||
return merge(defaultTheming, ...styleObjs) | ||
} |
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.
This function was created for re-usability to handle merging of default styles with custom stylings. It uses the lodash merge
function to handle recursive merging to prevent unexpected overrides.
Though this works as intended, I believe this could be improved, as there are multiple circumstances that this would be used in.
Ex. 1: Simple merge
// From custom Link config
baseStyle: defineMergeStyles(linkDefaultTheme.baseStyle, {
color: "primary",
textDecoration: "underline",
_focus: {
boxShadow: "none",
},
_focusVisible: {
boxShadow: "none",
outline: "auto",
},
},
})
Ex. 2: Style function props needed to be passed to a default theme that uses some of those props (type error throws otherwise)
// From custom Button config
const variantOutline = defineStyle((props) =>
defineMergeStyles(defaultVariants?.outline(props), commonOutline)
)
Ex. 3: There may be a circumstance where a default baseStyle would be combined with a default variant because the component may not use other variants in the project, thereby compacting the custom config.
const baseStyle = defineMergeStyles(
defaultBaseStyle,
defaultVariant.outline,
{
// Custom styles
}
)
NOTE: There is a mergeThemeOverride that is available from Chakra that essentially does the same thing, but it doesn't have any type safety.
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.
Awesome. Would love to have this documented somewhere...I feel bad to lose this doc in this PR.
======
On the other hand, merge
will return any
, taking away the whole purpose of this function I believe. Shouldn't we do something like:
🤔
export function defineMergeStyles( | |
defaultTheming?: SystemStyleObject, | |
...styleObjs: SystemStyleObject[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) | |
} | |
export function defineMergeStyles( | |
defaultTheming?: SystemStyleObject, | |
...styleObjs: SystemStyleObject[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) as SystemStyleObject | |
} |
or
export function defineMergeStyles( | |
defaultTheming?: SystemStyleObject, | |
...styleObjs: SystemStyleObject[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) | |
} | |
export function defineMergeStyles<T extends SystemStyleObject>( | |
defaultTheming?: T, | |
...styleObjs: T[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) as T | |
} |
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.
Awesome. Would love to have this documented somewhere...I feel bad to lose this doc in this PR.
I can put this up in the PR description as Additional Information
😃
With your second suggestion, this approach will return a type equivalent only to the first object, which would be the default theme, and therefore lock down what the second object could have in its properties.
With the first suggestion, this will throw a type error in configs where the function is used in a defineMultiStyleConfig
property.
For example, the sizes
property in the Button theme config. The error thrown here:
Type 'SystemStyleObject' is not assignable to type 'Dict<SystemStyleInterpolation> | undefined'
Dict
is currently a private type in Chakra, but it's simply
type Dict<T = any> = {
[ x: string ]: T
}
We could apply this assertion on the return, written as Record<string, SystemStyleObject>
which will work everywhere.
export function defineMergeStyles(
defaultTheming?: SystemStyleObject | unknown,
...styleObjs: SystemStyleObject[] | unknown[]
) {
return merge(defaultTheming, ...styleObjs) as Record<string, SystemStyleObject>
}
Note that for both params, I am also using unknown
for any object that is inferring as an object or undefined. (Type error throws otherwise because of either an object mismatch for defaultTheming
or of the array type for styleObjs
, if that makes sense)
✅ ethereum-org-website-dev deploy preview ready
|
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.
Amazing @TylerAPfledderer!
A few minor observations but this looks really nice. GJ
|
||
const variantSecondary: SystemStyleObject = { | ||
const { baseStyle: defaultBaseStyle, sizes: defaultSizes } = badgeDefaultTheme |
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.
const { baseStyle: defaultBaseStyle, sizes: defaultSizes } = badgeDefaultTheme | |
const { baseStyle: defaultBaseStyle } = badgeDefaultTheme |
|
||
export const Button = defineStyleConfig({ | ||
baseStyle, | ||
sizes: defineMergeStyles(defaultSizes, { | ||
md: { | ||
h: 42, |
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.
This was my mistake, this should be
h: 42, | |
h: "42px", |
const { baseStyle: defaultBaseStyle } = checkboxDefaultTheme | ||
|
||
const { definePartsStyle, defineMultiStyleConfig } = | ||
createMultiStyleConfigHelpers(checkboxAnatomy.keys) |
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.
Interesting, nice.
mt: "0.25rem", | ||
}, | ||
}, | ||
alignTop: variantAlignTop, |
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.
alignTop: variantAlignTop, | |
// TODO: remove this variant | |
alignTop: variantAlignTop, |
@@ -1,46 +1,69 @@ | |||
import { StyleFunctionProps } from "@chakra-ui/react" | |||
import type { ComponentStyleConfig } from "@chakra-ui/theme" | |||
import { createMultiStyleConfigHelpers, defineStyle } from "@chakra-ui/react" |
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.
import { createMultiStyleConfigHelpers, defineStyle } from "@chakra-ui/react" | |
import { createMultiStyleConfigHelpers } from "@chakra-ui/react" |
export function defineMergeStyles( | ||
defaultTheming?: SystemStyleObject, | ||
...styleObjs: SystemStyleObject[] | undefined[] | ||
) { | ||
return merge(defaultTheming, ...styleObjs) | ||
} |
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.
Awesome. Would love to have this documented somewhere...I feel bad to lose this doc in this PR.
======
On the other hand, merge
will return any
, taking away the whole purpose of this function I believe. Shouldn't we do something like:
🤔
export function defineMergeStyles( | |
defaultTheming?: SystemStyleObject, | |
...styleObjs: SystemStyleObject[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) | |
} | |
export function defineMergeStyles( | |
defaultTheming?: SystemStyleObject, | |
...styleObjs: SystemStyleObject[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) as SystemStyleObject | |
} |
or
export function defineMergeStyles( | |
defaultTheming?: SystemStyleObject, | |
...styleObjs: SystemStyleObject[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) | |
} | |
export function defineMergeStyles<T extends SystemStyleObject>( | |
defaultTheming?: T, | |
...styleObjs: T[] | undefined[] | |
) { | |
return merge(defaultTheming, ...styleObjs) as T | |
} |
@@ -37,4 +49,8 @@ export const Tag: ComponentStyleConfig = { | |||
}, | |||
custom: {}, // empty variant |
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.
custom: {}, // empty variant | |
// TODO: remove this variant, as it doesn't exist on the DS | |
custom: {}, // empty variant |
Not a big deal but I was analyzing the final bundles and noticed that the size had an unexpected result. They have basically the same size.
This PR build ( I was expecting a smaller size overall but we got an even slightly heavier one. Do you know what could be the reason? maybe is that we are not excluding a lot of Chakra components after all? 🤔 But again, not a big deal, regardless of the bundle size, I think this is a great improvement to reduce the number of theme styles we have. |
@pettinarip I think it would still be hard to say at this point. It makes sense if the lack of excluded default component themes being imported, but I am expecting some trimming from the imports after starting work on PRs for the form elements, tags, tables, and avatars with their theming. I would still find the results not telling when styled-components and the direct inclusion of emotion still a part of the package. Maybe it doesn't make a difference here! I think what would be good for the Chakra team is to keep record of at least three bundle size points:
I'm not sure if this will make a difference, but what if indeed I allowed the rendering of I've argued that this provider is a redundancy but would also be good to notate that result. I wanted to save these bundle size notes for the case study so it's worth bringing this up 😁 |
@TylerAPfledderer cool. Then, are you ok if I merge this PR? lgtm. After that, you can play around with |
@pettinarip yes, go ahead and merge! 🚀 |
Description
Applies Chakra's
extendBaseTheme
function for the custom config and updates the config to reflect this change.extendTheme
is to not immediately include all of the default component themes.Certainly open for trimming any of this, either now or in a future PR.
Related Issue
Closes #9679