@revive-real-estate/aether
TypeScript icon, indicating that this package has built-in type declarations

0.16.1 • Public • Published

Aether

Revive's Component Library

Getting started

Pre-requisites

To work with this project, you'll need to have Node and Yarn installed on your system.

Installation

  1. git clone https://github.com/Revive-Home/Aether.git && cd aether
  2. yarn install

Before you start contributing to Aether, be sure to read the contribution guide (TBA)

Development

Aether uses following technologies:

  • React
  • TypeScript
  • Tailwind
  • Vite
  • Storybook

Run yarn dev to start Storybook for development.

Tailwind

To style the components, Aether uses TailwindCSS.

Overriding the styles

The styling of Aether components can be overridden in the consumer apps by passing the Tailwind classes to the className prop.

Prefix

To avoid the className conflict in consumer apps, Aether's Tailwind is set to require the prefix. All class names should start with the prefix, aether-.

Example:

<div
  className="aether-p-10 aether-text-red-300 aether-border aether-border-red-300"
>
   Example
</div>

TODO: Add tailwind guideline/practice

Theme Aether utilizes the custom theming feature of Tailwind. The custom theming can be configured in tailwind.config.js.

Headless UI

Aether uses headlessui to abstract away some of the component behavior logic.

Usage

Within a separate application that uses Aether, import the style.css to apply styling in the root file of the application.

Next.js example:

// in `_app.tsx`
import "@revive-real-estate/aether/dist/style.css"
// ...other imports

And then, import the desired component as follows:

import { Button } from "@revive-real-estate/aether";

Within Aether itself, import the desired component by pointing to the component file. The alias (@) should be used for the import path:

import { Button } from "@/components/Button";

Using Aether package locally

Aether can be installed and tested locally without publishing to NPM by using yalc.

In Aether, change the version in package.json to indicate this is a test package.

Example: 0.0.0-yalc-test

Then, run

yarn build && yalc publish

yarn build will build the package and create /dist, then yalc publish command will copy all the files that should be published in remote NPM registry.

Then in consuming app, run

yalc add <package_name@version_number> && yarn

The <@version_number> should match the version in package.json of Aether.

To import Aether components, refer to the Usage section.

Writing components

All components should be written in TypeScript. Export the interface or type so they can be consumable in the app.

Each prop defined in the interfaces or types should have a description. Storybook Docs will translate these descriptions and generates the Props Table.

Example:

export interface ButtonProps
  extends React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {
  /** Text within the button */
  children?: React.ReactNode | React.ReactNode[];
  /** Provide a custom className that is applied directly to the button */
  className?: string;
  /** Specify whether the control is disabled */
  disabled?: boolean;
  /** Specify the theme of the button */
  variant?: "primary" | "secondary" | "gray" | "turquoise";
}

The components need to be exported in the src/index.ts file to be consumable. The type definition will be automatically generated by the Vite and included to the bundle.

Class names

To make it easier and quicker for developers to debug, it is recommended that the className of a component begins with a description of the component itself, such as className="aether-button".

If there are multiple classNames that get added conditionally, clsx should be used to consolidate all classNames into a string. This helps in avoiding any potential conflicts or errors that may occur due to multiple classNames being added separately.

const classes = clsx(
  "aether-button",
  ButtonClasses.baseStyle,
  ButtonClasses[size],
  variant && ButtonClasses[variant],
  disabled && ButtonClasses.disabled,
  fullWidth && ButtonClasses.fullWidth,
  loading && ButtonClasses.loading,
  className // className prop should be placed at the end
);

Extending Components with {...rest} Props

Many of Aether components support {...rest} props, allowing you to pass additional attributes directly to the HTML elements rendered by the component. This feature provides flexibility for extending our built-in components in various ways.

Benefits

  • Custom Styling: Add custom classes or styles directly to the component.
  • Event Handling: Attach event listeners like onClick, onBlur, etc.
  • Accessibility: Add attributes like aria-label, aria-labelledby, etc., to improve accessibility.
  • Forward Compatibility: Components will automatically support new HTML and React attributes as they are introduced.
// Example: Adding custom styles to a Button component using `style` attribute
import { Button } from "@revive-real-estate/aether";

<Button style={{ backgroundColor: 'tomato' }} onClick={handleClick}>
  Click Me
</Button>

Component Template

There's a set of template files for a component. Copy the src/example/ComponentTemplate folder and paste it inside the src/components, then rename the folder and files to an appropriate component name.

Adding SVG icons

Aether supports the import/export of SVG files. The custom icons should be created by the design team and exported as an SVG file.

Steps to add SVG icon to Aether:

  1. Export the SVG files for the desired icon from Figma
  2. Add SVG files to src/components/Icon/aether-icon-files
  3. In src/components/Icon/aether-icon-files/index.tsx, add an export of the newly added icon:
//...more icons
import { ReactComponent as NewIconGreen } from "./green/new-icon.svg"

export {
  // ...more icons
  NewIconGreen
}
  1. In src/components/Icon/data.ts, add the icon name.

Example:

export const AetherIconNamesArray = [
  // ...more icons
  "new-icon",
] as const
  1. In src/components/Icon/aether-icons.ts, import the newly added icon from src/components/Icon//aether-icon-files:
import {
  // ...more icons
  NewIconGreen
} from "./aether-icon-files"
  1. Add new entry to iconMap object in src/components/Icon/aether-icons.ts
export const getAetherIcon = (name: ListIconNames): SvgIcon | undefined => {
  const iconMap: IconMap = {
    // ...more icons
    "new-icon-green": NewIconGreen
  }

  // ...more code
}

Testing

For unit testing, Aether uses Vitest and React Testing Library.

Chromatic Visual Regression Testing

We use Chromatic, integrated with GitHub Actions, to automatically detect visual regressions in our UI components. This tool compares new changes against established baselines, helping us maintain visual consistency. Our main branch Chromatic link serves as a reference for visual comparisons. This link below gets updated to reflect the latest main branch.

Chromatic link: https://main--63cad365fab53dc41982eaae.chromatic.com/


Publishing the package

Our package publishing process is fully automated using GitHub Actions and semantic-release. This setup ensures a consistent and efficient release process without manual intervention.

Whenever a push is made to the main branch, the GitHub Actions workflow is triggered. It sets up the required environment, builds the package, and utilizes semantic-release to handle versioning and changelog generation. The new version is then automatically published to NPM, and a corresponding GitHub release is created.

This streamlined approach allows us to focus on development, knowing that our releases are handled with precision and transparency. Configuration details can be found in the .releaserc file and the corresponding GitHub Actions workflow file in our repository.

Readme

Keywords

none

Package Sidebar

Install

npm i @revive-real-estate/aether

Weekly Downloads

11

Version

0.16.1

License

none

Unpacked Size

10.5 MB

Total Files

255

Last publish

Collaborators

  • hoshkitsunoda
  • mansoorbahramand