Design Language System (DLS)
The Design Language System for ACT & Encoura front-end projects. View the UI components
here.
Project Setup
Installation
In order to use the DLS, you must install it along with
Material UI version 6.x
and
React version 17.x
or 18.x
.
npm install --save @actinc/dls@latest @mui/material @mui/system @mui/x-data-grid react react-dom
Choosing a Theme
This DLS is built on top of the
theme engine from
Material UI, and ships with several themes out of the box:
"ACT"
: for ACT's "traditional" look and feel"ACT_ET"
: for ACT's "Emerging Technology" look and feel"ENCOURA"
: for the Encoura's "MyEncoura" look and feel"ENCOURA_CLASSIC"
: for Encoura's "Classic" look and feel"ENCOURAGE"
: for the Encoura's "Encourage for Students" look and feel"ENCOURAGE_E4E"
: for the Encoura's "Encourage for Educators" look and feel
To apply one of these themes to your components, simply wrap your application
in the ThemeProvider
component and specify a theme!
import { ThemeProvider } from '@actinc/dls/components/ThemeProvider';
...
const MyApp = () => (
<ThemeProvider theme="ACT_ET">
<App />
</ThemeProvider>
);
Extending Themes
You can exend the core DLS themes using using our variation on the
createTheme
generator from Material UI:
import deepMerge from 'deepmerge';
import { createTheme } from '@actinc/dls/styles/createTheme';
import { THEME_ACT } from '@actinc/dls/styles/themeAct';
import { ThemeProvider } from '@actinc/dls/components/ThemeProvider';
const myExtendedTheme = createTheme(
deepMerge(THEME_ACT, {
}),
);
const MyApp = () => (
<ThemeProvider theme={myExtendedTheme}>
<App />
</ThemeProvider>
);
Custom Themes
Alternatively, you can build your own theme from scratch using our variation on the
createTheme
generator from Material UI. Our version takes the same parameters, but will
return a strongly typed version of the theme with any customizations you may
have added.
import { ThemeProvider } from '@actinc/dls/components/ThemeProvider';
import { createTheme } from '@actinc/dls/styles/createTheme';
const myCustomTheme = createTheme({
});
const MyApp = () => (
<ThemeProvider theme={myCustomTheme}>
<App />
</ThemeProvider>
);
Custom Themes And Styled Components
Within your styled components, if you need to access custom a theme variable
that is not present in the default MUI Theme
type, we provide a helper
function to generate a styled
function that is strongly typed to your theme:
import { createThemeStyled } from '@actinc/dls/helpers/styled';
import { THEME_ACT } from '@actinc/dls/styles/themeAct';
import TableCell from '@mui/material/TableCell';
const styled = createThemeStyled(THEME_ACT);
const StyledTypography = styled(TableCell)(({ theme }) => ({
height: theme.customDims.heights.tableHeader,
}));
Load Fonts
Montserrat
The ACT
and ACT_ET
themes assume that the
Montserrat font is available in
the browser. Therefore, it is recommended that you include the following font
reference in the head
of your React app:
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700&display=swap"
rel="stylesheet"
/>
Museo Sans
The ENCOURA
and ENCOURA_CLASSIC
themes assume that the
Museo Sans font
is available in the browser. Include this embed code in the head
of your React app after obtaining the licensed font URL from Marketing:
<style>
@import url('licensed-font-url');
</style>
Work Sans, Roboto, Roboto Mono
The ENCOURAGE
and ENCOURAGE_E4E
themes assume that the
Work Sans,
Roboto, and the
Roboto Mono fonts are available
in the browser. Therefore, it is recommended that you include the following font
reference in the head
of your React app:
<link
href="https://fonts.googleapis.com/css2?display=swap&family=Work+Sans:wght@200..800"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?display=swap&family=Roboto:wght@300;400;500;700"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?display=swap&family=Roboto+Mono:wght@200..700"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,600,700"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?display=swap&family=Work+Sans:wght@200..800"
rel="stylesheet"
/>
CSS Baseline
It is recommended to inject the CssBaseline
component from Material UI near
the root of your component tree in order to reset and normalize browser styles
for your project:
import { CssBaseline } from '@mui/material';
...
const MyApp = () => (
...
<CssBaseline />
...
);
Server-Side Rendering
If your project's React framework supports SSR, you can configure the DLS
components for server-side rendering. See the official Next.js example
here.
Icons
Option 1: Find and import from the DLS
The DLS re-exports all icons that are provided by the
mdi-material-ui
package. This
is an expansive list of icons that are managed by the material community. You
can search for a specific icon to use on
materialdesignicons.com. Once you've found
the perfect icon, you can use it in your project like so:
import PollBox from '@actinc/dls/icons/PollBox';
...
const MyComponent = () => (
...
<PollBox />
...
);
Option 2: Find and import from @mui/icons-material
If the DLS doesn't provide the icon you're looking for, as a second line of
defense, you can search for icons in the
@mui/icons-material
library. While most of these icons can be found directly in the DLS via
mdi-material-ui
, there is some unique selection within this library that could
be useful to you. You can search for a specific icon to use on
mui.com. Once you've found
the perfect icon, you can use it in your project like so:
import PollIcon from '@mui/icons-material/Poll';
...
const MyComponent = () => (
...
<PollIcon />
...
);
Option 3: Create a custom icon
When all else fails, you can create a custom icon using the SvgIcon
component
from Material UI. Here's an example:
import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
import React from 'react';
export const CustomIcon: React.FC<SvgIconProps> = (props: SvgIconProps): React.ReactElement<SvgIconProps> => (
<SvgIcon style={{ fill: 'none' }} viewBox="0 0 24 24" {...props}>
<path d="<insert-svg-data-here>" />
</SvgIcon>
);
export default CustomIcon;
Import Stuff
That's it! You're ready to use the DLS. Simply import the components,
constants, context, helpers, hooks, icons, styles, and types that you need:
import { Alert } from '@actinc/dls/components/Alert';
import { SORT_DIRECTION_TYPES } from '@actinc/dls/constants';
import { AlertContext } from '@actinc/dls/context';
import { search } from '@actinc/dls/helpers';
import { useLocalStorage } from '@actinc/dls/hooks';
import ChevronDown from '@actinc/dls/icons/ChevronDown';
import { THEME_ACT } from '@actinc/dls/styles/themeAct';
import { SortObject } from '@actinc/dls/types';
Transient Props and Styled Components
The DLS provides a customized styled helper which omits transient props
(those starting with $) from the rendered HTML, while still being able to use
those parameters in styled components. Use as a drop in replacement of the
styled
function that exists in @mui/material/styles
:
import { styled } from '@actinc/dls/helpers/styled';
import Button, { ButtonProps } from '@mui/material/Button';
import * as React from 'react';
const StyledButton = styled(Button)<ButtonProps & { $ultraWide: boolean }>(
({ $ultraWide, theme }) => ({
paddingLeft: $ultraWide ? theme.spacing(8) : theme.spacing(4),
paddingRight: $ultraWide ? theme.spacing(8) : theme.spacing(4),
}),
);
const MyComponent: React.FC = () => {
return <StyledButton $ultraWide />;
};
ES Modules & Tree Shaking
Version <= 6 of the DLS were built and exported as
CommonJS modules.
While this allowed the simplest integration of the DLS into any
project, it also resulted in project bundles being
larger than desired due to
the inability of bundlers to
tree-shake
the DLS.
In version >= 7 of the DLS, we are now building and exporting the library as
ECMAScript modules.
This allows your project's bundler to much more easily read and
tree-shake
the DLS right out of the box. (No more need for
babel-plugin-transform-imports
!)
Furthermore, the DLS's package.json
is also setting:
"sideEffects": false,
to instruct builders to enable even deeper tree-shaking. This should make
bundle sizes significantly smaller with less effort. However, the tradeoff
is that in certain scenarios, like
Lazy Loading,
if you are expecting a dependency to be there that is now removed from
tree-shaking, things will break and you may need to import that dependency
directly in a parent bundle.
SyntaxError: Unexpected token 'export'
One downside of exporting the DLS as ECMAScript modules is that the import
and
export
keywords are preserved, which may cause your packager/runner to throw:
SyntaxError: Unexpected token 'export'
If you see this error, you'll need to instruct your packager/runner to transpile
the DLS on-the-fly.
Next.js
You can do this in a Next.js app by adding the DLS to the
transpilePackages
option in your next.config.js
file.
transpilePackages: ['@actinc/dls'],
Jest
You can do this in the Jest test runner by omitting the
DLS from the
transformIgnorePatterns
option in your jest.config.js
file.
transformIgnorePatterns: ['/node_modules/(?!(@actinc/dls)/)'],
Local Development
Check out the developer guide to learn how to build
effectively for the DLS.
To run the DLS locally:
- Install node modules:
npm install
- Start the Storybook component visualizer:
npm start
How to Iterate Locally
Option 1: Creating a Local Build
When you're ready to pilot your changes to this library in your local project:
-
Run the npm run pack
command. When it finishes running, it will generate a
.tgz
file in the /dist
folder with the following name format
actinc-dls-<version-number>.tgz
;
-
Access the package.json
file of your local project in which the
@actinc/dls
package will be tested, and make the following edit:
"dependencies": {
"@actinc/dls": "9.2.1",
"@actinc/dls": "file:../path/to/@actinc/dls/dist/actinc-dls-<version-number>.tgz",
...
}
-
Run npm update @actinc/dls
to refresh your project's node_modules
folder.
-
You can now run your project with the local changes made to this library!
-
If you want to make any further edits to this library, simply run
npm run pack
to package up the changes, and then npm update @actinc/dls
in your local project to pull them in.
-
When you're done piloting the changes, simply revert your project's
package.json
file to pull this library from NPM, and run
npm update @actinc/dls
to refresh your project's node_modules
folder.
Option 2: Real-time Previews
For rapid iteration, you can run a live copy of this library in your
downstream project:
-
In this library, run the watch script: npm run watch
-
In your project, install a local build of this library: npm install <path-to-this-repo>/dist
Under the hood, this creates a symlink between the local build and your project.
When changes are detected under the src
folder, a new build will be output
into the dist
folder and picked up by your project.
Once you are happy with the changes, you'll want to destroy this symlink
and replace the local build with a formal/hosted version of this library.
You can do that by running the following commands in your project:
-
npm uninstall @actinc/dls
-
npm install @actinc/dls@<pick-your-version> --save --save-exact
npm Scripts
There are lots of npm scripts at your disposal during local development.
Here are some of the more important ones:
Script | Description |
---|
npm run build | Transpiles DLS from TypeScript (./src ) into ES5 (./dist ). |
npm run build-storybook | Creates a static website for deployment (./storybook-static ). |
npm start | Starts the Storybook component visualizer. |
npm test | Runs all tests. |
npm run release | Publishes a new release of the DLS. |
npm run release:storybook | Publishes a new release of Storybook (make sure to pull latest main ). |
npm run watch | Watch the src folder for changes and transpile on-the-fly to dist . |
Committing Code
semantic-release scans commits to manage package.json versions and CHANGELOG.MD
It is important that we accurately capture what type of development we are doing.
- For changes to storybook (i.e. no change to components), use the
docs
tag:
git commit -m "docs: Added stories for Alert"
- For patches to existing components, use
fix
:
git commit -m "fix: Fixed Snackbar not appear in center of screen"
- For new functionality, use
feat
:
git commit -m "feat: Added Carousel component"
Pinned Packages
Some npm packages are pinned to non-current versions for a specific reason: