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

feat(themes): add FontAwesome theme #1337

Merged
merged 26 commits into from
May 20, 2019
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cc9befa
feat(themes): add FontAwesome theme
layershifter May 14, 2019
75de2bb
fix visual regressions
layershifter May 14, 2019
2d89de6
Merge branches 'feat/fa-theme' and 'master' of https://github.com/sta…
layershifter May 15, 2019
04a0fed
fix more regressions
layershifter May 15, 2019
62a807c
fix more regressions
layershifter May 15, 2019
acbc177
fix regression
layershifter May 15, 2019
82b3934
Merge branches 'feat/fa-theme' and 'master' of https://github.com/sta…
layershifter May 15, 2019
83a7732
restructure styles
layershifter May 15, 2019
aa3d935
update examples
layershifter May 15, 2019
6931faa
update styles
layershifter May 15, 2019
4fe3fa8
fix regressions
layershifter May 15, 2019
4f36475
fix conflicts
layershifter May 16, 2019
55d9490
fixing regressions
layershifter May 16, 2019
816ac38
fixing regressions
layershifter May 16, 2019
c0fc01a
fixing regressions
layershifter May 16, 2019
c231413
add changelog entry
layershifter May 16, 2019
9b19f65
Merge branches 'feat/fa-theme' and 'master' of https://github.com/sta…
layershifter May 16, 2019
d4d8917
wip
layershifter May 17, 2019
e70b839
finish icon
layershifter May 17, 2019
a13e630
update example
layershifter May 17, 2019
aa17a05
update circle
layershifter May 17, 2019
ebfe10a
update circle again
layershifter May 17, 2019
9ce2080
move circle to circle
layershifter May 17, 2019
66453f0
Merge branches 'feat/fa-theme' and 'master' of https://github.com/sta…
layershifter May 17, 2019
8a97ad1
Merge branch 'master' into feat/fa-theme
layershifter May 20, 2019
3ec7f3d
Update CHANGELOG.md
layershifter May 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Fixed `Flex.Item` children prop type @mnajdova ([#1320](https://github.com/stardust-ui/react/pull/1320))
- Fixed `Icon`'s color example to align with the latest color updates @mnajdova ([#1336](https://github.com/stardust-ui/react/pull/1336))
- Fixed `TreeTitle` - `tabIndex` prop should be camel case in behavior @sophieH29 ([#1345](https://github.com/stardust-ui/react/pull/1345))
- FontAwesome icons is not part of Teams theme more @layershifter ([#1337](https://github.com/stardust-ui/react/pull/1337))

### Features
- Add `selected`, `isFromKeyboard` props to `DropdownItem` @mnajdova ([#1299](https://github.com/stardust-ui/react/pull/1299))
- Add styles for the dark and high contrast Teams themes for the `Dropdown` component @mnajdova ([#1299](https://github.com/stardust-ui/react/pull/1299))
- Highlight options by character keys in `Dropdown` non-search versions @silviuavram ([#1270](https://github.com/stardust-ui/react/pull/1270))
- Aligned link styles for `Chat.Message` component with latest Teams theme design @Bugaa92 ([#1269](https://github.com/stardust-ui/react/pull/1269))
- Add FontAwesome theme @layershifter ([#1337](https://github.com/stardust-ui/react/pull/1337))

<!--------------------------------[ v0.30.0 ]------------------------------- -->
## [v0.30.0](https://github.com/stardust-ui/react/tree/v0.30.0) (2019-05-10)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class App extends React.Component<any, ThemeContextData> {
<ThemeContext.Provider value={this.state}>
<Provider
as={React.Fragment}
theme={mergeThemes(themes[themeName], {
theme={mergeThemes(themes.fontAwesome, themes[themeName], {
Copy link
Member Author

Choose a reason for hiding this comment

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

We're using FA on docs, but we don't to have this theme in any other even in base

// adjust Teams' theme to Semantic UI's font size scheme
staticStyles: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ class ComponentExample extends React.Component<ComponentExampleProps, ComponentE
description,
title,
} = this.props
const { showCode, showRtl, showTransparent } = this.state
const { showCode, showRtl, showTransparent, themeName } = this.state

return (
<Flex column>
Expand Down Expand Up @@ -540,6 +540,7 @@ class ComponentExample extends React.Component<ComponentExampleProps, ComponentE
render={this.renderElement}
renderHtml={showCode}
resolver={importResolver}
themeName={themeName}
Copy link
Member Author

Choose a reason for hiding this comment

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

This will allow us to access themeName in example components

>
<Provider.Consumer
render={({ siteVariables }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const AvatarExampleImageCustomizationShorthand = () => (
// This example does not react to the avatar size variable
// and otherwise produces bad results when border is applied compared to "normal" image
<Icon
name="user"
name="lock"
Copy link
Member Author

Choose a reason for hiding this comment

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

Teams theme doesn't have this icon and font icons will not be supported inside of it

Copy link
Contributor

Choose a reason for hiding this comment

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

I am a bit confuse here. We are changing only this icon because Teams' theme doesn't support font icons? What about all other examples like: 'chess rook', 'book' etc. Are we planning to move all examples for now to reflect the Teams' theme icon names?

Copy link
Member Author

@layershifter layershifter May 17, 2019

Choose a reason for hiding this comment

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

We are changing only this icon because Teams' theme doesn't support font icons?

This slot in attachment requires an additional styling for font icons that is not present, so yes.

circular
bordered
variables={{ color: 'blue' }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
import * as React from 'react'
import { Grid, Divider, Header, Icon, Provider } from '@stardust-ui/react'
import { Grid, Divider, Header, Icon, themes } from '@stardust-ui/react'

const cellStyles = {
margin: '10px 0',
}

const IconSetExampleShorthand = () => (
<Provider.Consumer
render={theme => (
<>
<div>
<Divider>
<Header as="h3" content="Regular" />
</Divider>
<Grid columns={4} styles={{ textAlign: 'center' }}>
{Object.keys(theme.icons).map(name => (
<div key={name} style={cellStyles}>
<Icon name={name} />
<br />
<code>{name}</code>
</div>
))}
</Grid>
</div>
const IconSetExampleShorthand: React.FunctionComponent<{ themeName: string }> = ({ themeName }) => (
<>
<div>
<Divider>
<Header as="h3" content="Regular" />
</Divider>
<Grid columns={4} styles={{ textAlign: 'center' }}>
{Object.keys(themes[themeName].icons).map(name => (
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
<div key={name} style={cellStyles}>
<Icon name={name} />
<br />
<code>{name}</code>
</div>
))}
</Grid>
</div>

<div>
<Divider>
<Header as="h3" content="Outline" />
</Divider>
<Grid columns={4} styles={{ textAlign: 'center' }}>
{Object.keys(theme.icons).map(name => (
<div key={`${name}-outline`} style={cellStyles}>
<Icon name={name} outline />
<br />
<code>{name} outline</code>
</div>
))}
</Grid>
</div>
</>
)}
/>
<div>
<Divider>
<Header as="h3" content="Outline" />
</Divider>
<Grid columns={4} styles={{ textAlign: 'center' }}>
{Object.keys(themes[themeName].icons).map(name => (
<div key={`${name}-outline`} style={cellStyles}>
<Icon name={name} outline />
<br />
<code>{name} outline</code>
</div>
))}
</Grid>
</div>
</>
)

IconSetExampleShorthand.defaultProps = {
themeName: 'teams',
}

export default IconSetExampleShorthand
63 changes: 22 additions & 41 deletions packages/react/src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as customPropTypes from '@stardust-ui/react-proptypes'
import * as React from 'react'
import cx from 'classnames'
import * as PropTypes from 'prop-types'
import {
callable,
Expand All @@ -12,9 +12,8 @@ import {
} from '../../lib'
import { iconBehavior } from '../../lib/accessibility'
import { Accessibility } from '../../lib/accessibility/types'

import { SvgIconSpec } from '../../themes/types'
import { WithAsProp, withSafeTypeForAs } from '../../types'
import Box from '../Box/Box'

export type IconXSpacing = 'none' | 'before' | 'after' | 'both'

Expand Down Expand Up @@ -80,46 +79,28 @@ class Icon extends UIComponent<WithAsProp<IconProps>, any> {
rotate: 0,
}

private renderFontIcon(ElementType, classes, unhandledProps, accessibility): React.ReactNode {
return (
<ElementType
className={classes.root}
{...accessibility.attributes.root}
{...unhandledProps}
/>
)
}

private renderSvgIcon(
ElementType,
svgIconDescriptor: SvgIconSpec,
classes,
unhandledProps,
accessibility,
rtl,
): React.ReactNode {
return (
<ElementType className={classes.root} {...accessibility.attributes.root} {...unhandledProps}>
{svgIconDescriptor && callable(svgIconDescriptor)({ classes, rtl })}
</ElementType>
)
}

public renderComponent({ ElementType, classes, unhandledProps, accessibility, theme, rtl }) {
renderComponent({ ElementType, classes, unhandledProps, accessibility, theme, rtl, styles }) {
const { className, name } = this.props
const { icons = {} } = theme

const maybeIcon = icons[this.props.name]

return maybeIcon && maybeIcon.isSvg
? this.renderSvgIcon(
ElementType,
maybeIcon.icon as SvgIconSpec,
classes,
unhandledProps,
accessibility,
rtl,
)
: this.renderFontIcon(ElementType, classes, unhandledProps, accessibility)
const maybeIcon = icons[name]
const isSvgIcon = maybeIcon && maybeIcon.isSvg

return Box.create(
{ content: isSvgIcon && callable(maybeIcon.icon)({ classes, rtl }) },
{
defaultProps: {
as: ElementType,
className: cx(Icon.className, className),
...accessibility.attributes.root,
...unhandledProps,
styles: {
...(isSvgIcon ? styles.svgRoot : styles.fontRoot),
...styles.root,
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
},
Copy link
Member Author

@layershifter layershifter May 16, 2019

Choose a reason for hiding this comment

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

I have to use styles to avoid collisions in generated classes names... The other option is to use generateCSS() directly, but I will need to get renderer from somewhere

},
},
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export const icons: ThemeIcons = {
'stardust-play': fontIcon('23F8'),
}

const emptyIcon = { icon: { content: '?' } }
export const emptyIcon: ThemeIconSpec = { icon: { content: '?' } }

export default (name: string): ThemeIconSpec => icons[name] || emptyIcon
76 changes: 29 additions & 47 deletions packages/react/src/themes/base/components/Icon/iconStyles.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,9 @@
import icons from './index'
import { callable, pxToRem } from '../../../../lib'
import { pxToRem } from '../../../../lib'
import { ComponentSlotStylesInput, ICSSInJSStyle, FontIconSpec } from '../../../types'
import { ResultOf } from '../../../../types'
import { IconXSpacing, IconProps } from '../../../../components/Icon/Icon'
import { IconVariables } from './iconVariables'

const getDefaultFontIcon = (iconName: string) => {
return callable(icons(iconName).icon)()
}

const getFontStyles = (
size: number,
iconName: string,
themeIcon?: ResultOf<FontIconSpec>,
): ICSSInJSStyle => {
const { fontFamily, content } = themeIcon || getDefaultFontIcon(iconName)
const sizeInRems = pxToRem(size)

return {
fontFamily,
fontSize: sizeInRems,
lineHeight: 1,

display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',

width: sizeInRems,
height: sizeInRems,

'::before': {
content,
},
}
}
import { emptyIcon } from './iconNames'

const getXSpacingStyles = (xSpacing: IconXSpacing, horizontalSpace: string): ICSSInJSStyle => {
switch (xSpacing) {
Expand Down Expand Up @@ -61,27 +31,39 @@ const getPaddedStyle = (): ICSSInJSStyle => ({
})

const iconStyles: ComponentSlotStylesInput<IconProps, IconVariables> = {
root: ({ props: p, variables: v, theme }): ICSSInJSStyle => {
const iconSpec = theme.icons[p.name]
const rtl = theme.rtl
const isFontBased = p.name && (!iconSpec || !iconSpec.isSvg)
root: ({ props: p, variables: v }): ICSSInJSStyle => ({
speak: 'none',
verticalAlign: 'middle',

...getXSpacingStyles(p.xSpacing, v.horizontalSpace),

...(p.bordered && getBorderedStyles(v.borderColor)),
...(p.circular && { ...getPaddedStyle(), borderRadius: '50%' }),
...(p.disabled && {
color: v.disabledColor,
}),
}),
fontRoot: ({ props: p, variables: v, theme: t }): ICSSInJSStyle => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Now we have separate roots for SVG and font icons that allows to apply overrides without conditions

Copy link
Contributor

Choose a reason for hiding this comment

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

I like that we have two things separated 👍

const iconSpec = t.icons[p.name] || emptyIcon
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
const icon = iconSpec.icon as ResultOf<FontIconSpec>

return {
display: 'inline-block',
speak: 'none',
verticalAlign: 'middle',

alignItems: 'center',
boxSizing: 'content-box',
display: 'inline-flex',
justifyContent: 'center',

...(isFontBased && getFontStyles(16, p.name)),

...getXSpacingStyles(p.xSpacing, v.horizontalSpace),

...(p.circular && { ...getPaddedStyle(), borderRadius: '50%' }),
fontFamily: icon.fontFamily,
fontSize: v[`${p.size}Size`],
lineHeight: 1,
width: v[`${p.size}Size`],
height: v[`${p.size}Size`],

...(p.bordered && getBorderedStyles(v.borderColor)),
'::before': {
content: icon.content,
},

transform: rtl ? `scaleX(-1) rotate(${-1 * p.rotate}deg)` : `rotate(${p.rotate}deg)`,
transform: t.rtl ? `scaleX(-1) rotate(${-1 * p.rotate}deg)` : `rotate(${p.rotate}deg)`,
}
},
}
Expand Down
27 changes: 21 additions & 6 deletions packages/react/src/themes/base/components/Icon/iconVariables.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import { pxToRem } from '../../../../lib'

export type IconSizeModifier = 'x' | 'xx'

export interface IconVariables {
[key: string]: object | string | number | boolean | undefined
color?: string
borderColor?: string

color: string
borderColor: string
backgroundColor: string
disabledColor: string
horizontalSpace: string

smallestSize: string
smallerSize: string
smallSize: string
mediumSize: string
largeSize: string
largerSize: string
largestSize: string
Copy link
Member Author

Choose a reason for hiding this comment

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

Size values where moved to variables

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure that these size values are general enough for base theme...

Copy link
Member Author

Choose a reason for hiding this comment

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

Base theme should support size prop properly and we should avoid nesting in variables. Do you have better proposal? 🐱

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that we should have variables and use this, I was saying about the size values (which now reflect the Teams theme) If you think these values are general and should be defined as this, then I am okay

}

export default (): IconVariables => ({
color: undefined,
backgroundColor: undefined,
borderColor: 'black',
disabledColor: 'gray',

horizontalSpace: pxToRem(10),

smallestSize: pxToRem(7),
smallerSize: pxToRem(10),
smallSize: pxToRem(12),
mediumSize: pxToRem(16),
largeSize: pxToRem(20),
largerSize: pxToRem(32),
largestSize: pxToRem(40),
})
12 changes: 2 additions & 10 deletions packages/react/src/themes/base/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@ import { ThemeInput } from '../types'
import * as siteVariables from './siteVariables'
import * as componentVariables from './componentVariables'
import * as componentStyles from './componentStyles'
import { FontIconSpec, ThemeIconSpec, ThemeIcons } from 'src/themes/types'
import { default as fontIcons, icons } from './components/Icon/index'

const declareFontBased = (fontIcon: FontIconSpec): ThemeIconSpec => ({ icon: fontIcon })

const themeIcons: ThemeIcons = {}
Object.keys(icons).forEach(iconName => {
themeIcons[iconName] = declareFontBased(fontIcons[iconName])
})
import { icons } from './components/Icon/iconNames'

export default {
siteVariables,
icons: themeIcons,
icons,
componentVariables,
componentStyles,
} as ThemeInput
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Icon } from './components/Icon/iconStyles'
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,4 @@ const fontAwesomeIcons: ThemeIcons = {
'star empty': outline('f089'),
}

const emptyIcon = { icon: { content: '?', fontFamily: '' } }

export default (name: string): ThemeIconSpec => fontAwesomeIcons[name] || emptyIcon
export default fontAwesomeIcons
Loading