A while back I showed a storybook component showing a 2D grid of combinations for props for a component library. V2 looked a little less cool but did a much better job of coming up with ALL permutations, not just the 1+1 combos you can show on a grid...
Here is the code:
import React from 'react'; import PropTestingProps from './permutation-testing.props'; import { PermutationTestingStyle } from './permutation-testing.style'; import { Button } from '../Button/button.component'; import { Checkbox } from '../Checkbox/checkbox.component'; import { Radio } from '../Radio/radio.component'; import styled from 'styled-components'; import { IconButton } from '../IconButton/icon-button.component'; import { Slider } from '../Slider/slider.component'; import { Tab } from '../Tab/tab.component'; import { TextArea } from '../TextArea/text-area.component'; import { TextField } from '../TextField/text-field.component'; import { Dropdown } from '../Dropdown/dropdown.component'; import { TypeAhead } from '../TypeAhead/type-ahead.component'; const Table = styled.table` th { font-weight: bold; } th, td { padding: 8px; font-family: sans-serif; vertical-align: middle; text-align: left; } margin-bottom: 16px; `; let count = 0; interface ComponentPropMatrixProps { label: string; permutations: string[]; render: React.FC; } const getAllSubsets = (theArray: string[]) => theArray.reduce( (subsets, value) => subsets.concat(subsets.map((set) => [value, ...set])), [[] as string[]], ); const ComponentPropSubsetsList = (props: ComponentPropMatrixProps) => { const { permutations, render, label } = props; // get all subsets, sort on length of subset, then keep original order of elemts const subsets = getAllSubsets(permutations) .sort((a, b) => a.length - b.length) .map((arr) => arr.sort((a, b) => permutations.indexOf(a) - permutations.indexOf(b)), ); return ( <> <h3>{label}</h3> <Table> <tbody> {subsets.map((subset) => { const subsetAsProps = {}; subset.forEach((x) => { subsetAsProps[x] = true; }); count++; console.log(count); return ( <tr key={JSON.stringify(subset)}> <td>{render({ componentProps: subsetAsProps, label })}</td> <th>{subset.join(' ')}</th> </tr> ); })} </tbody> </Table> </> ); }; // idle, checked, error, disabled const buttonVariations: React.ReactChild[] = []; for (const shape of ['rectangle', 'oval']) { for (const size of ['sm', 'lg']) { for (const ord of ['primary', 'secondary', 'tertiary']) { console.log(`${size} ${shape} ${ord}`); buttonVariations.push( <ComponentPropSubsetsList label={`Button ${size} ${shape} ${ord}`} permutations={['disabled']} render={({ componentProps, label }) => ( <Button size={size} shape={shape} buttonType={ord} {...componentProps} > Button </Button> )} />, ); } } } const checkboxVariations: React.ReactChild[] = []; for (const size of ['sm', 'md']) { checkboxVariations.push( <ComponentPropSubsetsList label={`Checkbox ${size}`} permutations={['checked', 'error', 'disabled']} render={({ componentProps, label }) => ( <Checkbox size={size} {...componentProps} label='Checkbox' /> )} />, ); } const iconButtonVariations: React.ReactChild[] = []; for (const shape of ['square', 'circle']) { for (const size of ['sm', 'md', 'lg']) { for (const ord of ['primary', 'secondary', 'tertiary']) { iconButtonVariations.push( <ComponentPropSubsetsList label={`Icon Button ${size} ${shape} ${ord}`} permutations={['disabled']} render={({ componentProps, label }) => ( <IconButton size={size} shape={shape} buttonType={ord} {...componentProps} > Icon Button </IconButton> )} />, ); } } } const radioVariations: React.ReactChild[] = []; for (const size of ['sm', 'md']) { radioVariations.push( <ComponentPropSubsetsList label={`Radio ${size}`} permutations={['checked', 'error', 'disabled']} render={({ componentProps, label }) => ( <Radio size={size} {...componentProps} id={`${JSON.stringify(componentProps)}_${size}`} label='Checkbox' /> )} />, ); } const sliderVariations: React.ReactChild[] = []; sliderVariations.push( <ComponentPropSubsetsList label={`Slider`} permutations={[]} render={({ componentProps, label }) => ( <Slider {...componentProps} label='Slider' /> )} />, ); const tabVariations: React.ReactChild[] = []; tabVariations.push( <ComponentPropSubsetsList label={`Tab`} permutations={[]} render={({ componentProps, label }) => <Tab {...componentProps}>Tab</Tab>} />, ); const textAreaVariations: React.ReactChild[] = []; textAreaVariations.push( <ComponentPropSubsetsList label={`Text Area`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <TextArea {...componentProps}>Some Text</TextArea> )} />, ); const textFieldVariations: React.ReactChild[] = []; textFieldVariations.push( <ComponentPropSubsetsList label={`Text Field`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <TextField value='Some Text' {...componentProps}></TextField> )} />, ); const dropDownVariations: React.ReactChild[] = []; dropDownVariations.push( <ComponentPropSubsetsList label={`Dropdown`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <Dropdown value='Some Text' {...componentProps}></Dropdown> )} />, ); const typeAheadVariations: React.ReactChild[] = []; typeAheadVariations.push( <ComponentPropSubsetsList label={`Type Ahead`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <TypeAhead value='Some Text' {...componentProps}></TypeAhead> )} />, ); export const PermutationTesting = (props: PropTestingProps) => { return ( <PermutationTestingStyle> {buttonVariations} {checkboxVariations} {iconButtonVariations} {radioVariations} {sliderVariations} {tabVariations} {textAreaVariations} {textFieldVariations} {dropDownVariations} {typeAheadVariations} </PermutationTestingStyle> ); };
As maybe you can see it's pretty easy to spin up new variants. "getAllSubsets()" is some very clever code I found online and honestly don't quite understand that makes all the permutations possible.
No comments:
Post a Comment