Skip to content

Commit

Permalink
perf: Keyed children (#231)
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Jun 4, 2020
1 parent 184e8ed commit 8b63483
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 132 deletions.
3 changes: 2 additions & 1 deletion packages/fuselage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"@rocket.chat/css-in-js": "^0.9.0",
"@rocket.chat/fuselage-tokens": "^0.9.0",
"@rocket.chat/icons": "^0.9.0",
"invariant": "^2.2.4"
"invariant": "^2.2.4",
"react-keyed-flatten-children": "^1.2.0"
},
"devDependencies": {
"@babel/core": "^7.4.5",
Expand Down
3 changes: 2 additions & 1 deletion packages/fuselage/src/components/Avatar/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { useContext, createContext } from 'react';
import flattenChildren from 'react-keyed-flatten-children';

import { Box } from '../Box';
import { sizePropType } from '../../styles/props/layout';
Expand Down Expand Up @@ -48,7 +49,7 @@ Avatar.propTypes = {

const AvatarStack = ({ children, ...props }) =>
<Box rcx-avatar-stack {...props}>
{React.Children.toArray(children).reverse()}
{flattenChildren(children).reverse()}
</Box>;

Avatar.Stack = AvatarStack;
30 changes: 23 additions & 7 deletions packages/fuselage/src/components/Box/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
import PropTypes from 'prop-types';
import React, { createElement, forwardRef, memo, useContext } from 'react';

import { mergeProps } from '../../helpers/mergeProps';
import { marginPropType, paddingPropType, mapSpaceProps } from '../../styles/props/spaces';
import { colorPropType, mapColorProps } from '../../styles/props/colors';
import { fontFamilyPropType, fontScalePropType, mapTypographyProps } from '../../styles/props/typography';
import { sizePropType, mapLayoutProps } from '../../styles/props/layout';
import { insetPropType, mapPositionProps } from '../../styles/props/position';
import { PropsContext } from './PropsContext';
import { useStyleSheet } from './useStyleSheet';
import { mergeProps } from './mergeProps';
import { marginPropType, paddingPropType } from '../../styles/props/spaces';
import { colorPropType } from '../../styles/props/colors';
import { fontFamilyPropType, fontScalePropType } from '../../styles/props/typography';
import { sizePropType } from '../../styles/props/layout';
import { insetPropType } from '../../styles/props/position';
import { mapSpecialProps } from '../../styles/props/special';
import { mapClassNames } from './mapClassNames';
import { mapFlexBoxProps } from '../../styles/props/flexBox';
import { mapBorderProps } from '../../styles/props/borders';

const transforms = [
mapBorderProps,
mapColorProps,
mapFlexBoxProps,
mapLayoutProps,
mapPositionProps,
mapSpaceProps,
mapTypographyProps,
mapSpecialProps,
mapClassNames,
];

export const Box = memo(forwardRef(function Box(props, ref) {
useStyleSheet();

const contextProps = useContext(PropsContext);
const { is, ...mergedProps } = mergeProps(props, contextProps, ref);
const { is, ...mergedProps } = mergeProps(contextProps, { ...props, 'rcx-box': true, ref }, transforms);

const children = createElement(is || 'div', mergedProps);

Expand Down
48 changes: 0 additions & 48 deletions packages/fuselage/src/components/Box/mergeProps.js

This file was deleted.

38 changes: 20 additions & 18 deletions packages/fuselage/src/components/Box/props.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { css } from '@rocket.chat/css-in-js';
import { Meta, Preview, Props, Story } from '@storybook/addon-docs/blocks';
import flattenChildren from 'react-keyed-flatten-children';
import { Box, Button } from '../..';

<Meta title='Box/Props' parameters={{ jest: ['Box/spec'] }} />
Expand Down Expand Up @@ -32,7 +33,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Margins'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) => <Box bg='neutral-200' m='x16'>
{flattenChildren(fn().props.children).map((child) => <Box key={child.key} bg='neutral-200' m='x16'>
{React.cloneElement(child, { bg:'primary-200' }, <Box bg='neutral-500' size='x16' />)}
</Box>)}
</Box>
Expand Down Expand Up @@ -64,7 +65,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Paddings'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) => <Box bg='neutral-200' m='x16'>
{flattenChildren(fn().props.children).map((child) => <Box key={child.key} bg='neutral-200' m='x16'>
{React.cloneElement(child, { bg:'primary-200' }, <Box bg='neutral-500' size='x16' />)}
</Box>)}
</Box>
Expand Down Expand Up @@ -98,7 +99,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Colors'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center' overflow='hidden'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg: 'neutral-200', m: 'x4', p: 'x4' }, child.props.color))}
</Box>
]}
Expand Down Expand Up @@ -141,7 +142,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Background colors'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center' overflow='hidden'>
{React.Children.map(fn().props.children, (child) => React.cloneElement(child, { m: 'x4', size: 'x32' }))}
{flattenChildren(fn().props.children).map((child) => React.cloneElement(child, { m: 'x4', size: 'x32' }))}
</Box>
]}
>
Expand Down Expand Up @@ -364,7 +365,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Widths'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg:'primary-200', h: 'x32', m: 'x4' }))}
</Box>
]}
Expand All @@ -385,7 +386,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Heights'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg:'primary-200', w: 'x32', m: 'x4' }))}
</Box>
]}
Expand All @@ -406,7 +407,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Sizes'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg:'primary-200', m: 'x4' }))}
</Box>
]}
Expand All @@ -426,7 +427,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Display'
decorators={[
(fn) => <Box>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { children: child.props.display }))}
</Box>
]}
Expand All @@ -450,7 +451,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Vertical alignment'
decorators={[
(fn) => <Box>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { display: 'inline', children: child.props.verticalAlign }))}
</Box>
]}
Expand All @@ -476,7 +477,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Borders'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg:'primary-200', size: 'x32', m: 'x16' }))}
</Box>
]}
Expand Down Expand Up @@ -521,7 +522,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Border radii'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg:'primary-200', size: 'x32', m: 'x16' }))}
</Box>
]}
Expand All @@ -545,7 +546,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Position'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg:'primary-200', size: 'x32', m: 'x16' }))}
</Box>
]}
Expand All @@ -567,7 +568,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Z-index'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg: 'primary-200', borderWidth: 'x4', size: 'x32', m: 'neg-x2' }))}
</Box>
]}
Expand All @@ -588,9 +589,10 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Inset'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) => <Box position='relative' bg='neutral-200' m='x16' size='x64'>
{React.cloneElement(child, { bg:'primary-200', position: 'absolute', minSize: 'x16' })}
</Box>)}
{flattenChildren(fn().props.children).map((child) =>
<Box key={child.key} position='relative' bg='neutral-200' m='x16' size='x64'>
{React.cloneElement(child, { bg:'primary-200', position: 'absolute', minSize: 'x16' })}
</Box>)}
</Box>
]}
>
Expand Down Expand Up @@ -620,7 +622,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Elevation'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn().props.children, (child) =>
{flattenChildren(fn().props.children).map((child) =>
React.cloneElement(child, { bg: 'primary-100', m: 'x16', size: 'x64' }))}
</Box>
]}
Expand All @@ -640,7 +642,7 @@ The `is` prop allows `Box` to render any component capable of handling common DO
name='Invisible'
decorators={[
(fn) => <Box display='flex' flexWrap='wrap' alignItems='center'>
{React.Children.map(fn(), (child) => <Box bg='neutral-200' p='x16'>
{flattenChildren(fn()).map((child) => <Box key={child.key} bg='neutral-200' p='x16'>
{React.cloneElement(child, { bg:'primary-200', size: 'x16' })}
</Box>)}
</Box>
Expand Down
7 changes: 3 additions & 4 deletions packages/fuselage/src/components/ButtonGroup/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';

import { Box, PropsProvider } from '../Box';
import { Box } from '../Box';
import { patchChildren } from '../../helpers/patchChildren';

export function ButtonGroup({
align,
Expand All @@ -20,9 +21,7 @@ export function ButtonGroup({
role='group'
{...props}
>
<PropsProvider children={children} fn={({ className }) => ({
className: [className, 'rcx-button-group__item'],
})} />
{patchChildren(children, { className: 'rcx-button-group__item' })}
</Box>;
}

Expand Down
73 changes: 38 additions & 35 deletions packages/fuselage/src/components/ButtonGroup/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,19 @@

align-items: center;

& > .rcx-button-group__item {
margin-inline: lengths.margin(8);

&:first-child {
margin-inline-start: lengths.margin(none);
}

&:last-child {
margin-inline-end: lengths.margin(none);
}
}

&--wrap {
flex-wrap: wrap;

margin-block-end: lengths.margin(-16);

& > .rcx-button-group__item {
margin-block-end: lengths.margin(16);
margin-inline-start: lengths.margin(none);
margin-inline-end: lengths.margin(16);
}
}

&--stretch {
justify-content: stretch;

& > .rcx-button-group__item {
flex-grow: 1;
}
align-items: stretch;
}

&--vertical {
flex-direction: column;

& > .rcx-button-group__item {
margin-block-end: lengths.margin(16);
margin-inline: lengths.margin(none);

&:last-child {
margin-block-end: lengths.margin(none);
}
}
}

&--vertical#{&}--stretch {
align-items: stretch;
}

&--align-start {
Expand All @@ -69,3 +35,40 @@
justify-content: flex-end;
}
}

.rcx-button-group__item {
.rcx-button-group > & {
margin-inline: lengths.margin(8);

&:first-child {
margin-inline-start: lengths.margin(none);
}

&:last-child {
margin-inline-end: lengths.margin(none);
}
}

.rcx-button-group--wrap > & {
margin-block-end: lengths.margin(16);
margin-inline-start: lengths.margin(none);
margin-inline-end: lengths.margin(16);
}

.rcx-button-group--stretch > & {
flex-grow: 1;
}

.rcx-button-group--vertical > & {
margin-block: lengths.margin(8);
margin-inline: lengths.margin(none);

&:first-child {
margin-block-start: lengths.margin(none);
}

&:last-child {
margin-block-end: lengths.margin(none);
}
}
}
Loading

0 comments on commit 8b63483

Please sign in to comment.