npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@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

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 with scope of parent.

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 with scope of parent.

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 with variant="embedded"

Deprecation of a component

  • Set deprecation warnings manually (usually by calling edsWarn from a useEffect or mounted())
  • 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 for props.default

v1.5

v1.4

v1.3

v1.2

v1.1

v1

  • Initial documentation