In the /react-components
directory you can run:
Installs the project's dependencies.
Launches the Storybook application for fast development and debugging. Generally, for any component in ui-lib there should be a story. Stories are also used to run the tests.
Launches the test runner in the interactive watch mode. All tests should pass before creating a merge request. See the section about running tests for more information.
There are 2 locations where DE components live.
- Here in the ui repo /react-components/src - these components are typically specific to the DE.
- In the ui-lib repo - these components and helper functions are typically general enough to be used in other CyVerse products.
All of the below standards will apply to both repositories.
Use material-ui components before attempting to design your own. Material-ui, or MUI, has most of the components we'll need, like buttons, dialogs, and grid layouts. If a component is not available directly from material-ui, you can typically find a repo on github that has created a component that follows the material-ui design spec for you.
Use material icons before asking our graphic designer to create something custom.
It is strongly recommended that all development for components is done utilizing Storybook. It allows you to view your collection of components in a browser and "develop UI components in isolation without worrying about app specific dependencies and requirements". Every time you save your component's story file, Storybook will automatically refresh the browser with your changes so you can visually inspect and iterate on it.
Add your component's story within the /stories
folder here. Then, import your story in the index file here. Run the storybook command listed above.
Create a test for your components located in the /src/__tests__
folder here. Note that all the tests rely on rendering the story for each component.
All text displayed to the user should be internationalized. We currently use react-intl for internationalization of our app. There are helper functions in the ui-lib repo that should be used.
Generally, you'll need to:
- Create a
messages
file similar to the following with all the text your component(s) will need. Generally, the first 3 lines don't change -locales
andmessages
must be present. Beyond that, you have your text in key-value pairs.
export default {
locales: "en-US",
messages: {
header: "Welcome",
namedHeader: "Welcome back {name}",
}
}
- Export your component while wrapping it with the
withI18N
higher-order component from the helper function file in theui-lib
repo and pass in themessages
file you created. This basically links them together soreact-intl
knows where to look up text.
import myMessagesFile from "./messages";
import { getMessage, withI18N } from "@cyverse-de/ui-lib";
function MyComponent(props) {
return (
<span>Welcome</span>
<span>Welcome back {props.name}</span>
)
}
export default withI18N(MyComponent, myMessagesFile);
- Update your component to fetch the internationalized text with the corresponding key you created. The getMessage(key) helper function covers roughly 80% of the use cases
import myMessagesFile from "./messages";
import { getMessage, withI18N } from "@cyverse-de/ui-lib";
function MyComponent(props) {
return (
<span>{getMessage("header")}</span>
<span>{getMessage("namedHeader", { values: {name: props.name} })}</span>
)
}
export default withI18N(MyComponent, myMessagesFile);
For robust QA testing, add static IDs to all of your components.
All ids should be in a separate ids
file. Example file here.
In order to ensure uniqueness of those IDs, use a pattern of parentID.childId
. For example, a dialog may have an ID of toolsDialog
. Every component within that dialog will then have an ID in the format toolsDialog.myID
. If those components then have sub-components, they will take the format toolsDialog.myID.theirID
, and so on.
To help with this, there's a build
helper function in the ui-lib
repo here. build(id1, id2, id3)
will yield an id of id1.id2.id3
.
If your component(s) require a lot of CSS, create a separate styles
file to keep things minimal. Example file here.
For utilizing styles, we're transitioning to using makeStyles
from @material-ui/core
as a hook (Historically, we have many components using withStyles
from @material-ui/core/styles
as a higher-order component). Here's a small example of using makeStyles
:
import { makeStyles } from "@material-ui/core";
import myStylesFile from "./styles";
const useStyles = makeStyles(myStylesFile);
function myComponent(props) {
const classes = useStyles();
return (
<div className={classes.myDivCSS}/>
)
}
Try to stick with using colors from the CyVerse palette (in order to access that link, you must be signed in and be a CyVerse staff member).
We have defined the palette for code use in the ui-lib
repo here. There's an example of using the palette here.
Be aware the DE has a customized material-ui theme to update material-ui components to use the CyVerse palette.
The default values can be found here.