Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

feat(theme): add font icons support for themes #243

Merged

Conversation

kuzhelov
Copy link
Contributor

@kuzhelov kuzhelov commented Sep 17, 2018

This PR is introduced as one of the steps necessary to address #230.

Overview

Support for font icons is introduced for themes, icon types are generalized (no need to specify svg prop to switch between SVG and font-based icons).

API changes for SVG icons

Before

// SVG icon
<Icon svg name='umbrella' />   

// font icon
<Icon name='user' /> 

Now

// SVG icon
<Icon name='umbrella' />

// font icon - exactly the same API
<Icon name='user' />

Font icons support for themes

Theme authors are able to introduce custom set of icons, both font-based and SVGs are supported.

// theme.js
const icons = {
  'umbrella': () => <svg>...</svg>,
  'user': { fontFamily: 'Icons', content: '"\\f0152" }
}
...

export default {
  ...
  icons: icons
}

@kuzhelov kuzhelov changed the title Add font icons support for themes feat(icons): add font icons support for themes Sep 18, 2018
@kuzhelov kuzhelov changed the title feat(icons): add font icons support for themes feat(theme): add font icons support for themes Sep 18, 2018
Copy link
Contributor

@hughreeling hughreeling left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@@ -120,7 +122,8 @@ const renderComponent = <P extends {}>(
}: IThemeInput | IThemePrepared = {}) => {
const ElementType = getElementType({ defaultProps }, props)

const stateAndProps = { ...state, ...props }
const derivedProps = getExtraProps({ icons })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So derivedProps or extraProps?

return this.props.svg
? this.renderSvgIcon(ElementType, icons, classes, rest, accessibility)
: this.renderFontIcon(ElementType, classes, rest, accessibility)
return this.isFontBased(icons)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the fact that you do similar calculation to what you've already done in getExtraProps(). Primarily not because of the performance but because for me (as a component developer) it is difficult to understand what the extraProps are good for - they are used to calculate styles, accessibility... why there are not used to render the component?
renderComponent() should receive extraProps as a parameter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we can remove getExtraProps entirely if we check the type of the icon instead. To limit the number of ideas and patterns in the library, I propose we also allow values or functions (as with variables and styles):

const icons = {
  // value form
  umbrella: <svg></svg>,                             
  user: { fontFamily: 'Icons', content: "\\f0152" },

  // function form
  umbrella: () => <svg></svg>,
  user: () => ({ fontFamily: 'Icons', content: "\\f0152" }),
}

React.isValidElement(callable(icons.umbrella)()) ? isSVG : isFONT

This would allow us to pass values to the icon later. It also removes the need for the getExtraProps function.

@@ -130,10 +136,26 @@ class Icon extends UIComponent<Extendable<IIconProps>, any> {
)
}

isFontBased(themeIcons: ThemeIcons): boolean {
const { name } = this.props
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: from the function signature, it is not obvious that it checks current icon (in this).
I would change the signature to isFontBased(name, themeIcons)

fontIconFromTheme: isFontBased && icons[this.props.name],
}
}

renderComponent({ ElementType, classes, rest, accessibility, icons }) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Propose we pass the entire theme to renderComponent as it is more generic and seems more useful in a wider range of scenarios. Icons alone probably are not that useful to many other components.

@codecov
Copy link

codecov bot commented Sep 19, 2018

Codecov Report

Merging #243 into feat/themable-icons will decrease coverage by 0.45%.
The diff coverage is 77.77%.

Impacted file tree graph

@@                   Coverage Diff                   @@
##           feat/themable-icons     #243      +/-   ##
=======================================================
- Coverage                91.78%   91.32%   -0.46%     
=======================================================
  Files                       60       60              
  Lines                     1035     1038       +3     
  Branches                   132      154      +22     
=======================================================
- Hits                       950      948       -2     
- Misses                      82       86       +4     
- Partials                     3        4       +1
Impacted Files Coverage Δ
src/components/Icon/Icon.tsx 81.48% <77.77%> (-18.52%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 72c62eb...f436722. Read the comment docs.

@kuzhelov
Copy link
Contributor Author

agreed with @miroslavstastny to reduce amount of style parts exposed for SVG icons to absolute necessary minimum (instead of path1, path2, path3 ... path9 we have now) before merging changes into master

@@ -103,7 +98,9 @@ const iconStyles = {
width: '1em',
height: '1em',

...(isFontBased ? getFontStyles(font, name, size) : {}),
...(isFontBased
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplify this one

types/theme.d.ts Outdated
export type RenderSvgIconFunction = (classes: Classes) => React.ReactNode
type SvgIconFuncArg = {
classes: Classes
props: any
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props should be eliminated for now

@kuzhelov kuzhelov merged commit 835f91d into feat/themable-icons Sep 20, 2018
@kuzhelov kuzhelov mentioned this pull request Sep 20, 2018
1 task
kuzhelov added a commit that referenced this pull request Sep 21, 2018
* add SVG icons to teams theme

* udpate theme icons api, add example enumerating icons

* generalize API for svg and font-based icons

* feat(theme): add font icons support for themes (#243)

* generalize API for svg and font-based icons

* remove 'svg' prop in IconSet example

* add mechanism for providing font-based icons in theme

* fix UTs

* remove getExtraProps method

* fix theme icons example in docs

* generalize object and function types as icon descriptors

* fix unit tests

* address review comments

* fix lint issues

* fix import statement

* replace helper methods

* remove 'derivedProps' from renderer

* remove unused styles for SVG paths

* address review comments

* fix lint issues

* changelog
@kuzhelov kuzhelov deleted the feat/generalize-svg-and-font-based-icons-api branch November 19, 2018 15:57
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants