diff --git a/CHANGELOG.md b/CHANGELOG.md index ccd2e43cab..8a4c4bb2ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/packages/react/src/lib/UIComponent.tsx b/packages/react/src/lib/UIComponent.tsx index cc48d6b162..5f110d99f7 100644 --- a/packages/react/src/lib/UIComponent.tsx +++ b/packages/react/src/lib/UIComponent.tsx @@ -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 +import { ThemeContext } from 'react-fela' + import renderComponent, { RenderResultConfig } from './renderComponent' import { AccessibilityActionHandlers } from './accessibility/types' import { FocusZone } from './accessibility/FocusZone' @@ -11,6 +14,7 @@ class UIComponent
extends React.Component
{ static displayName: string static className: string + static contextType = ThemeContext static propTypes: any /** Array of props to exclude from list of handled ones. */ @@ -47,17 +51,20 @@ class UIComponent
extends React.Component
{ } 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 => { diff --git a/packages/react/src/lib/createComponent.tsx b/packages/react/src/lib/createComponent.tsx index 3b73670264..7f02e1dcc0 100644 --- a/packages/react/src/lib/createComponent.tsx +++ b/packages/react/src/lib/createComponent.tsx @@ -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
{ displayName: string @@ -40,17 +43,22 @@ const createComponent =
= any>({ } const StardustComponent: CreateComponentReturnType
= (props): React.ReactElement
=> { - 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({ diff --git a/packages/react/src/lib/renderComponent.tsx b/packages/react/src/lib/renderComponent.tsx index bf9b229546..5265e3a3ad 100644 --- a/packages/react/src/lib/renderComponent.tsx +++ b/packages/react/src/lib/renderComponent.tsx @@ -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' @@ -131,7 +130,10 @@ const renderWithFocusZone =
( return render(config) } -const renderComponent =
(config: RenderConfig
): React.ReactElement
=> { +const renderComponent =
( + config: RenderConfig
, + theme: ThemePrepared, +): React.ReactElement
=> { const { className, defaultProps, @@ -144,98 +146,86 @@ const renderComponent =
(config: RenderConfig
): React.ReactElem
render,
} = config
- return (
-
-
- 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 = {
- ElementType,
- unhandledProps,
- classes,
- variables: resolvedVariables,
- styles: resolvedStyles,
- accessibility,
- rtl,
- theme,
- }
-
- if (accessibility.focusZone) {
- return renderWithFocusZone(render, accessibility.focusZone, config, focusZoneRef)
- }
-
- return render(config)
- }}
-
+ + 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
= { + 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