194 lines
3.7 KiB
Markdown
194 lines
3.7 KiB
Markdown
# ⚒️ forge
|
|
|
|
```
|
|
╔═╝╔═║╔═║╔═╝╔═╝
|
|
╔═╝║ ║╔╔╝║ ║╔═╝
|
|
╝ ══╝╝ ╝══╝══╝
|
|
```
|
|
|
|
## overview
|
|
|
|
Forge is a typed, local, variant-driven way to organize CSS and create
|
|
self-contained TSX components out of discrete parts.
|
|
|
|
## css problems
|
|
|
|
- Styles are global and open - anything can override anything anywhere.
|
|
- No IDE-friendly link between the class name in markup and its definition.
|
|
- All techniques are patterns a human must know and follow, not APIs.
|
|
- Errors happen silently.
|
|
|
|
## forge solutions
|
|
|
|
- All styles are local to your TSX components.
|
|
- Styles defined using TS typing.
|
|
- Component styles are made up of independently styled "Parts".
|
|
- "Variants" replace inline styles with typed, declarative parameters.
|
|
- Style composition is deterministic.
|
|
- Themes are easy.
|
|
- Errors and feedback are provided.
|
|
|
|
## examples
|
|
|
|
### styles
|
|
|
|
```tsx
|
|
import { define } from "forge"
|
|
|
|
export const Button = define("button", {
|
|
base: "button",
|
|
|
|
padding: 20,
|
|
background: "blue",
|
|
})
|
|
|
|
// Usage
|
|
<Button>Click me</Button>
|
|
```
|
|
|
|
### variants
|
|
|
|
```tsx
|
|
import { define } from "forge"
|
|
|
|
export const Button = define("button", {
|
|
base: "button",
|
|
|
|
padding: 20,
|
|
background: "blue",
|
|
|
|
variants: {
|
|
status: {
|
|
danger: { background: "red" },
|
|
warning: { background: "yellow" },
|
|
}
|
|
},
|
|
})
|
|
|
|
// Usage
|
|
<Button>Click me</Button>
|
|
<Button status="danger">Click me carefully</Button>
|
|
<Button status="warning">Click me?</Button>
|
|
```
|
|
|
|
### parts + `render()`
|
|
|
|
```typescript
|
|
export const Profile = define("div", {
|
|
padding: 50,
|
|
background: "red",
|
|
|
|
parts: {
|
|
Header: { display: "flex" },
|
|
Avatar: { base: "img", width: 50 },
|
|
Bio: { color: "gray" },
|
|
},
|
|
|
|
variants: {
|
|
size: {
|
|
small: {
|
|
parts: { Avatar: { width: 20 } },
|
|
},
|
|
},
|
|
},
|
|
|
|
render({ props, parts: { Root, Header, Avatar, Bio } }) {
|
|
return (
|
|
<Root>
|
|
<Header>
|
|
<Avatar src={props.pic} />
|
|
<Bio>{props.bio}</Bio>
|
|
</Header>
|
|
</Root>
|
|
)
|
|
},
|
|
})
|
|
|
|
// Usage:
|
|
import { Profile } from "./whatever"
|
|
|
|
console.log(<Profile pic={user.pic} bio={user.bio} />)
|
|
console.log(<Profile size="small" pic={user.pic} bio={user.bio} />)
|
|
```
|
|
|
|
## themes
|
|
|
|
built-in support for CSS variables with full type safety:
|
|
|
|
```tsx
|
|
// themes.tsx - Define your themes
|
|
import { createThemes } from "forge"
|
|
|
|
export const theme = createThemes({
|
|
dark: {
|
|
bgColor: "#0a0a0a",
|
|
fgColor: "#00ff00",
|
|
sm: 12,
|
|
lg: 24,
|
|
},
|
|
light: {
|
|
bgColor: "#f5f5f0",
|
|
fgColor: "#0a0a0a",
|
|
sm: 12,
|
|
lg: 24,
|
|
},
|
|
})
|
|
|
|
// Use theme() in your components
|
|
import { define } from "forge"
|
|
import { theme } from "./themes"
|
|
|
|
const Button = define("Button", {
|
|
padding: theme("spacing-sm"),
|
|
background: theme("colors-bg"),
|
|
color: theme("colors-fg"),
|
|
})
|
|
```
|
|
|
|
Theme switching is done via the `data-theme` attribute:
|
|
|
|
```tsx
|
|
// Toggle between themes
|
|
document.body.setAttribute("data-theme", "dark")
|
|
document.body.setAttribute("data-theme", "light")
|
|
```
|
|
|
|
The `theme()` function is fully typed based on your theme keys, giving
|
|
you autocomplete and type checking throughout your codebase.
|
|
|
|
## scopes
|
|
|
|
Sometimes you want your parts named things like ButtonRow, ButtonCell,
|
|
ButtonTable, etc, but all those Button's are repetitive:
|
|
|
|
```typescript
|
|
const { define } = createScope("Button")
|
|
|
|
// css class becomes "Button"
|
|
const Button = define("Root", {
|
|
// becomes "Button"
|
|
// ...
|
|
})
|
|
|
|
// css class becomes "ButtonRow"
|
|
const ButtonRow = define("Row", {
|
|
// ...
|
|
})
|
|
|
|
// css class becomes "ButtonContainer"
|
|
const ButtonContainer = define("Container", {
|
|
// ...
|
|
})
|
|
```
|
|
|
|
## see it
|
|
|
|
Check out the `examples/` dir and view them at http://localhost:3300 by
|
|
cloning this repo and running the local web server:
|
|
|
|
```
|
|
bun install
|
|
bun dev
|
|
open http://localhost:3300
|
|
```
|