first commit
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# template-builder
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`TemplateBuilder` is a fluent API for assembling an `EmailTemplate<TProps>`
|
||||
value step-by-step. It exists because constructing the template literal
|
||||
inline reads poorly when defaults and subject functions are non-trivial,
|
||||
and because the builder enforces presence of the three required fields
|
||||
(`name`, `subject`, `component`) at `build()` time with a typed error.
|
||||
|
||||
The class itself is a typical builder — each setter mutates the internal
|
||||
state and returns `this`. `build()` is the one terminal operation. Calls
|
||||
made after `build()` continue to work (the builder is not consumed), so a
|
||||
single builder can produce two slightly-different templates by switching
|
||||
one setter and calling `build()` twice.
|
||||
|
||||
## Features
|
||||
|
||||
- Fluent setters: `name`, `subject` (literal or function-of-props),
|
||||
`component`, `defaultProps`.
|
||||
- Runtime validation in `build()` — missing required fields raise
|
||||
`EmailTemplatesError(INVALID_TEMPLATE)` with a specific message key.
|
||||
- `createTemplateBuilder<TProps>()` factory for inference-friendly use.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createTemplateBuilder } from "@suaveplan/email-templates/template-builder";
|
||||
import { h } from "@suaveplan/email-templates/vnode";
|
||||
|
||||
interface Props { name: string; ctaUrl: string }
|
||||
|
||||
const myTemplate = createTemplateBuilder<Props>()
|
||||
.name("custom-welcome")
|
||||
.subject((p) => `Hi ${p.name}`)
|
||||
.component((p) => h("a", { href: p.ctaUrl }, "Click me"))
|
||||
.build();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Reuse a single builder to produce a localised template family by mutating
|
||||
between `build()` calls:
|
||||
|
||||
```ts
|
||||
import { createTemplateBuilder } from "@suaveplan/email-templates/template-builder";
|
||||
import { h } from "@suaveplan/email-templates/vnode";
|
||||
|
||||
interface Props { name: string }
|
||||
|
||||
const b = createTemplateBuilder<Props>()
|
||||
.component((p) => h("p", {}, `Hi ${p.name}`));
|
||||
|
||||
const en = b.name("greet-en").subject("Hello").build();
|
||||
const fr = b.name("greet-fr").subject("Bonjour").build();
|
||||
```
|
||||
|
||||
`en.subject === "Hello"` and `fr.subject === "Bonjour"` — the builder
|
||||
returns a fresh `EmailTemplate` object on each `build()` call.
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| ------------------------ | -------- | ---------------------------------------------------- |
|
||||
| `TemplateBuilder<T>` | class | The builder itself; instance methods are chainable. |
|
||||
| `createTemplateBuilder` | function | `<T>() => TemplateBuilder<T>` factory. |
|
||||
| `TemplateBuilderApi<T>` | type | The interface implemented by `TemplateBuilder<T>`. |
|
||||
| `EmailComponentFn<T>` | type | `(props: T & { theme?; clock? }) => VNode`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The builder never throws inside a setter — invariants are checked
|
||||
exclusively in `build()`. Empty-string `name` is treated as missing
|
||||
(consistent with upstream behaviour). The `defaultProps` field is
|
||||
optional; omitting it leaves it `undefined` on the produced template.
|
||||
|
||||
Because `build()` returns a fresh object every time, callers can mutate
|
||||
the builder and reuse it for closely-related templates — useful for
|
||||
i18n where the body component is identical and only the subject text
|
||||
changes by locale.
|
||||
Reference in New Issue
Block a user