first commit
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# email-button
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`EmailButton` is the canonical call-to-action surface in an email body —
|
||||
a table-wrapped `<a>` with variant-driven theme colours and three preset
|
||||
sizes. The table wrapper is non-optional: Outlook on Windows uses a
|
||||
Word-derived rendering engine that historically ignores `padding` on
|
||||
inline anchors, so the only reliable way to ship a visually-correct CTA
|
||||
into Outlook desktop is a `<table>` containing a centred `<td>` containing
|
||||
the styled `<a>`.
|
||||
|
||||
The component centralises the variant + size recipe so callers don't
|
||||
duplicate it at every CTA site, and validates `variant`/`size` against
|
||||
the published enums at call time — typos turn into a typed
|
||||
`EmailTemplatesError(INVALID_OPTIONS)` instead of a silently-malformed
|
||||
button.
|
||||
|
||||
## Features
|
||||
|
||||
- Three variants — `primary`, `secondary`, `outline` — each pulling
|
||||
colours from the active theme.
|
||||
- Three sizes — `sm`, `md`, `lg` — each driving distinct padding +
|
||||
font-size.
|
||||
- `fullWidth` toggle emits `width: 100%` on both the wrapping `<table>`
|
||||
and the `<a>` so the CTA spans its container.
|
||||
- `align` prop emitted as the table's `align` attribute.
|
||||
- Validation: unknown variant or size raises
|
||||
`EmailTemplatesError(INVALID_OPTIONS)` and bumps an OTel counter
|
||||
tagged `reason="invalid_button_variant"` or `"invalid_button_size"`.
|
||||
- Safe link defaults (`target="_blank"`, `rel="noopener noreferrer"`).
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { EmailButton } from "@suaveplan/email-templates/components";
|
||||
import { renderVNode } from "@suaveplan/email-templates/vnode";
|
||||
|
||||
renderVNode(EmailButton({
|
||||
href: "https://app.example.test/get-started",
|
||||
children: "Get Started",
|
||||
}));
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
A full-width secondary CTA with custom letter-spacing:
|
||||
|
||||
```ts
|
||||
import { EmailButton } from "@suaveplan/email-templates/components";
|
||||
import { renderVNode } from "@suaveplan/email-templates/vnode";
|
||||
|
||||
renderVNode(EmailButton({
|
||||
href: "https://app.example.test/upgrade",
|
||||
children: "Upgrade Now",
|
||||
variant: "secondary",
|
||||
size: "lg",
|
||||
fullWidth: true,
|
||||
style: { "letter-spacing": "0.5px" },
|
||||
}));
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Prop | Type | Description |
|
||||
| ----------- | --------------------------------- | ---------------------------------------------------- |
|
||||
| `href` | `string` | CTA target URL. |
|
||||
| `children` | `string` | Button label (string only — keeps the table cell-tight). |
|
||||
| `theme` | `EmailTheme?` | Theme override. |
|
||||
| `variant` | `"primary" \| "secondary" \| "outline"` | Defaults to `primary`. |
|
||||
| `size` | `"sm" \| "md" \| "lg"` | Defaults to `md`. |
|
||||
| `fullWidth` | `boolean?` | Defaults to `false`. |
|
||||
| `align` | `"left" \| "center" \| "right"` | Outer table align; defaults to `"center"`. |
|
||||
| `style` | `StyleObject?` | Additional anchor-level inline styles. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The variant style returns three keys (`background-color`, `color`,
|
||||
`border`) plus the size returns two (`padding`, `font-size`); a switch
|
||||
on the variant tag emits the right triple. Validation uses a `Set`
|
||||
lookup — branch coverage is satisfied by one true-case test plus one
|
||||
false-case test per validator.
|
||||
|
||||
The `box-sizing: border-box` declaration on the anchor ensures the
|
||||
2 px border doesn't push the button over its intended outside width when
|
||||
`fullWidth: true`. Without that declaration Outlook would render the
|
||||
button slightly wider than its container in the `outline` variant where
|
||||
the border weight matters most.
|
||||
Reference in New Issue
Block a user