Skip to content

Latest commit

 

History

History
574 lines (446 loc) · 39.7 KB

CONTRIBUTING.md

File metadata and controls

574 lines (446 loc) · 39.7 KB

Contributing Code

The preferred process

  1. Create a new issue before starting your project so that we can keep track of what you are trying to add/fix. That way, we can also offer suggestions or let you know if there is already an effort in progress.
  2. Fork this repository, then clone that forked repository locally.
  3. Create a topic branch for the issue that you are trying to add locally.
  4. Edit the code locally and push to your username's forked repository. Be sure to add a Storybook story for new features.
  5. Send us a well-documented pull request based on the branch from your forked repository.

GitHub pull requests should meet the following criteria:

  • descriptive title
  • brief summary
  • @mention several relevant people to review the code
  • add helpful GitHub comments on lines where you have questions or concerns

We'll review your code, suggest any needed changes, and merge it in. Thank you.

  • UX pattern / design must exist in SLDS. Components in the process of being added to SLDS will be considered as prototypes.
  • All new props and components need tests. Please review the testing readme
  • If you are adding a feature, add a story to the React Storybook that uses your feature, so that reviewers can test it.
  • Stories are stored in examples folder along with Documentation site examples. To add a story to the interactive examples on the documentation site, add the JSX file to examples/index.js. All examples that are present for a component in the SLDS website or it's internal site should be created as a Storybook story and listed in examples/index.js.
  • Prop description tables on the documentation site are generated from propType comments within the component. All props should have a Tested with snapshot testing. or Tested with Mocha framework. notice in them.
  • Introductory component descriptions are generated from the comment before the component declaration.

The review process

This is an internal open-source project. You may be asked to review code submitted by others. To do this:

  • git clone this repository
  • npm install
  • Pull down the pull requested branch. It will be within the contributor's forked repository. For instance, git checkout -b interactivellama-data-table-width master then git pull git@github.com:interactivellama/design-system-react.git data-table-width. You could also create an additional remote and pull down the branch directly.
  • npm start and review the appropriate React Story example at http://localhost:9001/. Open http://localhost:8001/ and confirm that tests are passing in your environment.
  • Check that any modified or added examples for the documentation site are working and are present in examples/index.js. See Releasing for instructions.

Concepts and Best Practices

What we've learned about building React components for the enterprise

Introduction to presentational components

If you are new to React, you may be trained to design components in a more complicated way than they need to be. Please prioritize the simple and the flexible. The gist of presentational components is to be a template that takes in data and passes out user events and related data to callback functions. One over-simplified way to approach it is to consider these components as Handlebars templates with event listeners. The goal is for engineers to not have to think about markup and stylesheets.

  • Take data and UI data, such as disabled buttons, from parent via props to display data and UI state correctly. Don't manipulate props with string concatenations, array pushes, and sorting within components.
  • Pass mouse and keyboard events and related event data, such as the item data for the item that was clicked, up to parent state machine, so it can decide how to manipulate it's child components' props.
  • Parent component should be the only component that changes data. Components should be data stateless. Only UI state, such as "is this dialog open?" should be within components.

Think of others first

  • # Consider your audience. This project is not Bootstrap, and we've built frameworks on top of Bootstrap. The primary audience for this project is software engineers yearning to easily implement the design artifact handed to them. Yes, contributors should over-document and explain much as you need to, but you do not need to have components just work when you drop them on the page. Read on for more about limiting internal component state.

  • # Put yourself in the consuming developer mindset. "I just updated. What just broke and why?" Why does the React child component become the the DOM parent node? Write as long of a prop description comment that is needed to understand the concept. Need to sunset a prop or change the variable type accepted? Write backwards compatible code and add console warnings that will only run in development. See the checkProp paradigm. If the test can become an independent module and work in multiple components, add it to the design-system-react/utilities folder. Some examples include:

    • A component has children without a specified displayName
    • Determine if trigger can be tabbed to
    • Require one of multiple prop, but not both or only one of specified properties
    • Warnings of property deprecation, sunsetting, and future changes
  • # Any text the user can read (including text for screenreaders) should be able to be set via a prop for internationalization purposes. Within the component, do not concatenate strings. This assumes that you know the word order of all languages. Strings should be passed into props in their entirety.

  • # All assistive text for accessibility and visible text should be grouped in an object and passed in with a prop, assistiveText and labels respectively. This will allow consuming developers to easily find and map text to localize it.

  • # React component hierarchy doesn't always mean HTML tag hierarchy. Sometimes children become the wrapping component.

  • # Place child components not intended to be part of the public API within a folder labelled private. All other React components should be considered public (and considered within the scope of Semantic Versioning), and can be used by developers in their own JSX within their application. See Child component decorator pattern

  • # Use loose coupling and weak connascence. The goal should be that a contributor can understand one piece of code without understanding another and be able to easily make updates in the future. You want weak connascence between components or components and the application (such as events) and not strong connascence. This makes it easier to update one component when modifying another in the future. How easy it will be to change in the future depends on which of the nine types of connascence is being used. For instance, Connascence of Name can be simply updated with Find/Replace. PropTypes and type systems help with Connascence of Type. Connascence of Position with parameters is bad because it relies on the correct order of parameters. Objects with named keys should be used to avoid Connascence of Position.

Limit side effects

  • # Limit use of component state. If the parent application's state engine can handle it with a prop, then don't use state. New components should always start out as controlled by their parent and only be uncontrolled (that is have state) if a use case presents itself. It's better to have a component that needs 20 props set and outputs the correct markup, than to have a component that works with no props set, yet maintains multiple internal states. We like to think of this project as design system templates with minimal logic that happen to work with the React framework. Let the library consumer create a simple container component with state. Read more about controlled components.

    • # All id attributes in the component HTML should be unique to the page, especially if the same component is used. They should be able to be controlled by the consuming developer (not just shortid generated). Most id attributes are used for accessbility or for React key.
    • # Know how smart/stateful React components work together with pure/dumb stateless function components.
    • # It is preferable to only have one stateful top-level class per component in this library. For these top-level components, it’s preferable to leave them stateful (that is, to use class). It's much easier to get the DOM node reference if you need it for such things as measurements. Then, you don't have to go through a lot of hassle to work around not having lifecycle methods. It also allows components to follow the controlled / uncontrolled pattern mentioned below. All sub-components should be stateless and manipulated with props if possible.
    • A Tree should have state. A TreeNode should not.
    • A DataTable should have state, a TableColumn should not.
    • Frequently used items such as badges, pills, buttons or icons should probably not have state.
  • # Encapsulate your components. Global window events like resize or external DOM nodes should not be accessed from the component. body should be used for additional portal mounts. If a menu needs to be smaller to be responsive, consuming applications should listen for the resize event and change the correct props to make the component responsive--or a CSS solution should be found. The component should not be listening to window events directly. Global key press or mouse clicks are fine if used appropriately.

  • # Avoid querying the DOM for nodes you do not own. A ref callback is React's link to a DOM node. It is triggered on render and allows access to the DOM node asynchronously. In most cases within a component, you only need a ref for setting focus, but refs make testing easier. If you find yourself using querySelectorAll() to query parts of this library within your application tests, please stop and submit a contribution that surfaces the DOM node you are needing to test. If you control the contents or children yourself, please use a ref bound to your own JSX DOM node to test. For an example, review the renderDialog method of Popover and its body ref. Once surfaced, a DOM ref becomes part of the public API and will be treated as such.

  • # Non-backward compatible changes to component props or a new design system version that has breaking changes within it is a breaking change and this library should release a major version. SLDS markup alignment and class changes within the current design system release cycle are not considered breaking changes in this library although they may break markup queries. See Avoid querying the DOM for nodes you do not own.. The master branch of this library should be aligned to the code line that is open. When upgrading the design system CSS, please create a archive/stale branch labelled similar to spring-17-2.2.x, except use the correct Salesforce release date and SLDS version that the code was intended to support.

  • # Only submit approved design system patterns. This library should include only components which have approved patterns in Salesforce's design system. If there is a use case from a designer that conforms to a design pattern, that component should be able to be implemented with this library. This library does NOT conform to Salesforce production per se, but is open to being customized to support patterns in production if they remain generic and flexible.

  • # Limit the use of grouping div elements. React components can only have one HTML node / JSX / function return value. A component's render function should have one HTML node as its parent JSX element. Please limit use of extra wrapping div elements in order to align with SLDS markup. Other options include creating additional sub-components or passing an array of components to the parent component to render.

  • # Avoid implied mixins. Instead, import and use shared code and external libraries as libraries, or use higher-order components in order to more easily trace the code execution.

  • # Avoid external dependencies. Do not add external dependencies to production dependencies list unless absolutely necessary. Always consider the "total cost of ownership" for all dependencies.

  • # Use isRequired as much as possible in PropTypes. isRequired is explicit, determines the minimal API of each component, and simplifies a component's internal code. Similar to limiting state, this library prefers simple over flexible, so use isRequired as much as you can without over-burdening the consuming developer.

  • # Avoid inline CSS style/custom classes. We are blessed to have a team of great CSS developers working on our design system. Use their CSS or contribute code back to them.

Be consistent

  • # Use ESlint The larger a codebase becomes and the more contributors the project has, the more organization that is needed. Please use ESlint in your editor (via .eslinttc) and conform to ESlint settings present in ESlint Configuration for SLDS. The team is open to contributions. If a file is touched that has outstanding ESlint errors, please fix the ESlint errors first--in a separate commit. Sometimes special cases require an eslint-disable-line, but please use sparingly.

  • #Do not create in a vaccuum. Familiarize yourself with concepts used in the rest of the library.

  • # Use class/extend, but only extend from React.Component and never another class. This prevents class hierarchies and tight coupling being created beyond the basic React.Component. This completely avoids the gorilla-banana problem (“what you wanted was a banana, what you got was a gorilla holding the banana, and the entire jungle” - Joe Armstrong).

  • # Use consistent callback parameters. All render callbacks, that is callbacks that determine what to render, should pass a data object with named key/values as the second parameter. Event callbacks should pass in the synthetic event, then a data object with named key/values that relate to the event. If an event callback doesn't have a user event that triggered it, pass undefined as the event. This will look something like this.props.onCallback(event, { extraInfo: true }).

  • # Use classNames library. This library makes extensive use of the classnames library for feeding conditional CSS classes into className attributes and allows a variety of types such as string, object, and arrays. Although longer, static classname strings are preferred more than dynamic classnames (dynamic object keys) due to searchability when updating markup. See Classnames section for more details.

  • # The className prop should be on a consistent node. The classes passed into className should be present on the .slds-[COMPONENT] node and not on a container node--nor on a child of .slds-[COMPONENT]. All other className props should be prefixed--such as triggerClassName or containerClassName.

  • # Use boolean prefixes. If a prop is a boolean, please prefix with is or can or suffix it with -able. Never default a prop to true.

Use "the good parts"

  • # Do not mutate data. React tries to optimize and prevent re-rendering the DOM when possible. Many times this is not what you want. Avoid solitary use of push, pop, shift, unshift, sort, reverse, splice and delete when mutating arrays. If you ever have to ask yourself, why isn't my component rendering, this is likely the reason. Use Object.assign() on objects and Array.concat() on arrays instead of directly modifying these variables that are accessed by reference. A common pattern is to deconstruct an array with ... and create a new one. You may consider exploring some new ES6 types such as Set which are collections that help store unique values of any type.

  • # Be careful with rest operators when passively applying unnamed and unknown props to JSX nodes. This concept allows flexibility to the consuming developer, but is difficult to track for maintainers. If rest operators should be used, be sure to deconstruct each one that is actually needed by the JSX nodes, so that the rest operator only handles "unknown props" passed in from the outside developer. In short, don't utilize any properties in the ...props object within the component. After using const { active, className, ...rest } = props; do not go back to using this.prop.* anywhere in the render function.

  • # If a rest operator is already present in your render function and you need to remove additional props so that they do not get passed to a JSX node, use the rest operator along with // eslint-disable-line no-unused-vars to remove the prop from ...rest.

  • # Do not use props in initial state. Please review props in getInitialState is an anti-pattern.

  • # Read JSX Gotchas

  • # No falsy defaults. Do not set default prop values to false. If you need to detect if a variable is false or undefined in order to execute code, use a "double logical NOT operator". If isOpen gives you a "falsey" value, then !!isOpen will make it return the boolean value false. Otherwise it will return true. If you need to test if the value is not undefined, use !== undefined.

  • # External callbacks are optional. Public callback/handler function props should always be optional and tested to see if they exist before execution. Within private child components use .isRequired if the callback is needed internally for the component to function.

Advocate for accessibility

  • One of the key aspects of accessibility with React components is managing a DOM node's focus and blur. This should be implemented with callback references to DOM nodes and should not use ReactDOM.findDOMNode(). Use the the current DOM node ref prop to create a function that passes the DOM node to a callback that is provided by the parent which will control the focus once the DOM node has been rendered.

  • If a component has a focusable element, such as a button or an input, write a callback function that will pass the ref back to it's parent. buttonRef or inputRef are possible prop names.

  • Non-accessible component contributions are permitted but discouraged. These are labelled "prototypes" and do not follow an approved accessible user-experience pattern. Please create an additional issue to follow up with the contribution.

Unless you have an accessiblity guru in your department (knowledge of implementing accessible code and using assistive technology), you are going to have to figure out some things for yourself. A wise manager once said "real work is when you can't Google the answer." Here are some resources that have different answers to your questions.

  • ARIA-1.1 Authoring Practices guide - Although no one actually implemented ARIA 1.0 guidelines fully, this is the bleeding edge of the W3C's re-write of the Authoring Practices, which are based on ARIA 1.1. Many now come with the W3C's own examples pages.
  • ARIA 1.1 - Recommendation Candidate for the new ARIA Spec.
  • ARIA in HTML - Super useful reference to answer the question "Should I put ARIA on this?". Often a native HTML element will have an implicit role, so it's not required, nor recommended to be added.
  • HTML 5.1 - This is at the Recommendation Candidate stage, so it is very unlikely to change. Please notice the places where it informs of ARIA role for each element, the implicit roles, may not be 100% accurate. The document authors state that the ARIA in HTML spec above is the definitive source of truth for that bit and they'll fix up 5.1 when they find stuff that's not correct.
  • eBay MIND patterns - Nice to digest content. Most up to date functional base components our team has found so far with examples. This does not mean they are correct, though.

Be kind to future contributors and write tests

  • All external APIs should be tested, so that breaking changes can be detected. If a breaking change doesn't cause at least one test to fail, then add a test.
    • All props should be tested. It is OK to test multiple props in the same test for optmization as long as they are isolated and do not affect each other (for instance id, classname, and style).
    • All event callbacks should be tested along with any data object keys outside of the synthetic event to confirm the data. The data object, if present, is typically the second parameter of an event callback.
    • All mouse and keyboard interactions should be tested.
  • Components should have 90%+ test coverage. Coverage can be determined by reviewing the coverage summary at the end of npm test. High test coverage does not imply correct logic, but low coverage implies low test quality/quantity.
  • Test should run correctly in headless browsers (npm test) and within a "real" browser (npm start -> http://localhost:8001/)
  • For more specifics about testing please review the testing module walkthough.

Controlled and Uncontrolled Components

  • All new components should be controlled at first and then uncontrolled support added later if needed.
  • All Design System React components should be able to be "controlled"--that is expose a callback and expect their parent to control them with props.
  • Prefix callbacks that occur before an event with onRequest. Prefix callbacks that occur as a result of an event with on. The close button in a Popover will call onRequestClose while the Popover will call onClose after the Popover has been closed. This is because closing isn't guarenteed with onRequestClose, since the parent component will decide.
  • Please note that if controlled by its parent, a component will appear broken if just copied and pasted into an application without a parent to control its props.
  • Controlled components can be stateless components, but entirely stateless components do complicate DOM selectors for the consuming applications.

A controlled <input> has a value prop. Rendering a controlled <input> will reflect the value of the value prop.

  render() {
    return <input type="text" value="Hello!" />;
  }

User input will have no effect on the rendered element because React has declared the value to be Hello!. To update the value in response to user input, you could use the onChange event:

class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'Hello!'};
  }

  handleChange = (event) => {
    this.setState({value: event.target.value});
  }

  render() {
    return (
      <input
        type="text"
        value={this.state.value}
        onChange={this.handleChange}
      />
    );
  }
}

In this example, we are accepting the value provided by the user and updating the value prop of the <input> component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. For example:

  handleChange = (event) => {
    this.setState({value: event.target.value.substr(0, 140)});
  }

This would accept user input and truncate the value to the first 140 characters.

A Controlled component does not maintain its own internal state; the component renders purely based on props.

from Controlled Components in the React documentation.

  • If a component needs the ability to also manage its own state (that is to be an "uncontrolled" component) in particular situations the parent should still be able to take over and make it controlled simply by passing in a value for the prop. For instance, an onModalClose callback could change isModalOpen to false when it is ready to close the modal.
  • For more detail and examples of this pattern, visit DIMOC: Do It Myself or Callback.

Component Organization

  • extends React.Component
    • display name
    • prop types
    • defaults props
    • initial state within constructor
    • life cycle methods
    • sub-render methods (keep to a minimum, only use to stay "DRY")
    • component render
import React from 'react';
import PropTypes from 'prop-types';
import shortid from 'shortid';
import checkProps from './check-props';
import { EXTERNAL_CONSTANT } from '../../utilities/constants';

const propTypes = {
  /**
   * The description of this prop (will appear in the documentation site).
   */
  title: PropTypes.string.isRequired
};

// These values will also be visible in the documentation site.
const defaultProps = {};

/**
 * The description of this component (will appear in the documentation site).
 */
class DemoComponent extends React.Component {
  static displayName = EXTERNAL_CONSTANT_NAME;
  static propTypes = propTypes;
  static defaultProps = defaultProps;

  constructor (props) {
    super(props);

    // useful for unique DOM IDs
    this.generatedId = this.props.id || shortid.generate();

    // initial state
    this.state = {};
  }

  componentWillMount () {
    // Not required. This function issues console warnings to developers about props and is helpful in upgrading. All breaking changes to props must have a warning for developers when they upgrade.
    checkProps(EXTERNAL_CONSTANT, this.props);
  }

  // Class property bound to instance. Class methods that are not React lifecycle methods should use "fat-arrow" syntax if `this` binding is needed.
  toggleOpen = (event, { eventDataKey }) => {
    // you can use `this` here
  };

  // Minimize use of multiple renders. More HTML-like JSX is preferred with ternary statements
  renderSubComponent = () => null;

  // Render should be last
  render () {
    return null;
  }
}

export default DemoComponent;

Formatting Props

Wrap props on newlines for exactly 2 or more. Always list alphabetically.

// bad
<Person
 firstName="Michael" />

// good
<Person firstName="Michael" />
// bad
<Person firstName="Michael" lastName="Chan" occupation="Designer" favoriteFood="Drunken Noodles" />

// good
<Person
 favoriteFood="Drunken Noodles"
 firstName="Michael"
 lastName="Chan"
 occupation="Designer"
/>

Child component decorator pattern

Limit aliasing of props for child components that already exist. This pattern is similar to higher-order components. It creates a separation of concern and a more declarative approach that relies on child components with their own props instead of additional props on the parent component.

For instance, allowing MenuDropdown to have a Trigger child that can be a Button can prevent the creation of new props such as buttonClassName on MenuDropdown, since Button already has a className prop.

  • This reduces prop duplication for props that will just be passed down to the child component.
  • It allows MenuDropdown to decorate Button with the correct onClick among other props.
  • It allows the end-developer to use all existing Button props that they may already be familiar with.

The following is a simple example of the cloning process within the parent.

class CleverParent extends React.Component {
  render() {
    const children = React.Children.map(this.props.children, (child) => {
      return React.cloneElement(child, {
        onClick: () => alert(JSON.stringify(child.props, 0, 2))
      })
    })
    return <div>{children}</div>
  }
}

class SimpleChild extends React.Component {
  render() {
    return (
      <div onClick={this.props.onClick}>
        {this.props.children}
      </div>
    )
  }
}

class App extends React.Component {
  render() {
    return (
      <CleverParent>
        <SimpleChild>1</SimpleChild>
        <SimpleChild>2</SimpleChild>
        <SimpleChild>3</SimpleChild>
        <SimpleChild>4</SimpleChild>
        <SimpleChild>5</SimpleChild>
      </CleverParent>
    )
  }
}

Example taken from React Composability Patterns

Prefer Ternary to Sub-render

Keep login inside the render.

// bad
renderSmilingStatement () {
  return <div>{this.props.name}{(this.state.isSmiling) ? <span> is smiling</span> : ""}</div>;
},

render () {
  return <div>{this.props.name}{this.renderSmilingStatement()}</div>;
}
// good
render () {
  return (
    <div>
      {this.props.name}
      {this.state.isSmiling
        ? <span> is smiling</span>
        : null
      }
    </div>
  );
}

Preferred ways to render

Once your data is in a correct structure, your rendering should just respond to changes in your data. Here is list of ways to render:

  1. Inline ternary operator
    • Preferred more than a simple if-else statement
    • It is more concise than if-else and can be used within JSX since it’s an expression
  2. Logical && operator
    • Alternative to ternary. Use when one side of the ternary operation would return null
    • Be careful that you don’t run into bugs when using multiple conditions (truthy/falsey values, especially array length of zero)
  3. Inline Enum objects
    • Great to map different states
    • Great to map nested conditions ({prop1: { }}[prop1][prop2])
  4. Higher Order Components or Sub-components
    • Create another stateless component and use it to shield away complex conditional rendering
    • Components can focus on their main purpose
    • This is an abstraction and can only return one node (in React 15)
  5. Switch case
    • Verbose (break!)
    • Can only be JSX-inlined with self invoking function
    • Avoid it, enums are preferred
  6. If-else
    • Is the most basic conditional rendering
    • Beginner friendly
    • Cannot be inlined in JSX (needs variables)
  7. Multi-level/nested conditional renderings
    • Avoid them for the sake of readability
    • Split up components into stateless components with their own simple conditional rendering
    • Use HOCs instead
  8. External templating components
    • Avoid them and be comfortable with JSX and JavaScript

Naming DOM ref callbacks

Do not name a DOM callback prop of a library component ref. ref is a reserved prop name. This will return the component React object, not the DOM node. It is best practice to create an object called refs with keys that are semantic names of DOM nodes: refs: { triggerButton: ()=>{}, triggerInput: ()=>{} }. If you use a refs object, you may need shallow merge the object with default props. For more information, please review Exposing DOM Refs to Parent Components.

// bad
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.ref} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
    return (
      <CustomTextInput
        ref={el => this.inputElement = el}
      />
    );
  }
}
// good
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.refs.input} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
    return (
      <CustomTextInput
        refs={{
          input: (el) => { this.inputElement = el; }
        }}
      />
    );
  }
}

Naming Handler Methods

Name the handler methods after their triggering event.

// bad
punchABadger () { /*...*/ },

render () {
  return <div onClick={this.punchABadger} />;
}
// good
handleClick () { /*...*/ },

render () {
  return <div onClick={this.handleClick} />;
}

Handler names should:

  • begin with handle
  • end with the name of the event they handle (eg, Click, Change)
  • be present-tense

If you need to disambiguate handlers, add additional information between handle and the event name. For example, you can distinguish between onChange handlers: handleNameChange and handleAgeChange. When you do this, ask yourself if you should be creating a new component.

Classnames

Use classNames to manage conditional classes.

// bad
get classes () {
  let classes = ['MyComponent'];

  if (this.state.active) {
    classes.push('MyComponent--active');
  }

  return classes.join(' ');
}

render () {
  return <div className={this.classes} />;
}
// better
render () {
  return (
    <div className={classnames('MyComponent',
      `MyComponent--${this.props.active}`,
      `MyComponent--${this.props.variant}`,
    )} />
  );
}

The best solution allows you to search the source code for the entire class name in order to update it. Dynamic classnames are more difficult to locate.

// best
render () {
  return (
    <div className={classnames('MyComponent', {
      'MyComponent--active': this.props.active,
      'MyComponent--link': this.props.variant === 'link',
   })} />
}

Read: Class Name Manipulation

from the Planning Center

Finalize new component/features

  1. Write tests for your new component/feature.
  2. Run npm test.
  3. After your PR is merged, make sure it appears here: https://design-system-react-components.herokuapp.com. If it doesn't, reach out to one of the following people:
  1. Get your component/feature approved by the UX Accessibility Team (refer to the link above).

Test the documentation site

  1. Pull down the documentation site and place in the same parent folder as this library: git clone git@github.com:salesforce-ux/design-system-react-site.git and run npm install. `.
  2. Run npm run local-update from within design-system-react-site to build, copy, and serve a local version of this library into the site. You should be able to now view the updated site at http://localhost:8080/ and resolve any issues with updated documentation.

Release with build server (preferred)

  1. Add release notes for your version to RELEASENOTES.md under Latest Release heading.
  2. Commit and push a blank text file name patch.md or minor.md to the master branch. In the future, this will contain the release notes. The build server will detect this, delete the file, create a release for you, push back to the library repository.
  3. Copy and paste your release notes into the Github Draft Release UI and publish.

Manual release

  1. Choose one: npm run release-patch or npm run release-minor. This script pulls from upstream, bumps the version, commits changes, and publishes tags to your upstream repository (that is this repo).
  2. Copy and paste your release notes into the Github Draft Release UI and publish.

Update documentation site

  1. Update the version of Design System React in the documentation site's package.json and push to master. This is will build a Heroku application. Log into Heroku and promote the staged pull request to production. You will need promotion rights to the Heroku application.

Create a build server

  1. Create a Heroku app.
  2. Connect your App GitHub to the Github branch you wish to deploy and turn on automatic deploys for master branch.
  3. Create environment variable, IS_BUILD_SERVER and set to true.
  4. Create environment variable, NPM_CONFIG_PRODUCTION and set to false.
  5. Create environment variable, ORIGIN and set to [git@github.com:[your username]/design-system-react.git]
  6. Create environment variable, GIT_SSH_KEY and set to a user's private key (base64 encoded) that has access to your repository. openssl base64 < [PRIVATE_KEY_FILENAME] | tr -d '\n' | pbcopy

If you are timid about releasing or need your pull request in review "pre-released," you can publish to origin (your fork) with npm run publish-to-git and then test and review the tag on your fork. This is just the publish step though, any other tasks you will need to do manually to test publishing.