Skip to content

Commit

Permalink
New hybrid layout (#174)
Browse files Browse the repository at this point in the history
* Add stories for existing layouts

* Change renderPropType to be more extensible

* Add new hybrid layout

* Add layout stories

* Fix up spacing + borders

* Add a required prop

* Defualt styling for hybrid layout

* Stories for hybrid layout

* Required prop first

* Revise styling to match finalised design

* Update stories

* docs(changeset): Added a new hybrid layout for displaying props.

Co-authored-by: Declan Warn <[email protected]>
  • Loading branch information
declan-warn and declan-warn committed Mar 8, 2021
1 parent 48e0ff1 commit 84e9241
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-socks-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'pretty-proptypes': minor
---

Added a new hybrid layout for displaying props.
127 changes: 127 additions & 0 deletions packages/pretty-proptypes/src/HybridLayout/PropEntry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// @flow
/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import { Fragment, Component, type ComponentType, type Node } from 'react';
import md from 'react-markings';
import PrettyPropType from '../PrettyConvert';
import { HeadingType, HeadingDefault, Heading, HeadingRequired } from '../Prop/Heading';
import type { CommonProps } from '../types';
import { colors } from '../components/constants';

type PropProps = CommonProps & {
shapeComponent: ComponentType<CommonProps>
};

export default class PropEntry extends Component<PropProps> {
static defaultProps = {
shapeComponent: (props: CommonProps) => <PrettyPropType {...props} />
};

render() {
let { shapeComponent: ShapeComponent, ...commonProps } = this.props;

let { defaultValue, description, name, required, type, components } = commonProps;

return (
<Fragment>
<table
css={css`
width: 100%;
border-collapse: collapse;
margin-top: 40px;
th {
text-align: left;
padding: 4px 16px 4px 8px;
white-space: nowrap;
vertical-align: top;
}
td {
padding: 4px 0 4px 8px;
width: 100%;
}
`}
>
<caption
css={css`
text-align: left;
margin: 0;
font-size: 1em;
`}
>
<Heading
css={css`
font-size: 1em;
padding-bottom: 8px;
border-bottom: 1px solid ${colors.N30};
margin-bottom: 4px;
`}
>
<code
css={css`
background-color: ${colors.N20};
color: ${colors.N800};
border-radius: 3px;
padding: 4px 8px;
line-height: 20px;
display: inline-block;
`}
>
{name}
</code>
{required && defaultValue === undefined && (
<HeadingRequired
css={css`
margin-left: 1em;
color: ${colors.R400};
`}
>
required
</HeadingRequired>
)}
</Heading>
</caption>
<tbody
css={css`
border-bottom: none;
`}
>
<tr>
<th scope="row">Description</th>
<td>
{description && (
<components.Description>{md([description])}</components.Description>
)}
</td>
</tr>
{defaultValue !== undefined && (
<tr>
<th scope="row">Default</th>
<td>
<HeadingDefault>{defaultValue}</HeadingDefault>
</td>
</tr>
)}
<tr>
<th scope="row">Type</th>
<td
css={css`
display: flex;
flex-direction: column;
`}
>
<span>
<HeadingType>{type}</HeadingType>
</span>
<span>
<ShapeComponent {...commonProps} />
</span>
</td>
</tr>
</tbody>
</table>
</Fragment>
);
}
}
97 changes: 97 additions & 0 deletions packages/pretty-proptypes/src/HybridLayout/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// @flow

/* eslint-disable no-underscore-dangle */

/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import React, { Component, type ComponentType } from 'react';

import type { Components } from '../components';
import type { CommonProps } from '../types';
import PropsWrapper from '../Props/Wrapper';
import getPropTypes from '../getPropTypes';
import renderPropType from '../PropType';
import PropEntry from './PropEntry';

type Obj = {
kind: 'object',
members: Array<any>
};

type Gen = {
kind: 'generic',
value: any
};

type Inter = {
kind: 'intersection',
types: Array<Obj | Gen>
};

type DynamicPropsProps = {
components?: Components,
heading?: string,
shouldCollapseProps?: boolean,
overrides?: {
[string]: ComponentType<CommonProps>
},
props?: {
component?: Obj | Inter
},
component?: ComponentType<any>
};

const getProps = props => {
if (props && props.component) {
return getPropTypes(props.component);
}
return null;
};

export default class HybridLayout extends Component<DynamicPropsProps> {
render() {
let { props, heading, component, components, ...rest } = this.props;
if (component) {
/* $FlowFixMe the component prop is typed as a component because
that's what people pass to Props and the ___types property shouldn't
exist in the components types so we're just going to ignore this error */
if (component.___types) {
props = { type: 'program', component: component.___types };
} else {
/* eslint-disable-next-line no-console */
console.error(
'A component was passed to <Props> but it does not have types attached.\n' +
'babel-plugin-extract-react-types may not be correctly installed.\n' +
'<Props> will fallback to the props prop to display types.'
);
}
}

if (!components || !components.Description) {
components = components || {};
components.Description = ({ children }) => (
<div
css={css`
p:first-of-type {
margin-top: 0px;
}
p:last-of-type {
margin-bottom: 0px;
}
`}
>
{children}
</div>
);
}

let propTypes = getProps(props);
if (!propTypes) return null;

return (
<PropsWrapper heading={heading}>
{propTypes.map(propType => renderPropType(propType, { ...rest, components }, PropEntry))}
</PropsWrapper>
);
}
}
13 changes: 7 additions & 6 deletions packages/pretty-proptypes/src/PropType/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
/* eslint-disable no-param-reassign */
import React from 'react';
import convert, { getKind, reduceToObj } from 'kind2string';
import PropRow from '../PropsTable/PropRow';
import Prop from '../Prop';
import allComponents from '../components';

const renderPropType = (
propType: any,
{ table = false, overrides = {}, shouldCollapseProps, components }: any,
{ overrides = {}, shouldCollapseProps, components }: any,
PropComponent
) => {
if (!components) {
components = allComponents;
Expand Down Expand Up @@ -56,9 +55,11 @@ const renderPropType = (
typeValue: propType.value
};

return overrides[name]
? <OverrideComponent {...commonProps} />
: (table ? <PropRow {...commonProps} />: <Prop {...commonProps} />);
return overrides[name] ? (
<OverrideComponent {...commonProps} />
) : (
<PropComponent {...commonProps} />
);
};

export default renderPropType;
4 changes: 3 additions & 1 deletion packages/pretty-proptypes/src/Props/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import PropsWrapper from './Wrapper';
import getPropTypes from '../getPropTypes';
import renderPropType from '../PropType';

import Prop from '../Prop';

type Obj = {
kind: 'object',
members: Array<any>
Expand Down Expand Up @@ -68,7 +70,7 @@ export default class Props extends Component<DynamicPropsProps> {

return (
<PropsWrapper heading={heading}>
{propTypes.map(propType => renderPropType(propType, rest))}
{propTypes.map(propType => renderPropType(propType, rest, Prop))}
</PropsWrapper>
);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/pretty-proptypes/src/PropsTable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { CommonProps } from '../types';
import PropsWrapper from '../Props/Wrapper';
import getPropTypes from '../getPropTypes';
import renderPropType from '../PropType';
import PropRow from './PropRow';

type Obj = {
kind: 'object',
Expand Down Expand Up @@ -83,7 +84,7 @@ export default class PropsTable extends Component<DynamicPropsProps> {
<td>Description</td>
</tr>
</thead>
{propTypes.map(propType => renderPropType(propType, { table: true, ...rest }))}
{propTypes.map(propType => renderPropType(propType, rest, PropRow))}
</table>
</PropsWrapper>
);
Expand Down
5 changes: 4 additions & 1 deletion packages/pretty-proptypes/src/components/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ export const colors = {
R75: '#FFBDAD',
R50: '#FFEBE6',
P300: '#6554C0',
T300: '#00B8D9'
T300: '#00B8D9',
R400: '#DE350B',
N30: '#EBECF0',
N800: '#172B4D'
};
1 change: 1 addition & 0 deletions packages/pretty-proptypes/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as Prop } from './Prop';
export { default } from './Props';
export { default as PropsTable } from './PropsTable';
export { default as components } from './components';
export { default as HybridLayout } from './HybridLayout';
2 changes: 2 additions & 0 deletions stories/FlowComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import React from 'react';

type FlowComponentProps = {
// This prop is required as it is not optional and has no default
requiredProp: any,
// This prop is a string
stringProp: string,
// This prop is a number
Expand Down
2 changes: 2 additions & 0 deletions stories/TypeScriptComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ interface DummyInterface {
}

type TypeScriptComponentProps = {
// This prop is required as it is not optional and has no default
requiredProp: any;
// This prop is a string
stringProp: string;
// This prop is a number
Expand Down
17 changes: 17 additions & 0 deletions stories/layout/Default.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

import Props from 'pretty-proptypes';
import TypeScriptComponent from '../TypeScriptComponent';

export default {
title: 'Example/Layouts/Default',
component: Props
};

const Template = args => args.component;

export const Default = Template.bind({});

Default.args = {
component: <Props component={TypeScriptComponent} heading="Primitive types" />
};
35 changes: 35 additions & 0 deletions stories/layout/Hybrid.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';

import { HybridLayout } from 'pretty-proptypes';
import { css, Global } from '@emotion/core';
import TypeScriptComponent from '../TypeScriptComponent';

import { colors } from '../../packages/pretty-proptypes/src/components/constants';

export default {
title: 'Example/Layouts/Hybrid',
component: HybridLayout
};

const Template = args => args.component;

export const Base = Template.bind({});

Base.args = {
component: <HybridLayout component={TypeScriptComponent} heading="Primitive types" />
};

export const WithReset = Template.bind({});

WithReset.args = {
component: (
<>
<Global
styles={css`
@import 'https://unpkg.com/@atlaskit/[email protected]/dist/bundle.css';
`}
/>
<HybridLayout component={TypeScriptComponent} heading="Primitive types" />
</>
)
};
Loading

0 comments on commit 84e9241

Please sign in to comment.