@element-public/cerebro
v1.0.0
Published
Documentation and code generation utility for element-public components.
Downloads
3
Readme
element-public Cerebro
Documentation and code generation utility for element-public components.
See changelog below to see the latest changes in this document.
The purpose of this format is to enable a single source of truth for component documentation, specifically for props, content, and events.
It is recommended to read this content on GitHub as the formatting is better than VSCode's and is easier to read. Optionally, the Markdown Preview Enhanced or Markdown Preview Github Style plugins also improve legibility.
Table of Contents
- element-public Cerebro
- Table of Contents
- Usage
- Generated Files
- Documenting Sub-Components
- Schema
component
(string, required)description
(string, required)deprecated
(string, optional)directory
(string, optional)exclusive
(string, optional)vueComponent
(string, optional)reactComponent
(string, optional)internal
(boolean, optional)notes
(object array, optional)events
(object array, optional)contentProps
(object array, optional)props
(object array, optional)name
(string, required)type
(string, required)default
(boolean, required)description
(string, required)acceptedValues
(string array, optional)deprecatedValues
(string array, optional)deprecated
(string, optional)required
(boolean, optional)scope
(string, optional)internal
(boolean, optional)control
(string, optional)controlDefault
(string, optional)controlOptions
(string, optional)vueName
(string, optional)vueDefault
(string, optional)reactName
(string, optional)shape
(Object, Optional)exclusive
(string, optional)
- Deprecation Process
- Tips
- Changelog
Usage
One time setup for element-public-react and element-public-vue
A file called generateDocs.js
should be placed into the /scripts
directory
in the root of each library. The file should contain the following script:
const fsExtra = require('fs-extra');
const prettier = require('prettier');
const { generateLibraryDocs } = require('@element-public/cerebro');
// See README.md in the element-public-cerebro repo for more details about this script.
generateLibraryDocs(
fsExtra,
prettier,
'<platform>',
`${process.cwd()}/src/components`
);
Note: Each library (react and vue) will need a devDependency for fs-extra
and prettier
. These will be dependency injected into generateLibraryDocs()
.
This is due to the fact that the fs (which fs-extra and prettier) package is
meant to only be run by node and not in a browser.
Note: "<platform>" should be one of two values, either "react"
or
"vue"
. For example:
generateLibraryDocs(
fsExtra,
prettier,
'react',
`${process.cwd()}/src/components`
);
In each major component library (element-public-react
and element-public-vue
) an npm
script should be created to execute this script:
"docs":"node ./scripts/generateDocs.js"
Note: The shared library component docs will automatically be built into the element-public-website project as long as the package version is kept up to date.
README.md updates
Each component README.md will need to be updated with the following html comments. They should replaced the existing props & events tables. If they do not exist or do not appear as expected, the file will not be updated. Example:
<!--- Props Tables: Do not delete this line or put anything between these comments, it will be overwritten -->
<!--- End Props Tables: Do not delete this line or put anything between these comments, it will be overwritten -->
Warning any content placed between these comments will be overwritten!
One time setup for element-public-website
For each component index.md
(example: content/button/index.md
) replace the
props
section at the top of the page and replace it with the docs
array,
which will contain the names of the component document(s) (as seen in this
directory) to be included. Example:
docs:
[
'card.docs.json',
'cardActions.docs.json',
'cardContent.docs.json',
'cardFilter.docs.json',
'cardMedia.docs.json',
'cardTitle.docs.json'
]
Normal Usage
To update the generated documentation simple run the npm run docs
command in
the root of the project. There is a good chance this will be automatically
executed at some future point.
Note: Once setup, the shared library component docs will automatically be pulled into the element-public-website project as long as the package version is kept up to date.
Generated Files
The makedocs utility, when invoked in a library will produce several fully
generated files: a *.d.ts
per each component/sub-component,
/defs/propTypes.js
(for React), /defs/props.js
(for Vue) and
/defs/argTypes.json
. it will also modify the existing component README if
setup properly.
*.d.ts
One *.d.ts
file will be generated per component, including sub-components.
These will be named with the component name (ex. Button.d.ts
). These files
serve 2 important purposes. First they provide the necessary type definition for
Typescript to use our library. Second, they provide enhanced intellisense for
Visual Studio Code. No other steps are needed for these to work.
These files are fully automated and should not need to be modified manually.
argTypes.js
This file, located in the /defs
directory in the root of the component, is
specifically for Storybook to display accurate details in the props table. To
enable it to work, for each component you must import the argTypes into the the
stories file (component.stories.js) and add it to the default export
configuration object. Example:
import argTypes from './defs/argTypes.js';
export default {
title: 'Components/Button',
component: Button,
argTypes
})
};
To add to the argTypes (for example additional storybook controls setup) you can
use the mergeDeep()
utility in the @element-public/shared package. Example:
export default {
title: 'Components/Button',
component: Button,
argTypes: mergeDeep(argTypes, {
altColor: {
control: {
type: 'boolean'
}
}
})
};
propTypes.js
(React only)
This file, located in the /defs
directory in the root of the component,
contains both propTypes
as well as defaultProps
for each component and
sub-component. PropTypes will be exported as ComponentPropTypes
and
defaultProps
will be exported as ComponentDefaultProps
.
These will need to be imported and wired-up per component/sub-component.
Example:
import {ButtonPropTypes, ButtonDefaultProps} from './defs/propTypes.js';
export default Button (props) => {
//...
}
Button.propTypes = ButtonPropTypes;
Button.defaultProps = ButtonDefaultProps;
props.js
(Vue only)
This file, located in the /defs
directory in the root of the component,
contains the props
objects for each component and sub-component. The props
object will be exported as ComponentProps
.
These will need to be imported and wired-up per component/sub-component.
Example:
import { ButtonProps } from './defs/props.js';
export default {
name: 'Button',
props: ButtonProps
// ....
};
README.md
The makedocs utility will update any existing README.md as long as it contains the expected start and end comment tags. If they do not exist or do not appear as expected, the file will not be updated. Example:
<!--- Props Tables: Do not delete this line or put anything between these comments, it will be overwritten -->
<!--- End Props Tables: Do not delete this line or put anything between these comments, it will be overwritten -->
The readme will be updated with 3 tables: props (excluding content props), content props (including slots and react nodes), and events.
Additional tables may be generated for deprecated props, content props and events as needed.
Warning any content placed between these comments will be overwritten!
Documenting Sub-Components
Several components are made up of smaller components that can be composed by the
end-user. For example Card or Drawer. These sub-components should be captured as
a separate file. So for example for Card we have card.docs.json
,
cardActions.docs.json
, cardContent.docs.json
, etc. To make sure these get
documented correctly you must set the childOf
prop on each sub-component. For
example cardActions
will have a "childOf": "Card"
.
For components or sub-components that are generally not exposed publicly (atomic
components) such as FormField
, DateInput
, or Ripple
, mark them as
"internal":true to prevent them from being
expressed in readmes, website or other public facing documentation. The reason
to keep these documented is for automation as well as element-public-developer
reference - it's easy to forget the purpose or intention for these components or
their props. It may also help developers wanting leverage our atomic pieces to
build their own custom components.
Schema
Component docs are stored as json files with all of the necessary fields to generate the most common props documentation.
component
(string, required)
The name of the component. It must match the common component name in the libraries and website. The component name should be PascalCased (each word starts with an upper case, including the first) and no spaces between words.
description
(string, required)
The component description. This should explain the general purpose and use of the component.
deprecated
(string, optional)
This will mark the component as deprecated in the generated docs.
directory
(string, optional)
By default this is the same as the component name, however the directory field can be used to override the given directory name.
Added to support "Chip/Chips/ChipSet" mismatch.
exclusive
(string, optional)
This component is exclusive to the given platform. Value may be either "react" or "vue". If "vue" is specified the component will not be documented in react and vice-versa. This should rarely be used.
vueComponent
(string, optional)
The vueComponent field can be used to force a custom component name when the component names do not match between platforms. This should rarely be used.
Added to support Datepicker/Datepicker
naming mismatch. This is possible
redundant with the directory field and the two may be merged in time.
reactComponent
(string, optional)
The reactComponent field can be used to force a custom component name when the component names do not match between platforms. This should rarely be used.
internal
(boolean, optional)
This will mark the component for internal use only. This will prevent the component from being documented in the readme or website, but will still offer props/propTypes/intellisense support to enable easier development.
See Documenting Sub-Components for more context.
notes
(object array, optional)
The notes field is a way to capture usage advice to be rendered in a readme or on the website. It does not current output anywhere, but the goal is to move towards a completely generated readme (and possible generated usage guidelines in website.)
title
(string, optional)
The section title.
events
(object array, optional)
Events contains all of event props (react) and emitted events (vue).
name
(string, required)
The name field should be in the standard camelCase style (it will be appropriately formatted for vue).
default
(boolean, required)
The default field is the value the user should expect if this named prop is not explicitly set.
Acceptable values include null
or an inline function.
Warning: props.default values must always be quoted. (ie.
"default": "null"
is acceptable where "default": null
would be incorrect.)
description
(string, required)
The description field should be a useful explanation of the purpose and use of the property
deprecated
(string, optional)
Place any deprecation warnings here. It should be a helpful message explaining
the cause for the deprecation as well as any alternatives and should usually be
in the format 'Use x
instead. This change was made to support xyz reason.'. It
is often wise to include the context behind the change.
In any place the prop is documented it will be decorated with the @deprecated
jsdoc tag with the explanation.
Deprecation warnings will also be rendered with the deprecated(...)
syntax in
defs/propTypes.js in React. This functionality might
be added later to the Vue defs/props.js file.
Warning: Do not prefix with the word Deprecated
.
vueName
(string, optional)
The vueName field can be used to force a custom name when rendering documentation in vue that otherwise would not match. This should rarely be used.
vueDefault
(string, optional)
Override the default value when the platform is vue. This should rarely be used.
reactName
(string, optional)
The reactName field can be used to force a custom name when rendering documentation in react that otherwise would not match. This should rarely be used.
returns
(string, optional)
Events only. This is a description of the return value and type when the event is fired.
emits
(string, optional)
Events only and vue specific. This is to indicate what event will be fired in vue.
params
(object array, optional)
This is a proposal and may not be implemented.
Events only. An array of the event parameters
name
(string, optional)
This is a proposal and may not be implemented.
A friendly name for the parameter
type
(string, optional)
This is a proposal and may not be implemented.
A friendly name for the parameter
description
(string, optional)
This is a proposal and may not be implemented.
A description of the parameter.
contentProps
(object array, optional)
Content props contains any render props (react) and slots (vue).
name
(string, required)
The name field should be in the standard camelCase style (it will be appropriately formatted for vue).
default
(boolean, required)
The default field is the value the user should expect if this named prop is not
explicitly set. It is optional for contentProps and events only. These will be
rendered as defaultProps
in defs/propTypes.js for
React and as part of defs/props.js in Vue.
Acceptable values include null
, true
, false
, any valid number, any valid
string, or special tokens.
Special tokens include:
<random-id>
- will be replaced with the appropriate code in the component propTypes and vue default. The appropriate import will be handled as well. Note random id will not work correctly withscope
ofparent
.
Warning: props.default values must always be quoted. (ie.
"default": "null"
is acceptable where "default": null
would be incorrect.)
description
(string, required)
The description field should be a useful explanation of the purpose and use of the property
deprecated
(string, optional)
Place any deprecation warnings here. It should be a helpful message explaining
the cause for the deprecation as well as any alternatives and should usually be
in the format 'Use x
instead. This change was made to support xyz reason.'. It
is often wise to include the context behind the change.
In any place the prop is documented it will be decorated with the @deprecated
jsdoc tag with the explanation.
Deprecation warnings will also be rendered with the deprecated(...)
syntax in
defs/propTypes.js in React. This functionality might
be added later to the Vue defs/props.js file.
Warning: Do not prefix with the word Deprecated
.
required
(boolean, optional)
The required field is an indicator that a prop must be set for the component to function. Defaults to false.
This will be used as part of defs/propTypes.js in React and defs/props.js in Vue.
controlDefault
(string, optional)
This will set the default value for the prop when used as a storybook control.
Note: This value will default to the default
prop.
vueName
(string, optional)
The vueName field can be used to force a custom name when rendering documentation in vue that otherwise would not match. This should rarely be used.
vueDefault
(string, optional)
Override the default value when the platform is vue. This should rarely be used.
reactName
(string, optional)
The reactName field can be used to force a custom name when rendering documentation in react that otherwise would not match. This should rarely be used.
props
(object array, optional)
The props array should contain all props relating to a component, including events and content props (such as slots and render props).
Props can be grouped by one of 3 categories: "props", "contentProps", and "events". These should be noted with the "group" field. If no group is provided, it is assumed to be a standard property.
name
(string, required)
The name field should be in the standard camelCase style (it will be appropriately formatted for vue).
type
(string, required)
The type field is required for most props and should be a valid javascript type.
Note: If a prop can accept more than one type, use the pipe |
operator to
separate the types. Example: string|object
.
Note: Arrays should be notated as [type]
. Example: [string]
. Arrays also
support multi-types, ex: [string]|[object]
.
default
(boolean, required)
The default field is the value the user should expect if this named prop is not explicitly set.
Acceptable values include null
, true
, false
, any valid number, any valid
string, or special tokens.
Special tokens include:
<random-id>
- will be replaced with the appropriate code in the component propTypes and vue default. The appropriate import will be handled as well. Note random id will not work correctly withscope
ofparent
.
Warning: props.default values must always be quoted. (ie.
"default": "null"
is acceptable where "default": null
would be incorrect.)
description
(string, required)
The description field should be a useful explanation of the purpose and use of the property
acceptedValues
(string array, optional)
For props that can only accept certain values. These will be rendered as
PropTypes.oneOf(...)
for react PropTypes and otherwise as part of the
description in other locations.
deprecatedValues
(string array, optional)
For props that can only accept certain values, and one or more of those values have been deprecated.
deprecated
(string, optional)
Place any deprecation warnings here. It should be a helpful message explaining
the cause for the deprecation as well as any alternatives and should usually be
in the format 'Use x
instead. This change was made to support xyz reason.'. It
is often wise to include the context behind the change.
In any place the prop is documented it will be decorated with the @deprecated
jsdoc tag with the explanation.
Deprecation warnings will also be rendered with the deprecated(...)
syntax in
defs/propTypes.js in React. This functionality might
be added later to the Vue defs/props.js file.
Warning: Do not prefix with the word Deprecated
.
required
(boolean, optional)
The required field is an indicator that a prop must be set for the component to function. Defaults to false.
This will be used as part of defs/propTypes.js in React and defs/props.js in Vue.
scope
(string, optional)
For react, in the rare case that a property's default value needs to be used by
another property's default value, setting this to parent
will elevate the prop
to outside of the defaultProps object.
This prop was added for the pagination
itemsPerPageOptions
property which is
referenced by itemsPerPage
;
Example output:
un-scoped (produces error):
export const PaginationDefaultProps = {
itemsPerPage: itemsPerPageOptions[0],
itemsPerPageOptions: [10, 25, 50, 100, 200]
};
scoped to parent
:
const itemsPerPageOptions = [10, 25, 50, 100, 200];
export const PaginationDefaultProps = {
itemsPerPage: itemsPerPageOptions[0],
itemsPerPageOptions
//...
};
internal
(boolean, optional)
This will mark the prop for internal use only. This will prevent the prop from being documented in the readme or website, but will still offer props/propTypes/intellisense support to enable easier development.
Examples props include id
, className
, onBlur
which are common props that
we need to add special handling, but is otherwise transparent to the user.
control
(string, optional)
This will override the storybook control type (which will be automatically set in most cases).
Acceptable values are array
, boolean
, number
, range
, object
, radio
,
inline-radio
, check
, inline-check
, select
, multi-select
, text
,
color
, date
. See https://storybook.js.org/docs/react/essentials/controls for
full control descriptions.
Note: It may necessary for certain "enum" style controls (such as select,
radio, etc) to populate the controlOptions
array, though this can be done in
the story itself. controlOptions
will be defaulted to acceptedValues.
Note: You must also bind the control args to the component you are testing in the story itself.
Example:
// This will spread all argType controls to the button
const Basic = controls => {
return <Button {...controls}>
}
controlDefault
(string, optional)
This will set the default value for the prop when used as a storybook control.
Note: This value will default to the default
prop.
controlOptions
(string, optional)
This will set the list options for the prop when used as a storybook control when using an "enum" style control such as select, radio, etc.
Note: This will default to acceptedValues
.
vueName
(string, optional)
The vueName field can be used to force a custom name when rendering documentation in vue that otherwise would not match. This should rarely be used.
vueDefault
(string, optional)
Override the default value when the platform is vue. This should rarely be used.
reactName
(string, optional)
The reactName field can be used to force a custom name when rendering documentation in react that otherwise would not match. This should rarely be used.
shape
(Object, Optional)
The shape field describes a specific object shape to be used as a
PropType.shape. The format is { "fieldname": "type" }
.
ex.
"shape": {
"to": "date",
"from": "date",
"days": "number",
"daysOfMonth": "[number]",
"dates": "[date]",
"ranges": [{
"from": "date",
"to": "Date"
}],
"customPredictor": "function"
}
exclusive
(string, optional)
This prop is exclusive to the given platform. Value may be either "react" or "vue". If "vue" is specified the property will not be documented in react and vice-versa. This should rarely be used.
Deprecation Process
Deprecation of acceptedValues
for a prop
- Add the new values to the
acceptedValues
array - Move the old/deprecated values to
deprecatedValues
array - Update values used in tests
- Test with new values (make sure that console warnings are accurate)
- Example: kebab case values for
themeColor
prop on Typography component, replaced with camel case values
Deprecation of a prop
- Add
deprecated
field under prop - Mention deprecation in prop
description
- Test (make sure that console warnings are accurate)
- Example:
embedded
prop on Textfield component, replaced withvariant="embedded"
Deprecation of a component
- Set deprecation warnings manually (usually by calling edsWarn from a
useEffect
ormounted()
) - Mention deprecation in component
description
- Test (make sure that console warnings are accurate)
- Example: Autocomplete component, replaced with features in Select component
Tips
Generally you should organize the props array in alphabetical order, though that's just to make it easier maintainers to find a prop - the final documentation will always have sorted props. Whether or not it's advantageous to organize props by the "group" field is still TBD, so use your own discretion.
Make sure descriptions are complete sentences, including punctuation.
If a component accepts children
or a default slot
, make sure it's documented
in addition to what type of content is expected (ex. "Accepts any valid
markup.", "Expects one of CardActions, CardContent, CardFilter, CardMedia, or
CardTitle." or "Most commonly a list, but accepts any valid markup.").
If a prop takes an object please describe the object using shape and document thoroughly in the description.
Documentation is an opportunity to guide developers towards proper use of the object. It is encouraged to provide some context when writing prop descriptions - such as when you would/wouldn't want to use a particular prop or if several props are often used in combination, call that out.
Changelog
v2
- Updated documentation to reflect the new props, events, and contentProps schemas.
- Reformatted Schema slightly.
v1.6
- Added props.scope.
- Added back
<random-id>
support token forprops.default
v1.5
- Added props.vueDefault.
v1.4
- Added props.control.
- Added props.controlDefault.
- Added props.controlOptions.
v1.3
- Changed guidance on Documenting Sub-Components to include all sub-components.
- Added Table of Contents.
- Added additional links in this document for easier navigation.
- Added explanations for several props as to how and where they will be used.
- Added internal and props.internal.
- Added deprecated field at the component level.
- Updated Generated Docs to better reflect existing files.
- Added propTypes.js (React only) section.
- Added props.js (Vue only) section.
- Added notes field to schema.
- Added vueComponent and
- Updated props.deprecated usage guidelines.
- Changed props.group from
Optional
toRequired/Optional
. - Changed argTypes.json to argTypes.js and updated description.
- Changed index.d.ts to *.d.ts.
- Updated props.default recommendations to include an acceptable values, special tokens, and quotation warning.
- Changed props.type special token to
<children-default>
hoping to make it more clear. reactComponent to allow overriding the component name by platform. This was necessary for Datepicker.
v1.2
- Added Documenting Sub-Components section
- Added props.acceptedValues and props.deprecatedValues.
v1.1
- Added Tips section.
- Added directory prop.
- Added instructions for element-public-website setup.
- Added README.md section to one time setup.
- Updated props.default recommendation.
- Updated exclusive, props.exclusive, props.vueName, props.reactName scarey warning to be less harsh (there are some legitimate situations we need them).
- Updated one time setup for each libraries with new script.
- Updated mergeDeep import in the argTypes.json section.
- Added this changelog.
v1
- Initial documentation