Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced prop type definitions #105

Merged
merged 49 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
6e4875d
chore: remove extra whitespace
jerelmiller Jun 6, 2020
86e9e60
chore: unnest CSS
jerelmiller Jun 6, 2020
53c948e
chore: move classname to markdown instead of outer component
jerelmiller Jun 6, 2020
072c6ec
refactor: Make type a complex value to allow other info about it
jerelmiller Jun 6, 2020
87d6b7d
chore: Set argsIgnorePattern in eslint
jerelmiller Jun 6, 2020
a26b994
feat: Create shell for PropTypeInfo component
jerelmiller Jun 6, 2020
990d0ad
refactor: Add helper function to determine type name from a prop type
jerelmiller Jun 6, 2020
9dcaeee
chore: Rename variable in extractPropTypes
jerelmiller Jun 6, 2020
a549464
chore: Rename to getNormalizedTypeName
jerelmiller Jun 6, 2020
1d33f8f
feat: Add helper getRawTypeName function
jerelmiller Jun 6, 2020
110f52b
refactor: isUnion takes a prop type
jerelmiller Jun 6, 2020
80485ed
feat: Add helper function for getting default value
jerelmiller Jun 6, 2020
f40c603
feat: Use getDefaultValue helper in useComponentDoc
jerelmiller Jun 6, 2020
c833efd
chore: rename toStaticProperty
jerelmiller Jun 6, 2020
b5a6c83
chore: Include type info as meta for now
jerelmiller Jun 6, 2020
2701f51
chore: Remove old getDefaultValue function
jerelmiller Jun 6, 2020
a1d0ec3
chore: Fix prop type names in test
jerelmiller Jun 6, 2020
8a4a540
fix: Move isEnum check first
jerelmiller Jun 6, 2020
0a785fb
chore: Remove old propConstants file
jerelmiller Jun 6, 2020
873ae98
feat: Add deprecation prop to component doc
jerelmiller Jun 7, 2020
d390f5d
feat: Add deprecation message to prop list
jerelmiller Jun 7, 2020
b458b4a
refactor: Extract prop type definition into own function
jerelmiller Jun 7, 2020
9a74761
chore: Move getPropTypeDefinition into utils file
jerelmiller Jun 7, 2020
004dde1
feat: Add test and implementation to return meta for a func type
jerelmiller Jun 7, 2020
a1e86c2
feat: Add test and implementation to get meta for shape types
jerelmiller Jun 7, 2020
650818a
feat: Handle oneOf when returning meta info
jerelmiller Jun 7, 2020
b05948b
feat: Implement meta info for arrayOf types
jerelmiller Jun 7, 2020
77022be
feat: Implement meta for union types
jerelmiller Jun 7, 2020
bd79ea7
chore: Add advanced case for getting prop info
jerelmiller Jun 7, 2020
9dd5137
feat: Render function definition for func prop types
jerelmiller Jun 7, 2020
918d6e0
feat: render a comma between multiple args to func definition
jerelmiller Jun 7, 2020
09d8a69
feat: Render union type info for union props
jerelmiller Jun 7, 2020
eea8def
chore: Ensure space after comma
jerelmiller Jun 7, 2020
0ad9dbe
chore: Fix test name
jerelmiller Jun 7, 2020
f973f9f
fix: Return type info for union types
jerelmiller Jun 7, 2020
bc5e17a
feat: Render union types prop info
jerelmiller Jun 7, 2020
44b55ce
refactor: Move PropTypeInfo into PropList because of recursiveness
jerelmiller Jun 8, 2020
dc8b14b
feat: Implement shape prop type
jerelmiller Jun 8, 2020
5a7c884
chore: Add space below description
jerelmiller Jun 8, 2020
68f1944
feat: Implement arrayOf for prop list
jerelmiller Jun 8, 2020
a387e94
chore: Fix spacing for type name in function definition
jerelmiller Jun 8, 2020
1e67d21
Merge remote-tracking branch 'origin/master' into jerel/advanced-props
jerelmiller Jun 8, 2020
bd8399c
feat: Handle different arrayOf values
jerelmiller Jun 8, 2020
521801f
chore: Remove old unused code to generate prop type docs
jerelmiller Jun 8, 2020
0d5fb69
feat: Add prop type examples for each component
jerelmiller Jun 8, 2020
7924a7e
fix: Ensure shape prop types adhere to nested enums
jerelmiller Jun 8, 2020
dcdb3fa
chore: Fix failing test due to addition of examples
jerelmiller Jun 8, 2020
97b7a1b
fix: Handle enums that are nested in a shape prop type
jerelmiller Jun 8, 2020
2e4b9d9
chore: Fix spacing on sequential shape prop types
jerelmiller Jun 8, 2020
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
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module.exports = {
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
ignoreRestSiblings: false,
},
],
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@mdx-js/mdx": "^1.6.4",
"@mdx-js/react": "^1.6.4",
"classnames": "^2.2.6",
"date-fns": "^2.14.0",
"gatsby": "^2.20.25",
"gatsby-image": "^2.3.4",
"gatsby-plugin-google-tagmanager": "^2.3.3",
Expand Down
21 changes: 14 additions & 7 deletions src/components/FunctionDefinition.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import React from 'react';
import React, { Children } from 'react';
import PropTypes from 'prop-types';
import Markdown from 'react-markdown';
import styles from './FunctionDefinition.module.scss';

const ParamDescription = ({ children, ...props }) => (
<span {...props} className={styles.paramDescription}>
{'//'} {children}
</span>
);
const ParamDescription = ({ children, ...props }) => {
if (Children.toArray(children).length === 0) {
return null;
}

return (
<span {...props} className={styles.paramDescription}>
{' //'} {children}
</span>
);
};

ParamDescription.propTypes = {
children: PropTypes.node,
Expand All @@ -24,7 +30,8 @@ const FunctionDefinition = ({ params, returnValue }) => {
<span className={styles.paramName}>
{param.type.startsWith('...') ? `...${param.name}` : param.name}:{' '}
</span>
<span className={styles.type}>{param.type} </span>
<span className={styles.type}>{param.type}</span>
{i !== params.length - 1 && ', '}
<Markdown
source={param.description}
renderers={{
Expand Down
7 changes: 2 additions & 5 deletions src/components/FunctionDefinition.module.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.container {
font-family: 'Menlo', 'Consolas', monospace;
font-family: var(--code-font);
font-size: 0.875rem;
line-height: 1.5;
}
Expand All @@ -9,11 +9,8 @@
}

.param {
margin-left: 1rem;
}

.paramName {
color: var(--color-neutrals-700);
margin-left: 1rem;
}

.paramDescription {
Expand Down
115 changes: 107 additions & 8 deletions src/components/PropList.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,70 @@
import React from 'react';
import cx from 'classnames';
import PropTypes from 'prop-types';
import ReactMarkdown from 'react-markdown';
import FunctionDefinition from './FunctionDefinition';
import Markdown from 'react-markdown';
import ReferenceExample from './ReferenceExample';
import styles from './PropList.module.scss';
import { format } from 'date-fns';

const PropTypeInfo = ({ type }) => {
switch (type.raw) {
case 'func':
return (
<FunctionDefinition
returnValue={type.meta.returnValue}
params={type.meta.params}
/>
);
case 'arrayOf': {
const { itemTypes } = type.meta;

return itemTypes.raw === 'oneOf' ? (
<div className={styles.listLike}>
<div>{'<Array of'}</div>
<div className={styles.arg}>
<PropTypeInfo type={itemTypes} />
</div>
<div>{'>'}</div>
</div>
) : (
<PropTypeInfo type={itemTypes} />
Copy link
Contributor

Choose a reason for hiding this comment

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

recursive react! never thought about doing this but this is super cool

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! Its not often that you need it (I can only think of 1 other time I've done this), but super useful when you do need it. It helped me so much here.

);
}
case 'oneOf':
return (
<div className={styles.listLike}>
<div>{'<One of'}</div>
<div className={styles.arg}>
{type.meta.constants.map((constant) => (
<div key={constant}>{constant},</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

We might want to trim off the , on the last item in this list. Maybe we could do a .join(',) on an array of divs and then slice or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only reason I didn't do that was only because One Core has trailing commas:

Screen Shot 2020-06-09 at 9 51 04 AM

This isn't to say this is our desired result for the new dev site, but just the reason I did this to begin with. Should we do the same? Or remove the last comma?

FYI, .join() unfortunately doesn't work on the <div /> call since the return value of <div /> is an object (since its calling React.createElement under the hood). Calling .join unfortunately results in an [object Object] rendered to the screen. That being said, we can use indexes to determine whether to render the comma or or not depending on if its the last item.

))}
</div>
<div>{'>'}</div>
</div>
);
case 'oneOfType':
return type.meta.types.map((type, idx) => (
<PropTypeInfo key={idx} type={type} />
));
case 'shape':
return (
<div className={styles.shape}>
<h4>shape</h4>
<PropList propTypes={type.meta.types} />
</div>
);
default:
return null;
}
};

PropTypeInfo.propTypes = {
type: PropTypes.shape({
raw: PropTypes.string.isRequired,
meta: PropTypes.object,
}),
};

const PropList = ({ propTypes }) => {
if (propTypes.length === 0) {
Expand All @@ -11,26 +74,55 @@ const PropList = ({ propTypes }) => {
return (
<div>
{propTypes.map(
({ name, description, isRequired, type, defaultValue }) => {
({
name,
description,
deprecation,
examples,
isRequired,
type,
defaultValue,
}) => {
return (
<div key={name} className={styles.container}>
<div className={styles.info}>
<h3>
{name}{' '}
{name}
{isRequired && (
<span className={styles.required}>required</span>
<span className={styles.flagged}>required</span>
)}
{deprecation && (
<span className={styles.flagged}>deprecated</span>
)}
</h3>
<div className={styles.type}>{type}</div>
<div className={styles.type}>{type.name}</div>
{defaultValue !== undefined && (
<div className={styles.default}>
<p>DEFAULT</p>
<p>{String(defaultValue)}</p>
</div>
)}
</div>
<div className={styles.details}>
<ReactMarkdown source={description} />
<div className={styles.propInfo}>
{deprecation && (
<div className={styles.deprecation}>
<div className={styles.deprecationDate}>
Due {format(new Date(deprecation.date), 'MMMM do, yyyy')}
</div>
<Markdown
className={styles.markdownContainer}
source={deprecation.description}
/>
</div>
)}
<Markdown
className={cx(styles.details, styles.markdownContainer)}
source={description}
/>
<PropTypeInfo type={type} />
{examples.map((example, idx) => (
<ReferenceExample key={idx} example={example} />
))}
</div>
</div>
);
Expand All @@ -45,8 +137,15 @@ PropList.propTypes = {
PropTypes.shape({
name: PropTypes.string.isRequired,
description: PropTypes.string,
deprecation: PropTypes.shape({
Copy link
Contributor

Choose a reason for hiding this comment

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

if a PropType doesn't take the shape value (for example there's no deprecation) will this value be null/undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is correct! You can see it set explicitly to null here: https://github.com/newrelic/developer-website/pull/105/files#diff-0645d45905de3e0b87864beb8891fb71R182

I don't set the isRequired on this shape since I know that it can be null.

date: PropTypes.number,
description: PropTypes.string,
}),
isRequired: PropTypes.bool,
type: PropTypes.string,
type: PropTypes.shape({
...PropTypeInfo.propTypes.type,
name: PropTypes.string.isRequired,
}),
defaultValue: PropTypes.string,
})
),
Expand Down
68 changes: 58 additions & 10 deletions src/components/PropList.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,76 @@
.info {
width: 30%;

.type {
color: var(--color-neutrals-600);
h3 {
margin-top: 0;
}
}

.default {
margin-top: 2rem;
color: var(--color-neutrals-700);
.default {
margin-top: 2rem;
color: var(--color-neutrals-700);

p:first-of-type {
font-size: 0.75rem;
}
p:first-of-type {
font-size: 0.75rem;
}
}

.type {
color: var(--color-neutrals-600);
}

.deprecation {
padding: 0.25rem;
background: var(--color-red-100);
margin-bottom: 1rem;
}

.deprecationDate {
color: var(--color-red-400);
font-weight: 600;
margin-bottom: 1rem;
}

.propInfo {
width: 70%;
}

.markdownContainer > *:first-child {
margin-top: 0;
}

.details {
font-size: 1.25rem;
width: 70%;

&:not(:last-child):not(:empty) {
margin-bottom: 1rem;
}
}

.required {
.flagged {
font-size: 0.75rem;
color: var(--color-red-400);
text-transform: uppercase;
margin-left: 0.5rem;
}

.arg {
padding-left: 1rem;
}

.listLike {
font-family: var(--code-font);
font-size: 0.875rem;
color: var(--color-neutrals-600);
}

.shape {
&:not(:last-child) {
margin-bottom: 2rem;
}

h4 {
margin-top: 0;
color: var(--color-neutrals-600);
}
}
1 change: 1 addition & 0 deletions src/components/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
--primary-font-family: 'open sans', sans-serif;
--secondary-font-family: 'effra', sans-serif;
--tertiary-font-family: 'Ovo', serif;
--code-font: 'Menlo', 'Consolas', monospace;
}

/*-- Reset --*/
Expand Down
Loading