This page contains instructions and guidelines for anybody contributing code to the eBay Skin project.
- Contributing
- Table of Contents
- System Requirements
- Contribution Steps
- Development Modes
- Versioning
- Branching
- Package Dependencies
- Commit Message Format
- Pull Requests
- Naming Scheme
- Style Guide
- LESS API (deprecated)
- Custom Property API
- Dark Mode
- Storybook
- Visual Regression Testing
- Website
- Scripts
- Icon Creation
- Releases
Before writing any code, please submit a new issue to GitHub. Or, if you want to work on an existing issue, please request to do so on the relevant ticket.
We strongly advise you to only begin working on issues that are assigned specifically to you and that are part of the upcoming milestone, otherwise your work may end up being in vain.
Here is a rough overview of steps required when contributing code to skin:
- GitHub team members must create a new branch in the Skin repo. Non-team members should create their own fork.
- Please ensure you branch off from the correct milestone branch! See branching strategy section below.
- Skin adopts the BEM methodology (a popular naming convention for classes in HTML and CSS). Please familiarize yourself with our style guide in the section below.
- After making changes to
.less
files, ensure that no new CSS lint warnings or errors are introduced - Add or update the corresponding website documentation. More information in the documentation section below.
- Push commit(s) to the upstream branch. Ensure new dist files (i.e. the compiled CSS files) are included!
- Send pull request. See Pull Requests section below.
Skin can usually considered to be in one of two modes of development:
- Feature development mode (default)
- Refactoring/cleanup/breaking-changes mode
The vast majority of this guide is relevant to both modes.
Executing the following script will generate all files and references for a new module:
./scripts/develop-module -m "Your Module Name"
Example
./scripts/develop-module -m toast-dialog
Add applicable metadata about the component to the module_metadata
map in docs/index.html:
your-module-name: # the Skin module name
ds-component: # module's relationship with the eBay Design System
name: # eBay Design System component name
version: # version of the eBay Design System component implemented in Skin
status: # status, e.g. "beta", "deprecated", "in-progress"
submodules: # array of Skin modules used in this module
If the Skin component is used for multiple Design System components, include those as an array in the ds-component
field. For example:
lightbox-dialog:
ds-component:
- name: modal
version: 2.1
- name: bottom-sheet
version: 2.1
submodules:
- button
- icon-button
When updating a Skin module to match an updated Design System design, make sure to update its version in its ds-component
field.
Skin follows Semantic Versioning:
- MAJOR version when we make incompatible API changes,
- MINOR version when we add functionality in a backwards-compatible manner
- PATCH version when we make backwards-compatible bug fixes.
To help guide your contribution into the right bucket, we provide more detailed insight into each type of change in the sections below.
Here are some types of change that we consider as an incompatible API change:
- Removal of a CSS class
- Removal of a public variable or mixin
- Removal of a
browser.json
file - Removal of a folder from
dist
- Removal of an SVG icon
- Change to CDN path structure
- Change to HTML structure or attributes of module
- Change to CSS property that radically alters appearance and/or layout
Typically we will try and add a deprecation note for a period of time before introducing any breaking API change. The creation of aliases can often help ease the transition from one API to another.
Here are some of the changes we consider as new functionality:
- Addition of a new module
- Addition of a module subtype or variant
- Addition of a new variable or mixin
- Addition of an alias for a class or icon
- Update of a module to its latest playbook version
- Update of a colour value that remains within the same hue
- Update of a CSS property that does not affect the modules layout in page
Minor version updates are a signal that there is something new (no matter how small) that an app might be interested in using!
Bug fixes can perhaps best be summed up as: "fixing something that does not work as expected or documented".
NOTE: Updating a module to its latest visual specification is NOT a candidate for a bug fix. No matter how small or trivial the visual update may be, we always consider it as new functionality.
Do not attempt to commit feature work directly to the master
branch. Pushes to the master
branch are restricted to admins and should only be used for important corrections to the documentation or website.
All other branches are "milestone" branches or "issue" branches.
Work for every "issue" must go in its own branch. The branch name will reflect the issue number and issue type. For example, for an issue number 202, related to the pagination module, a branch named 202-pagination
would be created.
Issue branches must be created from the relevant milestone branch. For example, if issue 202 will go out in the v2.6.7 milestone, then the 202 issue branch must be created from the 2.6.7 milestone branch.
Every milestone branch must be created from the master
branch. For example, when beginning work on the 2.9.0 release, the 2.9.0
branch would be created from the master
branch.
When all milestone issues are complete, and merged into the milestone branch, a Skin admin will merge the milestone branch into the master
branch in preparation for the release.
A milestone branch will be deleted after it has been merged into master
. There is no need to keep these milestone branches lying around, as we can go back to any point in time using tags. See the hotfix section below for more details.
Every time we cut a new milestone branch, the package dependencies require updating.
- Ensure you are on the milestone branch and that the branch is up to date with latest from
master
- Run
npm install
to ensure your local node_modules are in sync with yourpackage-lock.json
- Run
npm outdated
- Go into
package.json
and update version numbers to the latest based on outdated. Pay attention to any major version updates as they may contain breaking changes! - Run
npm install
again. This will updatepackage-lock.json
. - Run
npm run build
,npm start
andnpm run storybook
and make sure those commands execute correctly - Check in
package.json
andpackage-lock.json
aschore: updated dev deps
.
We use commitlint conventional configuration to lint all commit messages.
When determining the commitlint type, use the following guidance:
build : package scripts or build scripts
ci : GitHub Actions
chore : project file/folder structure
docs : website docs/examples
feat : new Skin module
fix : bug fix on a Skin module
refactor : refactor of a Skin module
revert : revert previous commit
style : website or storybook styles
test : storybook stories
Guidance for pull requests:
- Always double-check which branch you are attempting to merge into. The target branch should always be a milestone branch!
- Only Skin admins are permitted to merge into
master
- Non-atomic commits should be squashed (i.e. "work in progress" type commits).
- Do not add any commit that leaves the code in a broken state.
- Pull request for a feature must only contain changes related to the issue (NOTE: refactoring/cleanup type PRs are often exempt from this rule)
- Do not be tempted to go fixing or refactoring unrelated issues. Doing so can make the code reviewer's job more difficult and/or time consuming, as well as increasing risk of regression
- If you spot some other unrelated bug or code smell, please create a GitHub issue for it.
- After the pull request has been merged, your issue branch should be immediately deleted (by yourself or admin)
eBay Skin is an implementation of the eBay MIND Patterns. The MIND patterns naming scheme follows an accessibility-first mindset; thus aligning our developer speak as closely as possible with existing W3C web standards & conventions.
When contributing to Skin, please bear the following guidelines in mind:
- Ensure all markup adheres to our accessibility patterns
- Ensure all markup is valid HTML
- Leverage ARIA roles, states and properties for styling hooks wherever possible. This safeguards against non-accessible markup (NOTE: this will increase specificity, but we accept this as a worthwile tradeoff)
- Use BEM syntax for modifiers (double-dash) and nested classes (double-underscore)
- Use the
<svg>
tag for icons - Never use the
<i>
tag for icons - Harness CSS margin-collapse wherever possible.
- Most block-level modules will require margin top and bottom as a sensible default
- Do not use presentational classnames, e.g.
.btn--green
should be.btn--secondary
for example - Do not combine classes into a single classname, e.g.
btn-sec
should bebtn btn--sec
, this allows cascades without advanced attribute selectors or pre-processors - Do not chain BEM modifiers (e.g.
.btn--large.btn--primary
). This is a code smell. - Do not use ambiguous or global classnames, e.g.
.large
should be.btn--large
- Do not use class
.disabled
to disable buttons or form elements, use the HTMLdisabled
property instead - Do not wrap inputs with labels, use explicit labels instead (e.g. use the
for
andid
attributes) - Do not use
href="#"
orhref="javascript"
in examples, usehref="http://www.ebay.com"
or any other dummy url - Every
<img>
tag must have analt
attribute, with no exceptions. The value can be an empty string for presentational images. - Avoid naming conflicts with other grid systems (e.g. Bootstap Grids)
- Keep LESS pre-processor usage restricted to variables, mixins and basic nesting (see below). 9 times out of 10 advanced features of pre-processors can be avoided by using CSS properly.
- Avoid too much nesting/indenting of LESS selectors as it can reduce human scan-ability of code and can also result in sub-optimal compiled CSS. Try and restrict nesting to pseudo selectors only (e.g.
:focus
,::after
). - Avoid over specificity (unless required for accessibility safeguarding). The fewer rules required to check for a given element, the faster style resolution will be. This is the key to dramatically increasing performance. https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Writing_efficient_CSS
- Please do not commit commented out code to production.
In comparison to past versions, Skin now offers a very minimal public LESS API (i.e. variables and mixins). Over time this may be reduced to zero. This is mainly due to the introduction of CSS Custom Properties (see next section below).
Skin has a token based system that leverages CSS Custom Properties. The tokens are categorised into three levels:
- core
- semantic
- component
Skin provides a set of core and semantic defaults but, in order for modules to render correctly, they must be explicitly included by the end user.
Core tokens are our primitives. They currently represent colour and border radius, but in time will go on to include spacing, type ramp, breakpoints and more. For example:
- color-neutral-1
- color-blue-4
- border-radius-100
- spacing-100 (not yet available)
Semantic tokens are aliases of core tokens. They represent an aspect of the interface that is common across the site. For example:
- color-background-primary
- color-background-confirmation
- color-foreground-on-confirmation
NOTE: semantic token values may change dynamically at runtime depending on the "prefers-color-scheme" media query (i.e. Dark Mode).
Component tokens are not used by Skin itself, but we expose them as a "brute-force" means for a page to override the system described above for one specific aspect of a component. For example:
- badge-background-color
- switch-checked-background-color
- textbox-placeholder-color
Obviously with great power, comes great responsibility.
Every Skin module has full support for dark mode.
Dark mode is powered by the Custom Property API. When the "prefers-color-scheme" media query is satisfied, all semantic token values will be replaced, dynamically at runtime, with the values from the relevant tokens module (e.g. evo-semantic-dark
or evo-semantic-light
).
NOTE: the semantic dark mode tokens are not included by default. They must be explicitly bundled by the end user. This allows end users to opt-in to dark mode only when their base page is ready for it.
Every module requires a page in storybook. In addition to the main use cases, try and cover as many variants, scenarios and edge cases as possible. The following tests are required for every module:
- RTL (right to left languages)
- Font-Size increase (up to 200%)
- Color inheritance (to a certain degree)
Each story must be isolated to a single test. This allows us to easily run visual regression testing.
We use Percy to do visual regression and compare visual changes in feature branches with the UIs in production. As such, changes to any specific module will need to verified against unintended consequences of those changes. This is usually to be done by internal contributors.
External contributors cannot run Percy visual regression tests. However, they should mark the modules that were changed in pull requests to allow the internal team to run visual regression tests.
Internal contributors will need to set up to run Percy snapshots by adding the Percy token to their operating system's environment variables. On a Mac, it would be like so:
export PERCY_TOKEN=[TOKEN_GOES_HERE]
This will allow internal contributors to run Percy snapshot tests.
Snapshots will likely be ran by developers locally before pushing up changes. Once they are ran, Percy dashboard should be checked to ensure no unintended style changes have taken place. If there are unintended style changes that have occurred, those should be reverted/fixed. Once the set of new local changes is final and in scope with the changes related to the issue, the snapshot run will need to be marked as the canonical version against which future updates are compared.
Running snapshots has two modes for all variations - build mode and dry mode.
Build mode creates snapshots for stories, uploads the snapshots to Percy and created a new Percy build for the purposes of making comparisons to previous visual builds.
Dry mode runs through snapshots (mainly for the purpose of verifying which stories will be captured) but does not upload the snapshots and does not create a Percy build.
To run all storybook snapshots in build mode:
npm run snapshots:all
To run all storybook snapshots in dry mode:
npm run snapshots:all:dry
To run single specific storybook snapshot in build mode for single module:
npm run snapshots 'Button'
To run multiple specific storybook snapshots in build mode for single module:
npm run snapshots 'Button,Icon'
To run single storybook snapshots in build mode for single module:
npm run snapshots:dry 'Button'
To run multiple storybook snapshots in dry mode for single module:
npm run snapshots:dry 'Button,Icon'
As internal contributors may see in package.json
, there are two other scripts, snapshots:execute
, snapshots:execute:dry
. These are scripts that should not be run directly. They are fired from gulpfils.js
after the Percy storybook regexes have been formatted.
First, be sure to Run npm install
to install all dependencies from NPM.
We use Marko Run to generate HTML from templates, SASS to preprocess and compile CSS. The website can be run and hosted locally (see next section) during development.
In order to run a dev server of the site, you can run npm run dev
. This launches the server which should allow you to see updates as you change your CSS or HTML. This will launch the site at http://localhost:3000
Our site source is located in src/routes
. These provide the basic site routing. Inside src/components
are our common components which we use to show repeated parts of the site (such as syntax highlighting our code). Finally, all top level modules are located in src/modules
. All these files will be used as the component name as well as in the nav. These are auto discoverable.
To build the site, run npm run deploy
. This will create all the site assets in _site
.
All CSS files are read directly from the source from src/bundles/skin-full.scss
The following scripts are available via npm:
npm start
- Builds the server and launches it at post 3000 (This does not have live reloading)npm run dev
- Starts local BrowserSync server on port 3000 (This has live reloading)npm test
- Runs a build and lints CSS and LESS filesnpm run build
- Runs a build only (no server)
To add new SVG icons, please follow the icon creation guide.
The @ebay/skin
module is published to the public NPM repository at https://registry.npmjs.org/.
Please ensure your NPM registry is set correctly and that you are on the package owners list, i.e. npm owner ls @ebay/skin
.
A pre-release is always made from a milestone branch.
- Run
npm version prepatch
,npm version preminor
, ornpm version premajor
. If you need to increment an existing prerelease usenpm version prerelease
. This command will automatically:- update the version number in css build files
- update the version number in
package.json
- commit all changes locally
- create a Git tag
- Push commit to origin.
- Run
npm publish --tag beta
to publish the package to NPM.
A final release is always made from the master branch.
- Create a GitHub PR to merge the milestone branch into master branch.
- Merge the PR after approval (do not squash!)
- Switch to your local master branch and pull the changes from origin.
- Run
npm version patch
,npm version minor
, ornpm version major
. This command will automatically:- update the version number in css build files
- update the version number in
package.json
- update the version number in Jekyll docs
- commit all changes locally
- create a Git tag
- Push commit to origin.
- Push the git tag to origin, e.g.
git push origin v3.1.0
. - Run
npm publish
to publish the package to NPM. - Publish the
/_cdn/skin/{version}
folder to the CDN.
After the module has been successfully pushed to NPM you should go ahead and create a Git release using the new Git tag that was created.
The release notes should reference all issues inside the relevant milestone.
If the master
branch is currently at v12.x
, but we need to go back and apply a critical bug fix to v6.3.x
, what do we do?
Git tags to the rescue! Git tags allow us to go back to any moment in time that we have previously "tagged".
Do not try and push an entire feature in a hot fix!! A hotfix is allowed for small one-liner type fixes only.
- Go to tags page: https://github.com/eBay/skin/tags
- Select the tag you'd like to go back in time to, e.g. https://github.com/eBay/skin/tree/v6.3.5
- Select the tag dropdown and create a new branch named accordingly, e.g
6.3.6
. This is the branch you will merge your PR to and do the release from. - Create another branch for your local dev work, e.g.
1723-textbox-fix
. - Now follow the release steps mentioned above, but substituting
master
branch for your release branch (e.g.6.3.6
) and milestone branch for your dev branch (e.g.1723-textbox-fix
). IMPORTANT: No changes should be pushed to master branch! - Don't forget to publish your new git tag (e.g.
v6.3.6
) - Use
npm publish --tag hotfix
when publishing to NPM to tag this as a hotfix.
The website archive under /docs/archive
should be updated each time a minor or major release is published.
- In a local branch, checkout the tag of the previous version, e.g.
git checkout v10.7.5
- Run
npm i
- Run
npx marko-run build -o /docs/archive/v0.7.5
- Create a pull request