https://github.com/pgbiel/elembic
Framework for custom elements and types in Typst
https://github.com/pgbiel/elembic
data-structures elements types typst validation
Last synced: 25 days ago
JSON representation
Framework for custom elements and types in Typst
- Host: GitHub
- URL: https://github.com/pgbiel/elembic
- Owner: PgBiel
- License: other
- Created: 2024-12-29T21:46:57.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-10-07T01:24:52.000Z (7 months ago)
- Last Synced: 2026-03-28T01:55:09.483Z (about 1 month ago)
- Topics: data-structures, elements, types, typst, validation
- Language: Typst
- Homepage: https://pgbiel.github.io/elembic/
- Size: 831 KB
- Stars: 58
- Watchers: 2
- Forks: 4
- Open Issues: 18
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# elembic
Framework for custom elements and types in Typst. **Supports Typst 0.11.0 or later.**
**Read the book:** https://pgbiel.github.io/elembic
**Mirrors:** [GitHub (pgbiel/elembic)](https://github.com/PgBiel/elembic); [Codeberg (pgbiel/elembic)](https://codeberg.org/PgBiel/elembic)
## About
Elembic lets you create [**custom elements,**](https://pgbiel.github.io/elembic/elements/creating/index.html) which are **reusable and customizable document components,** with support for **typechecked fields, [show and set rules](https://pgbiel.github.io/elembic/elements/styling/index.html)** (without using any `state` by default!), **[reference and outline support,](https://pgbiel.github.io/elembic/elements/creating/labels-refs.html)** as well as features not present in Typst elements today such as **[revokable rules](https://pgbiel.github.io/elembic/elements/styling/revoke.html)** and **[nested element selectors](https://pgbiel.github.io/elembic/elements/filters/within.html)**. In addition, Elembic lets you create [**custom types,**](https://pgbiel.github.io/elembic/types/custom-types/index.html) which also support **typechecked fields** but also [**custom casting**](https://pgbiel.github.io/elembic/types/custom-types/casts.html), and can be used in element fields or by themselves in arbitrary Typst code.
Elembic's name comes from "element" + ["alembic"](https://en.wikipedia.org/wiki/Alembic), to indicate that one of Elembic's goals is to experiment with different approaches for this functionality, and to help shape a future update to Typst that includes native custom elements, which will eventually remove the need for using this package.
Its documentation is at the Elembic Handbook: [https://pgbiel.github.io/elembic](https://pgbiel.github.io/elembic)
This library has a few limitations which are [appropriately noted in the book.](https://pgbiel.github.io/elembic/about/limitations.html)
## Who is elembic for?
Elembic is especially suited for:
1. **Packages:** elembic's elements allows creating reusable components which can be freely customized by your package's end users. With typechecking and other features, elembic's got you covered in terms of flexibility. See the ["Simple Theorems" example](https://pgbiel.github.io/elembic/examples/simple-theorems.html) for a sample.
2. **Templates:** elembic's elements can be used for fine-grained configuration of parts of your template. See the ["Simple Thesis" example](https://pgbiel.github.io/elembic/examples/simple-thesis.html) for a sample.
## Installation
Just import the latest elembic version from the package manager and you're ready to go!
```typ
#import "@preview/elembic:1.1.1" as e
// See the full example below
#show: e.set_(element, stroke: red)
// ...
```
## Example
### Custom element
```typ
#import "@preview/elembic:1.1.1" as e: field, types
#let bigbox = e.element.declare(
"bigbox",
prefix: "@preview/my-package,v1",
doc: "A fancy and customizable box.",
display: it => block(fill: it.fill, stroke: it.stroke, inset: 5pt, it.body),
fields: (
field("body", types.option(content), doc: "Box contents", required: true),
field("fill", types.option(types.paint), doc: "Box fill"),
field("stroke", types.option(stroke), doc: "Box border", default: red)
)
)
#bigbox[abc]
#show: e.set_(bigbox, fill: red)
#bigbox(stroke: blue + 2pt)[def]
```

### Custom type
```typ
#import "@preview/elembic:1.1.1" as e: field, types
#let person = e.types.declare(
"person",
prefix: "@preview/my-package,v1",
doc: "Relevant data for a person.",
fields: (
field("name", str, doc: "Person's name", required: true, named: true),
field("age", int, doc: "Person's age", default: 40),
field("preference", types.any, doc: "Anything the person likes", default: none)
),
casts: (
(from: dictionary),
(from: str, with: person => name => person(name: name)),
)
)
#assert.eq(
e.repr(person(name: "John", age: 50, preference: "soup")),
"person(age: 50, name: \"John\", preference: \"soup\")"
)
// Manually invoke typechecking and cast
#assert.eq(
types.cast((name: "abc", age: 99), person),
(true, person(name: "abc", age: 99))
)
#assert.eq(
types.cast("abc", person),
(true, person(name: "abc"))
)
// Can then use 'person' as the type of an element's field, for example
```
## Source structure
- `pub/`: Contains public re-exports of each module (so we can keep some things private)
- `data`: Functions and constants related to extracting data from elements and types
- `element`: Functions related to creating and using elements and their rules (set rules, revoke rules and so on)
- `filters`: Functions to create and match element filters
- `types`: Functions and constants related to Elembic's custom type system
- `fields`: Functions related to element and type field parsing
## License
Licensed under MIT or Apache-2.0, at your option.