|
3 | 3 | [](https://hex.pm/packages/weft) |
4 | 4 | [](https://hexdocs.pm/weft/) |
5 | 5 |
|
6 | | -Elm-UI-inspired layout primitives that generate deterministic CSS — core package (Lustre-free). |
| 6 | +Layout primitives for Gleam, inspired by Elm-UI. You describe layout with |
| 7 | +typed constructors instead of writing CSS by hand. Weft compiles those |
| 8 | +constructors into deterministic class names and a deduped stylesheet. |
| 9 | + |
| 10 | +It has no framework dependency. The core package produces plain class names |
| 11 | +and CSS strings that any renderer (Lustre, Nakai, raw HTML templates) can use. |
7 | 12 |
|
8 | 13 | ## Installation |
9 | 14 |
|
10 | | -```sh |
11 | | -gleam add weft |
| 15 | +Weft isn't on Hex yet. Add it as a git dependency: |
| 16 | + |
| 17 | +```toml |
| 18 | +[dependencies] |
| 19 | +weft = { git = "https://github.com/bbopen/weft", branch = "main" } |
12 | 20 | ``` |
13 | 21 |
|
14 | | -## Usage |
| 22 | +## Quick example |
| 23 | + |
| 24 | +```gleam |
| 25 | +import weft |
| 26 | +
|
| 27 | +pub fn card() { |
| 28 | + // Build a class from typed attributes |
| 29 | + let card_class = |
| 30 | + weft.class(attrs: [ |
| 31 | + weft.column_layout(), |
| 32 | + weft.padding(pixels: 16), |
| 33 | + weft.spacing(pixels: 8), |
| 34 | + weft.width(length: weft.fill()), |
| 35 | + weft.background(color: weft.rgb(red: 255, green: 255, blue: 255)), |
| 36 | + weft.rounded(radius: weft.px(pixels: 8)), |
| 37 | + weft.mouse_over(attrs: [ |
| 38 | + weft.background(color: weft.rgb(red: 245, green: 245, blue: 245)), |
| 39 | + ]), |
| 40 | + ]) |
| 41 | +
|
| 42 | + // Get the class name to put on your element |
| 43 | + let name = weft.class_name(class: card_class) |
| 44 | + // => "wf-a3b2c1d4" |
| 45 | +
|
| 46 | + // Render the stylesheet for all your classes |
| 47 | + let css = weft.stylesheet(classes: [card_class]) |
| 48 | + // => ".wf-a3b2c1d4{display:flex;flex-direction:column;...}" |
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +No CSS strings anywhere. Every value is typed and checked at compile time. |
| 53 | + |
| 54 | +## How deterministic CSS works |
| 55 | + |
| 56 | +Weft hashes the compiled CSS declarations with FNV-1a to produce class names |
| 57 | +like `wf-a3b2c1d4`. The same set of attributes always produces the same hash. |
| 58 | +Two elements that share identical styling get the same class name automatically, |
| 59 | +so the stylesheet never contains duplicates. |
| 60 | + |
| 61 | +This means you can call `weft.class()` freely in render functions without |
| 62 | +worrying about CSS bloat. If the attributes match, the output is reused. |
| 63 | + |
| 64 | +## What's in the box |
| 65 | + |
| 66 | +The API covers the layout and styling primitives you'd reach for in a |
| 67 | +typical web UI: |
| 68 | + |
| 69 | +- Flex layouts: `row_layout`, `column_layout`, `spacing`, `padding` |
| 70 | +- Grid layouts: `grid_layout`, `grid_columns`, `grid_rows`, `grid_fr` |
| 71 | +- Sizing: `fill`, `shrink`, `fill_portion`, `fixed`, `minimum`, `maximum` |
| 72 | +- Colors: `rgb`, `rgba`, `hsl`, `hex`, `transparent`, `current_color` |
| 73 | +- Typography: `font_size`, `font_weight`, `font_family`, `line_height`, `text_align` |
| 74 | +- Borders and rounding: `border`, `rounded`, `shadows`, `outline` |
| 75 | +- Positioning: `position`, `top`, `left`, `right`, `bottom`, `inset` |
| 76 | +- Transitions: `transition`, `transitions` with typed duration and easing |
| 77 | +- Pseudo-states: `mouse_over`, `focused`, `active`, `disabled`, `focus_visible` |
| 78 | +- Responsive: `when` (media queries), `when_container`, `hide_below`, `show_below` |
| 79 | +- Scroll: `scroll_x`, `scroll_y`, `overflow`, `scroll_snap_type` |
| 80 | +- Overlay positioning: a constraint solver for anchored overlays (dropdowns, tooltips) |
| 81 | +- Filters: `filter_blur`, `filter_brightness`, `backdrop_filter` |
| 82 | +- Groups: `group` / `group_hover` for parent-scoped hover effects |
| 83 | + |
| 84 | +All values go through opaque types. There's no `style("property", "value")` |
| 85 | +escape hatch in the public API. |
| 86 | + |
| 87 | +## Cross-target |
| 88 | + |
| 89 | +Weft is pure Gleam with no FFI. It builds on both Erlang and JavaScript |
| 90 | +targets. The only dependency is `gleam_stdlib`. |
| 91 | + |
| 92 | +## License |
15 | 93 |
|
16 | | -See [SPEC.md](SPEC.md) for the complete technical specification. |
| 94 | +Apache 2.0 -- see [LICENSE](LICENSE). |
0 commit comments