Please read EasyPost's general contribution guidelines.
Please read EasyPost's code of conduct.
Easy UI follows semantic versioning. We release patch versions for bug fixes, minor versions for new features, and major versions for breaking changes. When we make breaking changes, we try to introduce deprecation warnings in a minor version along with the upgrade path so that our users learn about the upcoming changes and migrate their code in advance.
The following sections detail what kinds of changes result in each of major, minor, and patch version bumps:
- Removal of a component
- Removal of a prop from a component
- Change to the type accepted for a prop
- Breaking changes to minimum version of dependencies
- Breaking changes to public variables, functions, and mixins
- New component
- New prop for a component
- Additional type accepted for a prop
- Deprecation of a component, prop, public variable, function, or mixin (ahead of its likely removal in the next major version)
- Breaking change to the HTML generated by a component, including addition, removal, or renaming of classes
- Changes that do not impact public APIs
- Non-breaking changes to minimum version of dependencies
- Breaking changes to private variables, functions, and mixins
Easy UI is a public project so pull requests are welcome. Before working on a large change, it is best to open an issue first to discuss it with the core team.
We'll review your pull request and either merge it, request changes to it, or close it with an explanation. We'll do our best to provide updates and feedback throughout the process.
Before submitting a pull request, please:
- Review best practices
- Fork the repository and create your branch from
main
- Run
npm install
in the repository root - If you’ve fixed a bug or added code, make sure to add tests
- Ensure the test suite passes with
npm test
- Format your code with
npm run format
- Make sure your code lints with
npm run lint
- Create a changeset by running
npm run changes:add
. More info.
The changelog is created with Changesets.
A changeset describes changes made in a branch or commit. It holds three bits of information:
- What packages we need to release
- What version we are releasing packages
- A changelog entry for the released packages
Add a changeset if you have made any changes that will require a package version bump and release:
- Run
npm run changes:add
. - Select the packages you want to include using ↑ and ↓ to navigate to packages, and space to select a package. Hit enter when all desired packages are selected.
- Select a bump type for each selected package.
- Provide a message to be written into the changelog on the next release.
To check the status of changesets that currently exist run npm run changes:status
. If there are changes to packages but no changesets are present, it exits with error status code 1
.
Keep the following in mind when authoring your changelog entry (final prompt after running npm run changes:add
):
- Use a positive, conversational tone (for example, use "support" over "allow" and other authoritative verbs)
- Avoid redundancy when possible (try to phrase a bug fix entry without the word "bug")
- Use sentence case
- Use plain language
Generally, changes related to these topics can be omitted:
- Dev dependencies upgrades
- Chores (infrastructure, release process, etc.)
If your pull request involves changes to any component APIs, please read over our list of best practices below.
- We define a one-off as a deviation from best practices. We understand that one-offs are virtually inevitable, so when we create them, we should have a good reason for doing so as creating one-offs adds additional context for contributors and users as well as introduces the possibility of creating inconsistent UX.
- Property names should be descriptive and intuitive of what they do. Intuitive names are preferred over descriptive names. For a button,
urlLinkDestination
is a descriptive name, buthref
is intuitive.
- Properties that have identical purposes across different components should share the same name. Similarly, properties that have identical purposes should also share the same type. If one component has a boolean
isValid
, other components that intend to control validity should do the same.
- Although unavoidable at times, we should do our best to not create properties that are dependent upon another. This helps avoid configurations that lead to invalid states. If a component has multiple dependent properties, take a closer look at the overall structure of the component.
- Booleans should be prefixed with simple verbs. For a button, the property name
isActive
is preferred toactive
. - By default booleans should be false. This makes the notation a bit cleaner for when the boolean is active:
// avoid
<Button isNotDisabled={false} />
// preferred
<Button isDisabled />
- Avoid creating booleans with hierarchical structure. If an icon component can have more than two possible placements, avoid
isIconStart
,isIconMiddle
, andisIconEnd
since we’d have to decide which variant takes precedence. Instead use an enum.
- For components that process multiple events with the same verb, they should be named with a descriptive noun in between. For a table component that needs to respond to changes to its column and row, use
onRowChange
andonColumnChange
.
- Abstractions are really difficult to get right and reason about. No abstraction is preferred to clunky abstractions. Ideally we want our components to be as composable as possible.
- For components that need to render a subcomponent, use the slot paradigm of cloning the React element.
- Components should not expose the
className
property as we run the risk of creating inconsistent UX.