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

perf(renderComponent): drop FelaTheme and use React.Context directly #1163

Merged
merged 3 commits into from
Apr 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### BREAKING CHANGES
- Rename `flipInRtl` Icon's `slot` to `svgFlippingInRtl` in Teams theme @mnajdova ([#1179](https://github.com/stardust-ui/react/pull/1179))

### Performance
- Drop usages of `FelaTheme` component and use `React.Context` to get `theme` directly @layershifter ([#1163](https://github.com/stardust-ui/react/pull/1163))

### Features
- Add `Reaction` variables to Teams dark and HOC themes @mnajdova ([#1152](https://github.com/stardust-ui/react/pull/1152))
- Move `Grid`'s and `Image`'s styles and variables from Teams to base theme @mnajdova ([#1182](https://github.com/stardust-ui/react/pull/1182))
Expand Down
29 changes: 18 additions & 11 deletions packages/react/src/lib/UIComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import * as React from 'react'
import * as _ from 'lodash'
// @ts-ignore We have this export in package, but it is not present in typings
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

import { ThemeContext } from 'react-fela'

import renderComponent, { RenderResultConfig } from './renderComponent'
import { AccessibilityActionHandlers } from './accessibility/types'
import { FocusZone } from './accessibility/FocusZone'
Expand All @@ -11,6 +14,7 @@ class UIComponent<P, S = {}> extends React.Component<P, S> {
static displayName: string
static className: string

static contextType = ThemeContext
static propTypes: any

/** Array of props to exclude from list of handled ones. */
Expand Down Expand Up @@ -47,17 +51,20 @@ class UIComponent<P, S = {}> extends React.Component<P, S> {
}

render() {
return renderComponent({
className: this.childClass.className,
defaultProps: this.childClass.defaultProps,
displayName: this.childClass.displayName,
handledProps: this.childClass.handledProps,
props: this.props,
state: this.state,
actionHandlers: this.actionHandlers,
focusZoneRef: this.setFocusZoneRef,
render: this.renderComponent,
})
return renderComponent(
{
className: this.childClass.className,
defaultProps: this.childClass.defaultProps,
displayName: this.childClass.displayName,
handledProps: this.childClass.handledProps,
props: this.props,
state: this.state,
actionHandlers: this.actionHandlers,
focusZoneRef: this.setFocusZoneRef,
render: this.renderComponent,
},
this.context,
)
}

private setFocusZoneRef = (focusZone: FocusZone): void => {
Expand Down
30 changes: 19 additions & 11 deletions packages/react/src/lib/createComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import * as React from 'react'
import * as _ from 'lodash'
// @ts-ignore
import { ThemeContext } from 'react-fela'

import renderComponent, { RenderResultConfig } from './renderComponent'
import { AccessibilityActionHandlers } from './accessibility/types'
import { FocusZone } from './accessibility/FocusZone'
import { createShorthandFactory } from './factories'
import { ObjectOf } from '../types'
import { ThemePrepared } from '../themes/types'

export interface CreateComponentConfig<P> {
displayName: string
Expand Down Expand Up @@ -40,17 +43,22 @@ const createComponent = <P extends ObjectOf<any> = any>({
}

const StardustComponent: CreateComponentReturnType<P> = (props): React.ReactElement<P> => {
return renderComponent({
className,
defaultProps,
displayName,
handledProps: _.keys(propTypes).concat(handledProps),
props,
state: {},
actionHandlers,
focusZoneRef,
render: config => render(config, props),
})
const theme: ThemePrepared = React.useContext(ThemeContext)

return renderComponent(
{
className,
defaultProps,
displayName,
handledProps: _.keys(propTypes).concat(handledProps),
props,
state: {},
actionHandlers,
focusZoneRef,
render: config => render(config, props),
},
theme,
)
}

StardustComponent.create = createShorthandFactory({
Expand Down
176 changes: 83 additions & 93 deletions packages/react/src/lib/renderComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import cx from 'classnames'
import * as React from 'react'
import * as _ from 'lodash'
import { FelaTheme } from 'react-fela'

import callable from './callable'
import felaRenderer from './felaRenderer'
Expand Down Expand Up @@ -131,7 +130,10 @@ const renderWithFocusZone = <P extends {}>(
return render(config)
}

const renderComponent = <P extends {}>(config: RenderConfig<P>): React.ReactElement<P> => {
const renderComponent = <P extends {}>(
config: RenderConfig<P>,
theme: ThemePrepared,
): React.ReactElement<P> => {
const {
className,
defaultProps,
Expand All @@ -144,98 +146,86 @@ const renderComponent = <P extends {}>(config: RenderConfig<P>): React.ReactElem
render,
} = config

return (
<FelaTheme>
{(theme: ThemePrepared) => {
if (_.isEmpty(theme)) {
logProviderMissingWarning()
}

const {
siteVariables = {
colorScheme: {},
colors: {},
contextualColors: {},
emphasisColors: {},
naturalColors: {},
fontSizes: {},
},
componentVariables = {},
componentStyles = {},
rtl = false,
renderer = felaRenderer,
} = theme || {}
const ElementType = getElementType({ defaultProps }, props) as React.ReactType<P>

const stateAndProps = { ...state, ...props }

// Resolve variables for this component, allow props.variables to override
const resolvedVariables: ComponentVariablesObject = mergeComponentVariables(
componentVariables[displayName],
props.variables,
)(siteVariables)

const animationCSSProp = props.animation
? createAnimationStyles(props.animation, theme)
: {}

// Resolve styles using resolved variables, merge results, allow props.styles to override
const mergedStyles: ComponentSlotStylesPrepared = mergeComponentStyles(
componentStyles[displayName],
{
root: props.styles,
},
)

const accessibility: AccessibilityBehavior = getAccessibility(
stateAndProps,
actionHandlers,
rtl,
)

const unhandledProps = getUnhandledProps({ handledProps }, props)

const colors = generateColorScheme(stateAndProps.color, resolvedVariables.colorScheme)

const styleParam: ComponentStyleFunctionParam = {
props: stateAndProps,
variables: resolvedVariables,
theme,
colors,
}

mergedStyles.root = {
...callable(mergedStyles.root)(styleParam),
...animationCSSProp,
}

const resolvedStyles: ComponentSlotStylesPrepared = Object.keys(mergedStyles).reduce(
(acc, next) => ({ ...acc, [next]: callable(mergedStyles[next])(styleParam) }),
{},
)

const classes: ComponentSlotClasses = getClasses(renderer, mergedStyles, styleParam)
classes.root = cx(className, classes.root, props.className)

const config: RenderResultConfig<P> = {
ElementType,
unhandledProps,
classes,
variables: resolvedVariables,
styles: resolvedStyles,
accessibility,
rtl,
theme,
}

if (accessibility.focusZone) {
return renderWithFocusZone(render, accessibility.focusZone, config, focusZoneRef)
}

return render(config)
}}
</FelaTheme>
if (_.isEmpty(theme)) {
logProviderMissingWarning()
}

const {
siteVariables = {
colorScheme: {},
colors: {},
contextualColors: {},
emphasisColors: {},
naturalColors: {},
fontSizes: {},
},
componentVariables = {},
componentStyles = {},
rtl = false,
renderer = felaRenderer,
} = theme || {}
const ElementType = getElementType({ defaultProps }, props) as React.ReactType<P>

const stateAndProps = { ...state, ...props }

// Resolve variables for this component, allow props.variables to override
const resolvedVariables: ComponentVariablesObject = mergeComponentVariables(
componentVariables[displayName],
props.variables,
)(siteVariables)

const animationCSSProp = props.animation ? createAnimationStyles(props.animation, theme) : {}

// Resolve styles using resolved variables, merge results, allow props.styles to override
const mergedStyles: ComponentSlotStylesPrepared = mergeComponentStyles(
componentStyles[displayName],
{
root: props.styles,
},
)

const accessibility: AccessibilityBehavior = getAccessibility(stateAndProps, actionHandlers, rtl)

const unhandledProps = getUnhandledProps({ handledProps }, props)

const colors = generateColorScheme(stateAndProps.color, resolvedVariables.colorScheme)

const styleParam: ComponentStyleFunctionParam = {
props: stateAndProps,
variables: resolvedVariables,
theme,
colors,
}

mergedStyles.root = {
...callable(mergedStyles.root)(styleParam),
...animationCSSProp,
}

const resolvedStyles: ComponentSlotStylesPrepared = Object.keys(mergedStyles).reduce(
(acc, next) => ({ ...acc, [next]: callable(mergedStyles[next])(styleParam) }),
{},
)

const classes: ComponentSlotClasses = getClasses(renderer, mergedStyles, styleParam)
classes.root = cx(className, classes.root, props.className)

const resolvedConfig: RenderResultConfig<P> = {
ElementType,
unhandledProps,
classes,
variables: resolvedVariables,
styles: resolvedStyles,
accessibility,
rtl,
theme,
}

if (accessibility.focusZone) {
return renderWithFocusZone(render, accessibility.focusZone, resolvedConfig, focusZoneRef)
}

return render(resolvedConfig)
}

export default renderComponent