-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Tokens: New Experimental Feature #7552
Conversation
…ering side-by-side.
…ve "old" experiment Button approach.
…tyling issues to be resolved.
…ys. Miscellaneous cleanup.
…ke Tokens optional.
fontSize: '20px', | ||
boxSizing: 'border-box', | ||
width: '2.2em', | ||
height: '1em', |
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'm not sure why these EM values are here. Not a change for this pr but something maybe we can look into.
This is awesome!!! |
WOOT! |
Great to see this go in @JasonGore ! :D |
🎉 Handy links: |
🎉 Handy links: |
🎉 Handy links: |
🎉 Handy links: |
I have one question about how the tokens are defined? I read the first post but maybe I missed something. For example: export interface IButtonTokens {
color?: string;
colorHovered?: string;
colorPressed?: string;
iconColor?: string;
iconColorHovered?: string;
iconColorPressed?: string;
...
} Why <Button
styles={{
icon: {
fontSize: 'large',
color: 'black',
fill: 'black'
},
menuIcon: {
color: 'black'
},
}}
/>
<Button
tokens={{
iconSize: 'large',
iconColor: 'black'
}}
/> Will |
We are adding tokens as we work on the new Documentation has since been added regarding |
Pull request checklist
$ npm run change
Overview
This PR introduces tokens and incorporates the evaluation of tokens and styles with slots while avoiding unnecessary styles preprocessing in parent component construction.
This PR is beefy. I went into this thinking it'd be roughly the same size as the Slots PR but it ended up being significantly bigger for the following reasons:
What are Tokens?
Tokens are similar to styles in that they affect styling of a component. The difference is that tokens are props "knobs" that can be more simply used to affect the styling of the component.
Tokens are presented as a
tokens
prop in a component's prop interface. For example, button's tokens appear in types as follows:And then via use of
IStyleableComponentProps
,tokens
prop is automatically added to the props interface viaIButtonTokens
type argument.And
IStyleableComponentProps
definestokens
as:So for example where styles would have to be used to do Button styling:
With tokens it's more simply:
Tokens are very similar to styles in that they can either be objects or functions that take in props and theme as arguments:
Why Tokens?
Using
styles
props requires knowledge of component styling implementation, such as knowledge of all of the style sections and their specific styling code. This approach tends to be fragile, breaking easily whenever the styling of the component is modified.Tokens are intended to be black box props "knobs" that devs can use at a higher level. The component is responsible for mapping their token specification to component styling. A component's style sections and implementation can change without breaking or regressing existing token usage.
Tokens vs. Styles
Our goal is for
tokens
to be the primary method for component consumers to style and theme components with thestyles
prop being used as a fallback for niche scenarios.Tokens, however, are a full complement to styling and both can be used side-by-side very easily. Tokens add another stage to the styling pipeline, converting props input into styling output.
Props => Tokens processing => Styles processing => classname generation
Notable PR Items:
Tokens Naming (vs. styleVariables / styleVars)
Foundation Changes
Existing Foundation preprocesses styling for all of its child components on render by using
mergeStyleSets
. However, with the addition of slots, component consumers now have access to every slot's component styles. This leads to extra style processing because slot component styles have to be merged again as slots are rendered.This PR substantially changes the styling approach made by
createComponent
.createComponent
now only merges styles targeted to itsstyles
prop and does not preprocess any styling targeted towards slotted components. The slots utilities have been modified to callmergeStyles
as slots are rendered, taking into account anystyles
props passed directly to the slot by the component consumer.For now, this new
createComponent
resides only inexperiments
package, but is intended to fully replace Foundation after this PR has been reviewed and tested.Slots and Styles
Slots and Styles are now bound concepts. The approach is that any part of a component that can be styled should also be a slot. Styles interfaces can simply be defined as
IComponentStyles<ISlotProps>
.If devs don't want to use slots but want to have style sections, they can still use existing
styled
approach with use ofgetClassNames
/classNamesFunction
.Example definition:
Styles Function Signatures Changed
Theme is now broken out as a separate argument for styles functions as opposed to being a props mixin. This is also consistent with tokens functions.
Token Function/Object Signature
Tokens now can be functions or objects similar to styles.
Intrinsic Slots vs. Component Slots
Similar to existing
styled
components, all slots / style sections of a component can be styled through itsstyles
prop, regardless of the type of element contained in the slot.However, now that
styles
props of all slotted components are also exposed, there are additional considerations to give to styling behavior. Slots currently are defined as either an intrinsic element or a Fabric component. This meansstyles
props can't be passed directly to intrinsic element slots as this will generate a TS error. (The key difference here is thestyles
prop of the slotted component as opposed to thestyles
prop of the component containing the slots.)For example, for an intrinsic root slot that is a
div
by default:If we want to allow a given slot to be both an intrinsic element and a Fabric component, we'll lose some type safety and Foundation will have to be modified to process tokens and styles before they are passed on to intrinsic elements. For now, devs that want to directly interact with an intrinsic slot's can use
className
andmergeStyles
as similar to how they are already used forstyled
components.Implicit Props
styles
,tokens
,theme
,className
are implicitly made available viaIStyleableComponentProps
, which component props can optionally extend. This means devs don't have to explicitly add any of these props to their component's prop interfaces.Nested Shorthand Works (!)
which allows for:
instead of having to do:
TODOs (within PR)
TODOs (after this PR)
Button
) have been converted to slots, but have not been "tokenified".tokens
defined for them.Microsoft Reviewers: Open in CodeFlow