- 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.
- Fork this repository, then clone that forked repository locally.
- Create a topic branch for the issue that you are trying to add locally.
- Edit the code locally and push to your username's forked repository. Be sure to add a Storybook story for new features.
- 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.
This is an internal open-source project. You may be asked to review code submitted by others. To do this:
git clone
this repositorynpm 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
thengit 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 athttp://localhost:9001/
. Openhttp://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.
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.
-
# 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 thedesign-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
- A component has children without a specified
-
# 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
andlabels
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 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 justshortid
generated). Mostid
attributes are used for accessbility or for Reactkey
. - # 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. ATreeNode
should not. - A
DataTable
should have state, aTableColumn
should not. - Frequently used items such as badges, pills, buttons or icons should probably not have state.
- # All
-
# 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 aref
for setting focus, butrefs
make testing easier. If you find yourself usingquerySelectorAll()
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 aref
bound to your own JSX DOM node to test. For an example, review therenderDialog
method ofPopover
and itsbody
ref. Once surfaced, a DOMref
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 wrappingdiv
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 useisRequired
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.
-
# 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 aneslint-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 fromReact.Component
and never anotherclass
. This prevents class hierarchies and tight coupling being created beyond the basicReact.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 likethis.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 asstring
,object
, andarrays
. 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 intoclassName
should be present on the.slds-[COMPONENT]
node and not on a container node--nor on a child of.slds-[COMPONENT]
. All otherclassName
props should be prefixed--such astriggerClassName
orcontainerClassName
. -
# Use boolean prefixes. If a prop is a boolean, please prefix with
is
orcan
or suffix it with-able
. Never default a prop totrue
.
-
# 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
anddelete
when mutating arrays. If you ever have to ask yourself, why isn't my component rendering, this is likely the reason. UseObject.assign()
on objects andArray.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 usingconst { active, className, ...rest } = props;
do not go back to usingthis.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 isfalse
or undefined in order to execute code, use a "double logical NOT operator". IfisOpen
gives you a "falsey" value, then!!isOpen
will make it return the boolean valuefalse
. Otherwise it will return true. If you need to test if the value is notundefined
, 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.
-
One of the key aspects of accessibility with React components is managing a DOM node's
focus
andblur
. This should be implemented with callback references to DOM nodes and should not useReactDOM.findDOMNode()
. Use the the current DOM noderef
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
orinputRef
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.
- 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 instanceid
,classname
, andstyle
). - 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.
- All
- 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.
- 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 withon
. The close button in a Popover will callonRequestClose
while the Popover will callonClose
after the Popover has been closed. This is because closing isn't guarenteed withonRequestClose
, 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 changeisModalOpen
tofalse
when it is ready to close the modal. - For more detail and examples of this pattern, visit DIMOC: Do It Myself or Callback.
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;
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"
/>
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 forprops
that will just be passed down to the child component. - It allows
MenuDropdown
to decorateButton
with the correctonClick
among otherprops
. - 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
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>
);
}
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:
- 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
- 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)
- Inline Enum objects
- Great to map different states
- Great to map nested conditions ({prop1: { }}[prop1][prop2])
- 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)
- Switch case
- Verbose (break!)
- Can only be JSX-inlined with self invoking function
- Avoid it, enums are preferred
- If-else
- Is the most basic conditional rendering
- Beginner friendly
- Cannot be inlined in JSX (needs variables)
- 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
- External templating components
- Avoid them and be comfortable with JSX and JavaScript
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; }
}}
/>
);
}
}
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.
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
- Write tests for your new component/feature.
- Run
npm test
. - 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:
- Get your component/feature approved by the UX Accessibility Team (refer to the link above).
- 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 runnpm install
. `. - Run
npm run local-update
from withindesign-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 athttp://localhost:8080/
and resolve any issues with updated documentation.
- Add release notes for your version to RELEASENOTES.md under Latest Release heading.
- Commit and push a blank text file name
patch.md
orminor.md
to themaster
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. - Copy and paste your release notes into the Github Draft Release UI and publish.
- Choose one:
npm run release-patch
ornpm run release-minor
. This script pulls from upstream, bumps the version, commits changes, and publishes tags to yourupstream
repository (that is this repo). - Copy and paste your release notes into the Github Draft Release UI and publish.
- 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 Heroku app.
- Connect your App GitHub to the Github branch you wish to deploy and turn on automatic deploys for
master
branch. - Create environment variable,
IS_BUILD_SERVER
and set totrue
. - Create environment variable,
NPM_CONFIG_PRODUCTION
and set tofalse
. - Create environment variable,
ORIGIN
and set to[git@github.com:[your username]/design-system-react.git]
- 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.