rewards-ds
v1.0.0
Published
Rewards Design System
Downloads
56
Keywords
Readme
Woolworths Atomic Design System
Welcome to the Woolworths Atomic Design System, an easy way to consume common reusable web components for use with various modern application frameworks (angular, vue, react).
Our design system is a collection of Web Components (using Stencil js by the lovely Ionic team), so they work in any major framework or with no framework at all.
QUICK START
- The repository contains stencil, stoybook and gatsby
- gatsby project has it's own
package.json
and build process -docs
sub-directory
GATSBY
- to run gasby you have to build static assets from stencil and storybook first
- after
npm install
runnpm run build:docs
thennpm run docs:start
to start working with gatsby - in
src/pages
you’ll see the mdx files, basically add stencil components as regular html, except using the object spread method{...{ attributes here }}
for attaching the attributes/props - to use react components in the mdx you’ll need to import them at the top
- each page should be wrapped in
<Layout></Layout>
- navigation can be updated from gatsby-config.js inside of the siteMetaData -> navigation object. First level is a group of nav items, then nav items are added into the items array. Second level nesting is achieved by setting the parent value to the parent path. A parent path of / will indicate top level within the group. There is a group with top and example next level item to use as reference. Active state is not currently working.
When you’re ready to deploy, just commit and push changes, docs will be auto built and deployed to s3 under the branch name used. Root domain should be http://ww-rewards-ds.s3-website-ap-southeast-2.amazonaws.com/
STORYBOOK
Integration between storybook and stencil inspired by: https://andreaswissel.com/integrating-stencil-with-storybook
Getting Started
You can learn about and contribute to the Atomic Design System in a number of ways:
Browse our online documentation
Take a look at our Design System's online documentation, found at rewards-ds.netlify.com.
Build locally to push new components or to prototype
If you are looking to either extend the Reward Design System, by adding new elements, components, or views, OR are looking to create interactive coded prototypes using the Atomic Design System, simply follow these steps:
git clone https://github.com/mothershipvc/woolworths-rewards-ds.git rewards-ds
cd rewards-ds
git remote rm origin
and run:
npm install
npm start
Installing Reward DS packages in your app
You can use various Atomic Design System properties and components as packages via NPM, within your Angular, Vue, React, or Static apps!
Install NPM Packages into your app's repo
npm install rewards-ds
If you only want to use a specific collection or component, install it like so:
npm install rewards-ds@core OR
npm install rewards-ds@forms OR specific components, like
npm install rewards-ds@balance-panel
Using Reward DS packages in your app
Once you've installed the relevant Atomic Design System node packages into your repo, simply do one of the following (depending on what kind of app you're building):
Add the component(s) to the dependencies
Add the component to the app dependencies in package.json:
// package.json
"dependencies": {
...
"@rewards-ds/core": "^0.3.2",
"@rewards-ds/forms": "^0.3.2",
"@rewards-ds/balance": "^0.3.2"
}
Integration with Frameworks
Angular
Using a Stencil built web component collection within an Angular CLI project is a two-step process. We need to:
- Include the
CUSTOM_ELEMENTS_SCHEMA
in the modules that use the components. - Call
defineCustomElements(window)
frommain.ts
(or some other appropriate place).
Including the Custom Elements Schema
Including the CUSTOM_ELEMENTS_SCHEMA
in the module allows the use of the web components in the HTML markup without the compiler producing errors this code should be added into the AppModule
and in every other modules that use your custom elements.
Here is an example of adding it to AppModule
:
import { BrowserModule } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
The CUSTOM_ELEMENTS_SCHEMA
needs to be included in any module that uses custom elements.
Calling defineCustomElements
A component collection built with Stencil includes a main function that is used to load the components in the collection. That function is called defineCustomElements()
and it needs to be called once during the bootstrapping of your application. One convenient place to do this is in main.ts
as such:
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
// Note: loader import location set using "esmLoaderPath" within the output target confg
import { defineCustomElements } from 'test-components/loader';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.log(err));
defineCustomElements(window);
Edge and IE11 polyfills
If you want your custom elements to be able to work on older browser, you should add the applyPolyfills()
that surrond the defineCustomElements()
function.
import { applyPolyfills, defineCustomElements } from 'rewards-ds/dist/loader';
...
applyPolyfills().then(() => {
defineCustomElements(window)
})
Accessing components using ViewChild and ViewChildren
Once included, components could be referenced in your code using ViewChild
and ViewChildren
as in the following example:
import { Component, ElementRef, ViewChild } from '@angular/core';
import 'rewards-ds';
@Component({
selector: 'app-home',
template: `
<test-components #test></test-components>
`,
styleUrls: ['./home.component.scss'],
})
export class HomeComponent {
@ViewChild('test') myTestComponent: ElementRef<HTMLTestComponentElement>;
async onAction() {
await this.myTestComponent.nativeElement.testComponentMethod();
}
}
React
With an application built using the create-react-app
script the easiest way to include the component library is to call defineCustomElements(window)
from the index.js
file.
Note that in this scenario applyPolyfills
is needed if you are targeting Edge or IE11.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
// test-component is the name of our made up Web Component that we have
// published to npm:
import { applyPolyfills, defineCustomElements } from 'test-components/loader';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
applyPolyfills().then(() => {
defineCustomElements(window);
});
Following the steps above will enable your web components to be used in React, however there are some additional complexities that must also be considered. https://custom-elements-everywhere.com/ describes them well.
Nuxt.js
Create a plugin, (e.g rewards.ts):
import Vue from 'vue';
import { defineCustomElements } from 'rewards-ds/dist/loader/index.cjs';
Vue.config.productionTip = false;
Vue.config.ignoredElements = [/rds-\w*/];
// Bind the custom elements to the window object
defineCustomElements(window);
// nuxt.config.ts
{
plugins: [
{ src: '~/plugins/rewards.ts', mode: 'client' },
],
}
Then, use it in any component!
<template>
<div>
<rds-barcode member-id="978020137962"></rds-barcode>
</div>
</template>
Without a framework
Integrating a component built with Stencil to a project without a JavaScript framework is straight forward. If you're using a simple HTML page, you can add your component via a script tag. For example, if we published a component to npm, we could load the component through unpkg like this:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/test-components/latest/dist/test-components.js"></script>
</head>
<body>
<test-component></test-component>
</body>
</html>
Alternatively, if you wanted to take advantage of ES Modules, you could include the components using an import statement. Note that in this scenario applyPolyfills
is needed if you are targeting Edge or IE11.
<!DOCTYPE html>
<html lang="en">
<head>
<script type="module">
import { applyPolyfills, defineCustomElements } from 'https://unpkg.com/test-components/latest/dist/esm/es2017/test-components.define.js';
applyPolyfills().then(() => {
defineCustomElements(window);
});
</script>
</head>
<body>
<test-component></test-component>
</body>
</html>
Passing object props from a non-JSX element
Setting the prop manually
import { Prop } from '@stencil/core';
export class TodoList {
@Prop() myObject: object;
@Prop() myArray: Array<string>;
}
<todo-list></todo-list>
<script>
const todoListElement = document.querySelector('todo-list');
todoListElement.myObject = {};
todoListElement.myArray = [];
</script>
Watching props changes
import { Prop, State, Watch } from '@stencil/core';
export class TodoList {
@Prop() myObject: string;
@Prop() myArray: string;
@State() myInnerObject: object;
@State() myInnerArray: Array<string>;
componentWillLoad() {
this.parseMyObjectProp(this.myObject);
this.parseMyArrayProp(this.myArray);
}
@Watch('myObject')
parseMyObjectProp(newValue: string) {
if (newValue) this.myInnerObject = JSON.parse(newValue);
}
@Watch('myArray')
parseMyArrayProp(newValue: string) {
if (newValue) this.myInnerArray = JSON.parse(newValue);
}
}
<todo-list my-object="{}" my-array="[]"></todo-list>