forge/README.md
2025-12-29 12:21:58 -08:00

93 lines
2.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Forge
## Why Forge?
CSS is powerful, but hostile.
### Problems with CSS
- Styles are **global and open** — anything can override anything.
- Theres **no link** between a class in markup and its definition.
- Inline styles exist because theres **no structured way to vary styles per instance**.
- Overrides are silent — conflicts happen without feedback.
- Complex components require selector gymnastics and reach-in styling.
### What Forge Does Instead
- Styles are **local to components** and attached by generated handles, not strings.
- **Parts** give components named sub-targets without selectors.
- **Variants** replace inline styles with typed, declarative parameters.
- Style composition is **deterministic** (known merge order, last-wins).
- Overlapping changes are **warned about in dev**, not silently ignored.
### What Forge Is
- A typed, local, variant-driven way to author CSS.
- A system that optimizes for **people typing at a keyboard**, not selectors in a cascade.
### What Forge Is Not
- Not a new component model.
- Not a new language.
- Not a CSS replacement — it compiles _to_ CSS, but removes the chaos.
Example:
```tsx
import { define } from "forge"
export const Button = define("button", {
base: "button",
padding: 20,
background: "blue",
variants: {
kind: {
danger: { background: "red" },
warning: { background: "yellow" },
}
},
})
// Usage
<Button>Click me</Button>
<Button kind="danger">Click me carefully</Button>
<Button kind="warning">Click me?</Button>
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'
<Profile pic={user.pic} bio={user.bio} />
```