Skip to content
This repository was archived by the owner on Jan 25, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ node_modules
# builds
build
dist
dist-ssr
*.local
.rpt2_cache

# misc
Expand Down
147 changes: 45 additions & 102 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,129 +4,72 @@

`npm install`

`npm install -g typescript` if you have never install TS

`npm run build`
`npm run dev`

There are a few ways of making new components for Indigo. Let's cover some of the core patterns.

## Component Patterns

### Single Element Component with dynamic properties

Creating a basic theme-aware component with dynamic properties from scratch.
Creating a basic component with dynamic properties that alter styling from scratch.

```tsx
import styled from "styled-components";
import css, { SystemStyleObject } from "@styled-system/css";
// commonStyle includes all commonly used styled-system props
import { commonStyle, CommonStyleProps } from "./system/unions";

// Define property types and export typing
export type LabelProps = CommonStyleProps & {
gray?: boolean;
bold?: boolean;
mono?: boolean;
};
import React, { FC } from "react";
import classNames from "classnames";

// First, a we create a style object. Then, we pass it to css(), whcih converts values like fontSize:0 to fontSize:'12px'. The conversion is based on the theme. Css() returns a function that can be passed to styled.foo() as a StyleFn, like border, color, and flexbox imported from styled-system. This method is convinient because you don't have to pass the theme as a prop and write a bunch of template string functions for each dynamic property. We also assign prop defaults in the argument field.
const style = ({ gray = false, bold = false, mono = false }: LabelProps) =>
css({
fontWeight: bold ? "bold" : "regular",
color: gray ? "gray" : "black",
fontFamily: mono ? "mono" : "sans",
display: "block",
lineHeight: "short",
fontSize: 1,
pointerEvents: "none",
userSelect: "none",
verticalAlign: "middle",
width: "100%",
} as SystemStyleObject);

// Here, we define out component. Because we want this component to use an HTML <label>, we used styled.label and pass a series of styleFns to it. These essentially 'gather' the styles defined above and styles passed through props. They are then merged in a css class which is seen in the DOM as something like `sc-jFdnav`.
export const Label = styled.label<React.PropsWithChildren<LabelProps>>(
style,
...commonStyle
);

// Add a displayName. It appears in the React devtools inspector and in errors. This is mandatory.
Label.displayName = "Label";
```

## Single Element Styled Component from Existing Component

Creating a styled component from an existing component, like one sourced from a 3rd party library.

```tsx
import { Form as FormikForm } from "formik";
import styled from "styled-components";
import { compose } from "styled-system";
import { structureStyle, StructureProps } from "./system/unions";
// Construct a union type of the variants
type LabelVariant = "default" | "important" | "caution";

// Create and export property typing.
type ManagedFormProps = StructureProps;

// An existing component can be passed to styled() to create a styled component.
export const ManagedForm = styled(FormikForm)<
React.PropsWithChildren<ManagedFormProps>
>({}, ...structureStyle);
// Use that variant type when constructing the props. It's often nice to leave the prop as optional and give a default value especially when that's the most often needed value.
export type LabelProps = HTMLAttributes<HTMLLabelElement> & {
variant?: LabelVariant;
};

ManagedForm.displayName = "ManagedForm";
```
// When building props it's important to let the underlying props of the HTML element pass through so we get things like className, onClick, etc. It's preferred to compose the base props using HTMLAttributes<element> so that they're complete.

### Composite React Component
// To build in the classes for variants we need the full class names so that Tailwind can pick them up and not purge them. Making a map like this is one way to do that and makes it easier to add new values later.
const variantMap: Record<LabelVariant, string> = {
default: "font-normal text-black",
important: "text-lg font-bold py-2 text-black",
caution: "font-bold text-orange-500",
};

This is a component made from several styled components imported from Indigo.
// Here, we define our component. Important to notice that we give variant a default value and also include className as a prop. Having className here gives the person using this component a path to inject customizations they might need, like margin, flexbox, etc. This is a convention that we like to keep in Indigo to always allow components to be customized to their surroundings, same as `props`.

//The the static classes inside the classNames helper function along with the variant map compose together to form the classes that will provide styling for the component.
export const Label: FC<LabelProps> = ({
variant = "default",
className,
children,
...props
}) => {
// ... some logic

return (
<label
className={classNames(
"label other-classes",
variantMap[variant],
className
)}
{...props}
>
{children}
</label>
);
};

```tsx
import * as React from "react";
import { CommonStyleProps } from "./system/unions";
import { Row } from "../Row/Row";
import { Col } from "../Col/Col";

// Create and export the main component typing
export type TwoUpProps = CommonStyleProps &
// Extend with this React typing so that the base component has div properties.
React.HTMLAttributes<HTMLDivElement> & {
// This is a special case where we overwrite `children` to be an array.
children: React.ReactNodeArray;
};

type ChildProps = CommonStyleProps & React.HTMLAttributes<HTMLDivElement>;

const Child = ({ children, ...props }: ChildProps) => (
<Col width={["100%", "100%", "50%"]} {...props}>
{children || <div />}
</Col>
);

export const TwoUp = ({ children, ...props }: TwoUpProps) => (
<Row flexDirection={["column", "row", "row"]} flexWrap="wrap" {...props}>
<Child>{children[0] || <div />}</Child>
<Child>{children[1] || <div />}</Child>
</Row>
);

TwoUp.displayName = "TwoUp";
// Add a displayName. It appears in the React devtools inspector and in errors. This is mandatory.
Label.displayName = "Label";
```

## Scripts

`npm run build` Builds the library with `esbuild` and constructs typings with `tsc`
`npm run build` Builds the library with `vite` and constructs typings with `tsc`, also copies over the Tailwind config and stylesheets.

`npm run esbuild` Builds the library with `esbuild` but skips generating typings. Typings take a long time to generate, so if you havn't changed your type definitons, this can rapidly speed up iteration time for visual polish tasks.
`npm run tailwind:dist` Copies the Tailwind config and our stylesheets for distribution.

`npm run reset` Removes node_modules and package-lock.json and npm installs fresh

### Related

| Library | Github | NPM |
| ------------ | ----------------------------------------- | ------------------------------------------------ |
| indigo-light | https://www.github.com/urbit/indigo-light | https://www.npmjs.com/package/@tlon/indigo-light |
| indigo-dark | https://www.github.com/urbit/indigo-dark | https://www.npmjs.com/package/@tlon/indigo-dark |
| indigo-react | https://www.github.com/urbit/indigo-react | https://www.npmjs.com/package/@tlon/indigo-react |

### License

MIT License © [Tlon](https://tlon.io)
88 changes: 50 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![npm (scoped)](https://img.shields.io/npm/v/@tlon/indigo-react?style=flat)](https://www.npmjs.com/package/@tlon/indigo-react)

Indigo React is a component library for implementing the [Indigo Design System](<https://www.figma.com/community/file/822953707012850361/Indigo-(alpha)>). It's built with React, [styled-components](https://styled-components.com) and [styled-system](https://styled-system.com). It also uses [Formik](https://formik.org/) and [Reach-UI](https://reach.tech/).
Indigo React is a component library for implementing the [Indigo Design System](<https://www.figma.com/community/file/822953707012850361/Indigo-(alpha)>). It's built with React and [Tailwind CSS](https://tailwindcss.com/). It also uses [Formik](https://formik.org/) and [Reach-UI](https://reach.tech/).

## Quick Start

Expand All @@ -15,63 +15,75 @@ npm install --save @tlon/indigo-react
2. Install peer dependencies

```bash
npm install --save @tlon/indigo-light styled-components styled-system react react-dom @reach/disclosure @reach/menu-button @reach/tabs markdown-to-jsx formik
$ npm install --save formik
```

If you are using Typescript, install the type definitions for several of these libraries.
3. Install and Setup Tailwind

```bash
npm install --save @types/styled-components @types/styled-system @types/styled-system__css
```
Tailwind has [significant documentation](https://tailwindcss.com/docs/installation) on how to get it setup in your particular environment.

3. Install a theme
Once you have Tailwind setup, you can simply import Indigo's `tailwind.config.js` and merge it with your config.

```bash
npm install --save @tlon/indigo-light @tlon/indigo-dark
**tailwind.config.js**

```js
import resolveConfig from "tailwindcss/resolveConfig";
import indigo from "@tlon/indigo-react/tailwind.config";

module.exports = resolveConfig(
{
purge: [],
theme: {
extend: {},
},
//... rest of your config
},
indigo
);
```

## Basic Usage

```js
import * as React from "react";
import { ThemeProvider } from "styled-system";
import { Text, Reset } from "@tlon/indigo-react";
import light from "@tlon/indigo-light";

class App extends React.Component {
render() {
return (
<ThemeProvider theme={light}>
<Reset />
<Text fontSize="2">Indigo!</Text>
</ThemeProvider>
);
}
}
In your main CSS file, you'll need to import both Tailwind and Indigo files:

```css
@import "tailwindcss/base";
@import "@tlon/indigo-react/base";

@import "tailwindcss/components";
@import "@tlon/indigo-react/components";

@import "tailwindcss/utilities";
@import "@tlon/indigo-react/utilities";
```

In the above, we are wrapping our application in styled-component's `ThemeProvider` and passing in our `theme` from `@tlon/indigo-light`. In practice, you should rarely need to import the theme.
**Example Component**

The `<Text />` component accepts a fontSize prop, which is one of many style props provided by `styled-system`. Using VSCode is the best way to see the list of props each component can accept.
```js
import React from "react";
import { Button } from "@tlon/indigo-react";

export const ExampleComponent = () => (
<div className="space-y-2">
<h2 className="h1">Important Information</h2>
<p className="text-gray-500">
Here's a block of text explaining something about why you need to save
</p>
<Button variant="primary">Save</Button>
</div>
);
```

You can also check out the [styled-system docs](https://styled-system.com/api) for a breakdown of props.
Indigo provides it's own components in addition to the utilities that Tailwind normally provides. A variety of classes have also been added for components that would only have styling applied and no other functionality.

Many of these props have corrosponding styling shortcuts, drawn from the provided theme, like `@tlon/indigo-light`. These shortcuts are also provided by `styled-system`. To see how props map to values in our theme, check out [styled-system's mapping](https://styled-system.com/table).
Above you can see a `<Button>` component used from Indigo, as well as a custom class for making the **Heading 1** style as `h1`. In addition to that we're using standard utilities from Tailwind like `space-y-2` and `text-gray-500`.

Take a look at the [theme](https://www.github.com/urbit/indigo-light) to get a sense for which style values can be accessed from styled props.
Full documentation of the new Tailwind version of Indigo is currently under development.

## Development

See [DEVELOPMENT.md](https://github.com/urbit/indigo-react/blob/master/DEVELOPMENT.md) for example cases of component patterns used to create Indigo.

### Related

| Library | Github | NPM |
| ------------ | ----------------------------------------- | ------------------------------------------------ |
| indigo-light | https://www.github.com/urbit/indigo-light | https://www.npmjs.com/package/@tlon/indigo-light |
| indigo-dark | https://www.github.com/urbit/indigo-dark | https://www.npmjs.com/package/@tlon/indigo-dark |
| indigo-react | https://www.github.com/urbit/indigo-react | https://www.npmjs.com/package/@tlon/indigo-react |

### License

MIT License © [Tlon](https://tlon.io)
Loading