What you should know before getting started
Before you get started, there are some technical decisions you should know about - as in every project.
Table of Contents
- What you should know before getting started
About technology
The library exists of React components. The newer components are written as functional components, with React hooks. This was added to React version 16.8 and has become the new standard of React.
Files in the library were first written in JavaScript using PropTypes to define component types. For newer components we adopt using TypeScript, substituting the use of PropTypes.
Components are styled using nested CSS class selectors with SASS (SCSS) and BEM (Block Element Modifier).
Eufemia is a Mono Repository
The Eufemia repository is a monorepo consisting of the following workspaces:
- dnb-design-system-portal: Source code of the portal website - this website.
- dnb-eufemia: Source code of the npm package - where all the components are located.
dnb-eufemia
The only folders you should need to know about to add new features are:
src/components
: The folder containing all the components, structured in component folders.src/extensions
: The folder containing all extensions, also structured in component folders.
dnb-design-system-portal
The documentation in markdown (MDX) is located at src/docs
and the portal will automatically create pages and menu items based on that current structure.
All you need to do to add a new page is to create a new markdown (.mdx
) file within one of the folders. All documentation for components and elements are located at src/docs/uilib
, which corresponds to the URL eufemia.dnb.no/uilib.
Configuration files
ncurc.json
is used to ignore certain dependencies during a dependency update made by npm-check-updates..eslintrc
is a file with configurations to ESLint, which is a tool for identifying and reporting on patterns found in ECMAScript/Javascript code, with the goal of making code more consistent and avoiding bugs..prettierrc
is a file with configurations to Prettier, which is a codeformatter for multiple languages..stylelintrc
is a file with configurations to stylelint, which is a linter for styling (SCSS/CSS).babel.config.js
configures Babel, a JavaScript compiler.jest.config.js
configures Jest, the JavaScript Testing Framework for this project.jest.config.screenshots.js
configures jest-image-snapshot, which is related to the screenshot testing (visual assertion).tsconfig.json
is a file with configurations to TypeScript.
About Types
The two main purposes of delivering TypeScript types are:
- Inline property documentation
- Property validation and type safety
As of now, some components are written in TypeScript (.tsx
) and some in JavaScript and type definition files (.d.ts
).
Legacy type handling
For JavaScript based components, the documentation for properties (properties.mdx
) is kept as a Markdown Table, they get extracted, parsed, and inserted in the type definition files.
You can still sync/update the documentation of these files (d.ts
), by running: yarn @dnb/eufemia build:types:docs
or yarn build
.
NB: After you have synced/updated the files, you will see that some newlines were removed. Thats a negative side-effect we have no solution at the moment.
Sharing PropTypes between components (legacy)
You can share PropTypes between files. You can either export them explicitly (named export):
Named Export
// Make sure you include `*PropType` in the variable name. This also effects references inside a single file.export const componentPropTypes = {...otherPropTypes,children: PropTypes.node,property: PropTypes.string,}
and import them in other components by using the spread operator:
import { componentPropTypes } from './component'const Other = () => {}Other.propTypes = {...componentPropTypes,otherProperty: PropTypes.string,}
Default Export
or as a static reference on the component itself (default export):
const Component = () => {}Component.propTypes = {children: PropTypes.node,property: PropTypes.string,}export default Component
and import them in other components by using the spread operator:
import Component from './component'const Other = () => {}Other.propTypes = {...Component.propTypes,otherProperty: PropTypes.string,}
There are a couple of components doing so. You may have a look at:
Input
andInputMasked
Icon
andIconPrimary
- Also the
SpacingHelper
sharesspacingPropTypes
with almost every component
NB: In order to activate the type generation, a component needs to import the prop-types
dependency.
Shared Properties docs (legacy)
If you have one /properties.md
file, but e.g. two components share most or all of the properties. Like a component and a provider for that component (Accordion and AccordionProvider) – then you can define in the markdown table header name both of the components: You can then provide a second table with a more specific table for a second component.
#### Properties| Accordion and AccordionProvider Properties | Description || ------------------------------------------ | --------------------------------------------------------------------- || `id` | _(optional)_ docs. || [Space](/uilib/layout/space/properties) | _(optional)_ spacing properties like `top` or `bottom` are supported. || AccordionProvider Properties | Description || ---------------------------- | ------------------------------ || `expanded_id` | _(optional)_ expanded_id docs. |
About component structure
Eufemia has a couple of common parts, so every component behaves consistent:
- Locale support.
- Provider support for centralized property forwarding.
- Spacing support.
- Skeleton support.
- FormLabel / FormStatus support if its a form component.
- Automatic id generation and linking of HTML elements to enhance accessibility.
- Handling of
aria-describedby
withcombineDescribedBy
etc.
How to add support for every one of these are explained in Additional support - Getting started.
Component folder
Every component and extension should have a similar structure, as described here.
As an example, we show the folder structure of component Breadcrumb. You can also check out the source on Github.
/__tests__
: Contains the tests (Breadcrumb.test.tsx
) and screenshot tests (Breadcrumb.screenshot.test.tsx
) for the component. All screenshots will be placed within the folder__snapshots__
./style
: Contains the styling of the component. The file_breadcrumb.scss
defines all styling using BEM.dnb-breadcrumb.scss
contains the component style exports.Breadcrumb.tsx
andBreadcrumbItem.tsx
: The React components for the Breadcrumb are defined and exported from these files.index.js
: Contains component exports.style.js
: Contains component style exports.
Modifications
- Adding theming files under a folder
style/themes
will unlock the possibility of having different themes in the future. Check out the source for theming in Button.
Development environments
There are a couple of environments for different purposes.
- For developing and styling new components, you can run a Storybook development.
- For writing documentation and displaying the components, you can run the portal locally.
- After development, you can run your tests.
- If you want to see the local changes of the search results, you can run Algolia search queries locally.
Storybook development
Storybook is used for quick examples and component development. They do not need to be perfect.
Stories are placed inside a /stories
directory and contain .stories in the filename: /components/button/stories/Button.stories.tsx
Run Storybook locally by running
yarn dev
in the root folder. Then you can view the Storybook website by visiting localhost:8002.
Add new pages to the storybook by adding a new directory /stories
and a new file under ComponentName.stories.tsx
and following the similar structure of the other files.
Eufemia portal
The portal is currently handled by Gatsby, a framework for building pre-rendered SSR websites.
Run the Portal locally:
$ yarn start
This will start the Portal. You can view the portal website by visiting localhost:8000.
Content changes to both Markdown (MDX) files and styles (SCSS) and code changes will be reflected immediately.
For a faster startup-time, you can decide what pages you need by using the environment variable filter
e.g.:
$ filter=button yarn start# - or –$ filter=button,/input/ yarn start # with comma$ filter="button /input/" yarn start # with space (needs to be quoted)
And visit e.g. this page: http://localhost:8000/uilib/components/button/
Local build
In case you have to create a local static build of the portal website (for various reasons), you can do so by:
# In the `dnb-design-system-portal` directory, run:$ yarn build
The build will be exported to the /public
directory. You can now also run a local static server to view it at the given port localhost:8000:
# In the `dnb-design-system-portal` directory, run:$ yarn serve
What happens in the build steps
During the build, a lot of various things will happen. First, a prebuild before the build and afterward a postbuild.
During prebuild
$ yarn build
- Assets are getting generated
- All index and lib files are getting generated
- All the lib code gets compiled (ECMAScript 6 and ECMAScript 5.1)
- All SASS styles are validated and compiled (to support IE)
- All bundles get minified
- Icons are getting converted
To use the local build, you can either run the portal, or use yarn link
to link the package with a totally different project.
During postbuild
$ yarn workspace @dnb/eufemia postbuild:ci
- Assets are getting generated
- All the lib code gets compiled (ECMAScript 6 and ECMAScript 5.1)
- UMD/ESM/ES/CJS bundles are getting generated
- TypeScript definitions are getting generated