-
Notifications
You must be signed in to change notification settings - Fork 55
feat(icons): add support for styling SVG icons #183
Conversation
Codecov Report
@@ Coverage Diff @@
## master #183 +/- ##
==========================================
+ Coverage 67.82% 68.08% +0.25%
==========================================
Files 101 113 +12
Lines 1386 1438 +52
Branches 265 268 +3
==========================================
+ Hits 940 979 +39
- Misses 443 456 +13
Partials 3 3
Continue to review full report at Codecov.
|
svg: ({ variables: v }): ICSSInJSStyle => ({ | ||
fill: v.color, | ||
}), | ||
svg: getSvgStyle('svg'), |
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.
yes-yes, let me guess what you might think about :) Actually, this is rather a 'have to' thing, because currently we don't have any possibility to introduce variable set of style parts, such that, for example, if props.name
is 'endCall' (a name of icon), there would be only parts in styles that are relevant to that icon (root
, phone
, cross-line
, etc). However, there are couple of things we should consider before, potentially, making this move:
- if set of styling parts will be decided by values from
props
, it will drastically complicate overall picture - one thing that immediately comes to my mind is increased debugging complexity - problem of hardcoded style parts - the ones that should fit all component from provided set, actually, is not that serious: generally there are just handful different parts of the icon that should be styled differently at any given moment, and these parts are entirely theme's aspects: there are no restrictions introduced from core components' functionality on how these style parts should be named, organised or consumed
With that being said, I rather see suggested approach as being flexible enough to meet quite broad set of introducing styles for custom set of icons.
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.
Should we add at least first add as many paths properties here as there is in our svg icons so far, and add increase the number of them accordingly if we are adding icons with multiple path parts? Maybe we can generate the paths properties in the begging of the file in order to avoid them being added like this?
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.
Maybe we can generate the paths properties in the begging of the file in order to avoid them being added like this?
yes, but this leads to exact problem I've described above - where the solution is to somehow allow variable amount of component parts being declared for styles (ideally, this number should be dependent on props). While it is an option, there are some drawbacks associated with it - have mentioned them above.
Should we add at least first as many paths properties here as there is in our svg icons so far, and add increase the number of them accordingly if we are adding icons with multiple path parts
we may consider to do this, yes
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 we have just as many paths properties as our svg icons actually have, I am okay with them being hardcoded, I see your point. With this, we will be aware about what each of those represent.
// SVG Icons | ||
// ======================================================== | ||
|
||
type Classes = { [iconPart: string]: string } |
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 seems to be like a general type that can be reused in some other places. Should we change the definition with something like type Classes = { [componentPart: string]: string }
and place it in the utils section? If not, maybe we should change the name to IconClasses in order to be more specific.
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.
yes, thanks - let me make this move if we'll agree on the general approach
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.
Note, this type exists in this file already:
src/themes/teams/index.ts
Outdated
import { default as svgIconsAndStyles } from './components/Icon/svg' | ||
import { IconSpec } from './components/Icon/svg/types' | ||
|
||
const svgIcons = Object.keys(svgIconsAndStyles as { [iconName: string]: IconSpec }).reduce< |
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 this worth converting to a type: { [iconName: string]: IconSpec }
|
||
export default { | ||
icon: classes => ( | ||
<svg viewBox="0 0 32 32" role="presentation" focusable="false" className={classes.svg}> |
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.
Should we pass the classes to the svg element here?
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.
yes - but this is intentionally left to icons' maintainers, as current system (where both CSS class selectors and DOM selectors are used for styling) should be refactored
export default (classes => ( | ||
<svg viewBox="0 0 32 32" role="presentation"> | ||
<path | ||
d="M22.5,9h-13C8.672852,9,8,9.672852,8,10.5v9C8,20.327148,8.672852,21,9.5,21H13c0.276367,0,0.5-0.223633,0.5-0.5 |
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.
Should we pass the classes to the svg element and the paths here? Is this where the path1, path2 etc. objects from the iconStyles will be used?
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 this where the path1, path2 etc. objects from the iconStyles will be used?
yes, exactly. I would leave this work to icons' maintainers, as well as making final decision on how styling parts should be named for icons. Once we'll agree that provided mechanisms are sufficient enough to meet their needs, the task will reduce only to styling aspects that I would rather prefer to be addressed by design folks
svg: ({ variables: v }): ICSSInJSStyle => ({ | ||
fill: v.color, | ||
}), | ||
svg: getSvgStyle('svg'), |
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.
Should we add at least first add as many paths properties here as there is in our svg icons so far, and add increase the number of them accordingly if we are adding icons with multiple path parts? Maybe we can generate the paths properties in the begging of the file in order to avoid them being added like this?
Heads up for the future: For RTL we will need to be able to flip certain icons, for example pointing arrows. It should be possible to do this in a generic way (applying css transformations on the svg). It is important that approach proposed in this PR will allow us to do that in the future. |
@jurokapsiar, this is a very good point. With provided functionality we have couple of ways to address that, essentially
|
src/lib/mergeThemes.ts
Outdated
@@ -159,6 +160,9 @@ const mergeThemes = (...themes: IThemeInput[]): IThemePrepared => { | |||
|
|||
acc.componentStyles = mergeThemeStyles(acc.componentStyles, next.componentStyles) | |||
|
|||
// Merge icons set, last one wins in case of collisions | |||
acc.svgIcons = { ...acc.svgIcons, ...(next.svgIcons || {}) } |
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.
UTs?
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, will introduce them once we will agree on the approach
export { default as call } from './call' | ||
export { default as callEnd } from './callEnd' | ||
|
||
export { default as callVideo } from './callIncomingVideo' |
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.
What's the reason for exporting with a name different from filename?
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.
the reason was to save mapping from the icon that is provided (with simple name) to the one that was originally used by Teams (longer name) - with that I thought it will be easier to track which one corresponds to which at the initial stages of adoption. Absolutely ok to make any renaming that will suit Teams theme devs
45c6f35
to
3fd1512
Compare
closing as this set of changes will be introduced by means of #260 |
TODO
Problem
Introduce mechanisms in Stardust to provide/extend set of SVG icons by themes.
Further problem analysis
Essentially, task of introducing custom SVG icons (by means of themes) could be reduced to solving the following tasks
Functionality that aims to solve these tasks should be added as part of core Stardust functionality, and there should be no assumptions made on Stardust's side about specific structure of rendered SVGs or their styling aspects - suggested mechanisms should be flexible enough to meet different needs of consumers (theme authors).
Proposed solution
svgIcons
object - this maps icon's name to the icon rendering function:(iconClasses) => SVG as ReactNode
. Please, note that althoughiconClasses
is something that is related toIcon
component, this is an aspect that is entirely controlled by theme - thus, all the styling aspects could be customized by themeUse case
Suppose that there is a task for theme developer to introduce custom set of SVG icons. Stardust requires them to be exported in the following form from theme:
With that the question of 'what' should be rendered (for each particular icon) is solved - the only question remains is how it should be styled. For that
classes
object is provided as argument, so that those could be used to style individual parts of the icon's element tree - and theme developer has full control over introducing necessary set of parts and styles forIcon
: