@comet/agent-features 9.0.0-beta.5 → 9.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rules/coding-guidelines/general.instructions.md +1 -1
- package/skills/comet-admin-ui/SKILL.md +159 -0
- package/skills/comet-block/SKILL.md +11 -5
- package/skills/comet-block/references/site-patterns.md +1 -1
- package/skills/comet-mail-react/SKILL.md +15 -23
- package/skills/comet-mail-react/references/components-and-theme.md +55 -65
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ alwaysApply: false
|
|
|
16
16
|
- Prefer descriptive identifiers over explanatory comments — comments drift out of sync with the code.
|
|
17
17
|
- Boolean variables must read as booleans: prefix with `is` / `has` / `should` (exceptions: well-known flags like `loading`, `disabled`).
|
|
18
18
|
- Name booleans in the **affirmative**: `isComplete`, not `isNotComplete`. Negate at the use site with `!`.
|
|
19
|
-
-
|
|
19
|
+
- Avoid non-obvious abbreviations. Exceptions: obvious, conventional abbreviations whose meaning is unambiguous in context (e.g. `i` for an index, `id`, `ref`, `props`), widely-known protocols/acronyms (HTML, CSS, TCP, API, SSO…), and names dictated by third parties. When in doubt, spell it out.
|
|
20
20
|
- When an acronym appears in PascalCase / camelCase, treat it like a word: `GuiController`, `UiElement` — not `GUIController` / `UIElement`.
|
|
21
21
|
|
|
22
22
|
## Control flow
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: comet-admin-ui
|
|
3
|
+
description: Building or editing admin UI in a project that uses @comet/admin and its sibling packages — pages, dashboards, dialogs, widgets, layouts, or component styling. Use even for small UI changes, to build with Comet's theme, components, and helpers instead of custom sx/styled CSS, hard-coded values, or Box layouts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Building admin UIs with @comet/admin
|
|
7
|
+
|
|
8
|
+
`@comet/admin` and its sibling packages ship a design system: a theme (spacing,
|
|
9
|
+
colors, shadows, typography, breakpoints) and a library of ready-made components. For
|
|
10
|
+
internationalization, the project uses `react-intl` to translate text, numbers, and dates. The
|
|
11
|
+
components and types are available in the consuming project through the installed packages —
|
|
12
|
+
import them directly (e.g. `import { Button, MainContent } from "@comet/admin"`).
|
|
13
|
+
|
|
14
|
+
Build admin UI by composing what the design system already provides. Add custom styling only
|
|
15
|
+
after the system genuinely can't express what you need.
|
|
16
|
+
|
|
17
|
+
## Core principle
|
|
18
|
+
|
|
19
|
+
**Prefer Comet's theme values, components, and helpers over custom styling.** Three reasons:
|
|
20
|
+
|
|
21
|
+
1. **Reviewability.** When styling lives in the theme and in components, the markup stays
|
|
22
|
+
declarative and diffs stay small. A component that mixes `sx`, inline `style`, and `styled()`
|
|
23
|
+
is hard to read and hard to review — the layout, the styling, and the logic blur together.
|
|
24
|
+
2. **Automatic upgrades.** A project's visual design is often built against a _future_ version of
|
|
25
|
+
the design system, so it won't fully match what the currently installed components and theme
|
|
26
|
+
produce. That gap is expected — it is not a reason to add custom styling to force the match.
|
|
27
|
+
Use the current Comet components and tokens as they are; a later library upgrade closes the gap
|
|
28
|
+
on its own, with no hand-written CSS to find and rework.
|
|
29
|
+
3. **Consistency.** Every screen built from the same components and tokens looks and behaves the
|
|
30
|
+
same way.
|
|
31
|
+
|
|
32
|
+
This holds **even when a project's design deliberately differs** from the current library
|
|
33
|
+
defaults: prefer the Comet component or token, and apply that project-specific difference by
|
|
34
|
+
configuring the theme — not by re-styling individual components. Add custom styling only when
|
|
35
|
+
explicitly instructed, or when no component, prop, or token can produce the result.
|
|
36
|
+
|
|
37
|
+
## Decision framework
|
|
38
|
+
|
|
39
|
+
Before writing any styling or markup, work down this list and stop at the first step that applies:
|
|
40
|
+
|
|
41
|
+
1. **Is there a component for this?** Use it rather than assembling the same thing from
|
|
42
|
+
`Box` + CSS (page structure, cards, toolbars, dialogs, alerts, buttons, …).
|
|
43
|
+
2. **Is there a prop for this?** Props apply the correct theme values with no CSS — e.g.
|
|
44
|
+
`elevation` / `square` on `Paper` and `Card`, `variant` on `Button` and `Typography`,
|
|
45
|
+
`spacing` on `Stack` and `Grid`.
|
|
46
|
+
3. **Is there a theme value for this?** Read spacing, colors, and shadows from the theme
|
|
47
|
+
(`theme.spacing(n)`, `theme.palette.*`, `theme.shadows[n]`) instead of hard-coding pixels,
|
|
48
|
+
hex colors, or shadow strings.
|
|
49
|
+
4. **Is there a helper for this?** User-facing text, numbers, and dates go through the i18n
|
|
50
|
+
helpers (`FormattedMessage`, `FormattedNumber`, `FormattedDate`), never hard-coded.
|
|
51
|
+
5. **Only then, custom-style** — using `styled()` (not `sx` or inline `style`) and reading
|
|
52
|
+
values from the theme.
|
|
53
|
+
|
|
54
|
+
## Styling and theme
|
|
55
|
+
|
|
56
|
+
### Custom styling: `styled()`, not `sx` or inline `style`
|
|
57
|
+
|
|
58
|
+
When you do need custom styling, write it with `styled()` from `@mui/material/styles` and give the
|
|
59
|
+
result a name that says what it is. Styling in `sx` props or inline `style` mixes the look into the
|
|
60
|
+
markup, so layout, styling, and logic blur together and the diff is harder to follow. A named
|
|
61
|
+
styled component keeps the markup declarative and the styling in one place.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
// Avoid — sx and inline style mixed into the markup
|
|
65
|
+
<Box sx={{ padding: 2, backgroundColor: "#fff", borderRadius: 1 }} style={{ marginTop: 16 }}>
|
|
66
|
+
{children}
|
|
67
|
+
</Box>;
|
|
68
|
+
|
|
69
|
+
// Prefer — a named styled component, styling separated from markup
|
|
70
|
+
const Panel = styled("div")`
|
|
71
|
+
padding: ${({ theme }) => theme.spacing(2)};
|
|
72
|
+
background-color: ${({ theme }) => theme.palette.background.paper};
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
<Panel>{children}</Panel>;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Spacing and color: theme tokens, not hard-coded values
|
|
79
|
+
|
|
80
|
+
Read spacing and color from the theme instead of typing pixels and hex codes. The theme is the
|
|
81
|
+
single place those values are defined, so reading from it keeps every screen consistent and lets a
|
|
82
|
+
theme change reach all of them at once. Comet's spacing base is `5px` — `theme.spacing(1)` is `5px`,
|
|
83
|
+
`theme.spacing(2)` is `10px` — and it takes up to four arguments for top, right, bottom, and left.
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
// Avoid — hard-coded pixels and colors
|
|
87
|
+
const Header = styled("header")`
|
|
88
|
+
padding: 16px 24px;
|
|
89
|
+
color: #1a1a1a;
|
|
90
|
+
border-bottom: 1px solid #e0e0e0;
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
// Prefer — spacing and palette tokens from the theme
|
|
94
|
+
const Header = styled("header")`
|
|
95
|
+
padding: ${({ theme }) => theme.spacing(2, 3)};
|
|
96
|
+
color: ${({ theme }) => theme.palette.text.primary};
|
|
97
|
+
border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
|
|
98
|
+
`;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use the palette tokens — `primary`, `secondary`, `error`, `warning`, `info`, `success`,
|
|
102
|
+
`grey[50…900]`, `divider`, `text`, `background`, `action` — rather than naming raw colors.
|
|
103
|
+
|
|
104
|
+
### Elevation and shape: `elevation` and `square`, not manual CSS
|
|
105
|
+
|
|
106
|
+
Shadows and corner radius come from props on `Paper` and `Card`, not hand-written CSS. Comet defines
|
|
107
|
+
four shadow elevations (1–4); higher values are `none`. The `elevation` prop selects one, and the
|
|
108
|
+
`square` prop toggles the rounded corner. Read `theme.shadows[n]` directly only inside a `styled()`
|
|
109
|
+
component that cannot be a `Paper` or `Card`.
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
// Avoid — manual shadow and radius on a plain element
|
|
113
|
+
<div style={{ boxShadow: "0 0 8px rgba(0,0,0,0.1)", borderRadius: 4 }}>{children}</div>
|
|
114
|
+
|
|
115
|
+
// Prefer — a Paper carrying the theme's elevation and shape
|
|
116
|
+
<Paper elevation={2}>{children}</Paper>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Typography: `<Typography variant>`, not manual font CSS
|
|
120
|
+
|
|
121
|
+
Render text through `<Typography>` with a variant rather than setting font size, weight, and line
|
|
122
|
+
height by hand. The variant carries the type scale and its responsive steps, so headings and body
|
|
123
|
+
text stay in proportion across breakpoints. Available variants: `h1`–`h6`, `body1`, `body2`,
|
|
124
|
+
`subtitle1`, `subtitle2`, `caption`, `overline`, `list`, `listItem`, `button`.
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
// Avoid — font properties set by hand
|
|
128
|
+
const Title = styled("h2")`
|
|
129
|
+
font-size: 20px;
|
|
130
|
+
font-weight: 600;
|
|
131
|
+
line-height: 26px;
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
// Prefer — a Typography variant from the type scale
|
|
135
|
+
<Typography variant="h4">{title}</Typography>;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Organizing styled components
|
|
139
|
+
|
|
140
|
+
By default, define a component's styled parts at the bottom of its own file, below the component
|
|
141
|
+
that uses them:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
imports → types → component → styled components
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
When a file grows hard to read, refactor the component itself first — split it into smaller
|
|
148
|
+
components and compose them, each keeping its own styled parts at the bottom. Move styles to a
|
|
149
|
+
separate `*.sc.ts` sibling only when you are asked to, or when the styles grow but the component
|
|
150
|
+
cannot be split logically. A `*.sc.ts` file is private to its equally-named component
|
|
151
|
+
(`FooButton.sc.ts` belongs to `FooButton.tsx`). Don't import one component's `*.sc.ts` from another:
|
|
152
|
+
that couples them through styling neither owns. When styling is shared, give it a single owner — a
|
|
153
|
+
reusable component (below).
|
|
154
|
+
|
|
155
|
+
When the same styled component is used by several components, it is no longer a styled part of any
|
|
156
|
+
one of them. Promote it to its own reusable component: one export per file, named exactly as that
|
|
157
|
+
export so it is easy to find, e.g. `SpecialButton.ts` exporting
|
|
158
|
+
`export const SpecialButton = styled(Button)`. Group several small related ones into a single
|
|
159
|
+
generically-named file only when explicitly instructed.
|
|
@@ -71,11 +71,17 @@ For block type decision guidance, see [block-types.md](references/block-types.md
|
|
|
71
71
|
|
|
72
72
|
Before generating any code:
|
|
73
73
|
|
|
74
|
-
1. **Locate `api
|
|
75
|
-
2. **
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
1. **Locate the `api` and `admin` directories.**
|
|
75
|
+
2. **Locate the site package or packages by their dependencies, not the folder name.** `site` is only the conventional name — a project may name the package differently or have several. A `package.json` (outside `node_modules`) that depends on `@comet/site-nextjs` or `@comet/site-react` is certainly a site package, since site blocks render through these (`withPreview`, `PropsWithData`):
|
|
76
|
+
```bash
|
|
77
|
+
grep -rl --include='package.json' --exclude-dir=node_modules -E '"@comet/site-(nextjs|react)"' . | xargs -n1 dirname
|
|
78
|
+
```
|
|
79
|
+
A frontend package can also exist without those dependencies — for example one that renders blocks for email with `@comet/mail-react`. Skip the site steps only if you find neither a site package nor another frontend package.
|
|
80
|
+
3. **Find existing blocks directories** — typically `src/documents/pages/blocks/`. Some shared blocks live in `common/blocks/` or similar. Check both.
|
|
81
|
+
4. **Verify referenced blocks exist** — search for any blocks named in the prompt (e.g., `HeadingBlock`, `LinkBlock`) in all layers and note their import paths.
|
|
82
|
+
5. **Find registration targets** — search for `createBlocksBlock` usages to locate `PageContentBlock`, `ContentGroupBlock`, or other targets. Note file paths in all layers.
|
|
83
|
+
|
|
84
|
+
In the later steps and the reference files, example paths written as `site/…` mean the site package's root and `@src/…` means its `src/` directory. They show the conventional layout — substitute the actual package folder found here.
|
|
79
85
|
|
|
80
86
|
---
|
|
81
87
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Comet-specific conventions for the site layer. All site blocks live in `{BlockName}Block.tsx` (PascalCase) under `site/src/`, typically `documents/pages/blocks/` or `common/blocks/`.
|
|
4
4
|
|
|
5
|
-
Skip site block creation when the project has no
|
|
5
|
+
Skip site block creation when the project has no site package (see [Step 2](../SKILL.md#step-2--discover-the-project) for how to detect one).
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -171,10 +171,10 @@ function MyEmail() {
|
|
|
171
171
|
|
|
172
172
|
### Contributing to `<MjmlHead>` and `<MjmlAttributes>`
|
|
173
173
|
|
|
174
|
-
`MjmlMailRoot` accepts
|
|
174
|
+
`MjmlMailRoot` accepts `head` and `attributes` slot props for content that can't be expressed via `registerStyles`:
|
|
175
175
|
|
|
176
|
-
- `head` —
|
|
177
|
-
- `attributes` —
|
|
176
|
+
- `head` — use for `<MjmlFont>`, `<MjmlConditionalComment>`, `<MjmlPreview>`, or `<MjmlStyle>` content that depends on React context at render time.
|
|
177
|
+
- `attributes` — use for `<MjmlClass>` or per-element defaults (e.g. `<MjmlText fontSize="14px" />`).
|
|
178
178
|
|
|
179
179
|
Pass the children directly — do not wrap them in another `<MjmlHead>` / `<MjmlAttributes>`:
|
|
180
180
|
|
|
@@ -227,20 +227,13 @@ declare module "@comet/mail-react" {
|
|
|
227
227
|
|
|
228
228
|
Place `declare module` blocks in your theme file below the `createTheme()` call.
|
|
229
229
|
|
|
230
|
-
→ For the full theme structure,
|
|
230
|
+
→ For the full theme structure, responsive values, module augmentation, and scoped theming, read [`references/components-and-theme.md`](references/components-and-theme.md).
|
|
231
231
|
|
|
232
232
|
---
|
|
233
233
|
|
|
234
234
|
## Configuration
|
|
235
235
|
|
|
236
|
-
`Config`
|
|
237
|
-
|
|
238
|
-
- **`Config`** — augmentable interface, no built-in keys. All keys optional.
|
|
239
|
-
- **`MjmlMailRoot.config`** — optional prop that exposes a `Config` value to descendants.
|
|
240
|
-
- **`useConfig`** — hook returning the nearest `Config`, or `{}` if no provider is mounted.
|
|
241
|
-
- **`ConfigProvider`** — standalone provider for cases that bypass `MjmlMailRoot`.
|
|
242
|
-
|
|
243
|
-
Add keys via module augmentation:
|
|
236
|
+
`Config` exposes environment-specific values — e.g. asset base URLs — to every component in the tree. Add keys via module augmentation:
|
|
244
237
|
|
|
245
238
|
```ts
|
|
246
239
|
declare module "@comet/mail-react" {
|
|
@@ -270,12 +263,12 @@ const config: Config = { assetBaseUrl: process.env.ASSET_BASE_URL };
|
|
|
270
263
|
| --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------- |
|
|
271
264
|
| `MjmlMailRoot` | Root element, provides theme, renders `<mjml>` skeleton | — |
|
|
272
265
|
| `MjmlWrapper` | Groups sections sharing a background; theme-aware default bg | — |
|
|
273
|
-
| `MjmlSection` | Full-width row,
|
|
266
|
+
| `MjmlSection` | Full-width row; theme indentation, columns stack on mobile | `.mjmlSection`, `.mjmlSection--indented` |
|
|
274
267
|
| `MjmlColumn` | Vertical column inside a section | — |
|
|
275
|
-
| `MjmlText` | Themed text block with
|
|
268
|
+
| `MjmlText` | Themed text block with typography variants | `.mjmlText`, `.mjmlText--{variant}`, `.mjmlText--bottomSpacing` |
|
|
276
269
|
| `MjmlImage` | Responsive image | `.mjmlImage` |
|
|
277
270
|
| `MjmlPixelImageBlock` | Renders a Comet CMS `PixelImageBlockData` via `MjmlImage` | `.mjmlPixelImageBlock` |
|
|
278
|
-
| `MjmlButton` |
|
|
271
|
+
| `MjmlButton` | Themed button (ending tag), theme styling and variants | `.mjmlButton`, `.mjmlButton--{variant}` |
|
|
279
272
|
| `MjmlDivider` | Themed horizontal divider, configurable through theme and variants | `.mjmlDivider`, `.mjmlDivider--{variant}` |
|
|
280
273
|
| `MjmlSpacer` | Vertical spacing | — |
|
|
281
274
|
| `MjmlRaw` | Raw HTML escape hatch (ending tag) | — |
|
|
@@ -284,17 +277,18 @@ const config: Config = { assetBaseUrl: process.env.ASSET_BASE_URL };
|
|
|
284
277
|
|
|
285
278
|
| Component | Purpose | CSS Classes |
|
|
286
279
|
| --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------- |
|
|
287
|
-
| `HtmlText` | Themed text as HTML element
|
|
280
|
+
| `HtmlText` | Themed text rendered as an HTML element | `.htmlText`, `.htmlText--{variant}`, `.htmlText--bottomSpacing` |
|
|
288
281
|
| `HtmlInlineLink` | `<a>` that inherits parent text styles, works in Outlook | `.htmlInlineLink` |
|
|
289
282
|
| `HtmlImage` | Responsive image (`<img>`) | `.htmlImage` |
|
|
290
283
|
| `HtmlPixelImageBlock` | Renders a Comet CMS `PixelImageBlockData` as `<img>` | `.htmlPixelImageBlock` |
|
|
284
|
+
| `HtmlButton` | Themed button for ending tags or non-MJML contexts | `.htmlButton`, `.htmlButton--{variant}` |
|
|
291
285
|
| `HtmlDivider` | Themed horizontal divider, configurable through theme and variants | `.htmlDivider`, `.htmlDivider--{variant}` |
|
|
292
286
|
|
|
293
|
-
|
|
287
|
+
Variants are named typography presets (font size, weight, line height, color) defined in the theme; their values can change per breakpoint.
|
|
294
288
|
|
|
295
289
|
All components are imported from `@comet/mail-react` — never from `@faire/mjml-react` directly.
|
|
296
290
|
|
|
297
|
-
→ For
|
|
291
|
+
→ For theme tokens, responsive values, component behavior, scoped theming, and MJML re-exports, read [`references/components-and-theme.md`](references/components-and-theme.md).
|
|
298
292
|
|
|
299
293
|
---
|
|
300
294
|
|
|
@@ -319,7 +313,7 @@ All components are imported from `@comet/mail-react` — never from `@faire/mjml
|
|
|
319
313
|
|
|
320
314
|
#### Configuration
|
|
321
315
|
|
|
322
|
-
Both blocks
|
|
316
|
+
Both blocks require `config.pixelImageBlock` and throw without it. Wire it once on `MjmlMailRoot.config`:
|
|
323
317
|
|
|
324
318
|
```tsx
|
|
325
319
|
const config: Config = {
|
|
@@ -332,9 +326,7 @@ const config: Config = {
|
|
|
332
326
|
|
|
333
327
|
#### Render width
|
|
334
328
|
|
|
335
|
-
The
|
|
336
|
-
|
|
337
|
-
Use `largestPossibleRenderWidth` when the image stretches wider on a narrower breakpoint than its desktop width — e.g. a two-column layout that stacks on mobile. Defaults to `theme.sizes.bodyWidth`.
|
|
329
|
+
The block picks the source size from the configured `validSizes`, accounting for retina displays. Use `largestPossibleRenderWidth` when the image stretches wider on a narrower breakpoint than its desktop width — e.g. a two-column layout that stacks on mobile.
|
|
338
330
|
|
|
339
331
|
```tsx
|
|
340
332
|
<MjmlPixelImageBlock data={pixelImageData} width={300} largestPossibleRenderWidth={420} />
|
|
@@ -342,7 +334,7 @@ Use `largestPossibleRenderWidth` when the image stretches wider on a narrower br
|
|
|
342
334
|
|
|
343
335
|
#### Aspect ratio
|
|
344
336
|
|
|
345
|
-
|
|
337
|
+
Without `aspectRatio`, the rendered ratio comes from the DAM crop area. Pass `aspectRatio` to override it.
|
|
346
338
|
|
|
347
339
|
```tsx
|
|
348
340
|
<MjmlPixelImageBlock data={pixelImageData} width={536} aspectRatio="16x9" />
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Components & Theme Reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Theme system, module augmentation, scoped theming, and the component behavior for `@comet/mail-react` that its types and TSDoc don't capture on their own. For prop names, types, and defaults, read the types and their TSDoc.
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
7
|
-
1. [Theme
|
|
7
|
+
1. [Theme tokens](#theme-tokens)
|
|
8
8
|
2. [Module Augmentation Interfaces](#module-augmentation-interfaces)
|
|
9
9
|
3. [MjmlMailRoot](#mjmlmailroot)
|
|
10
10
|
4. [MjmlSection](#mjmlsection)
|
|
@@ -13,29 +13,15 @@ Detailed reference for all `@comet/mail-react` components, the theme system, mod
|
|
|
13
13
|
7. [HtmlInlineLink](#htmlinlinelink)
|
|
14
14
|
8. [Image](#image)
|
|
15
15
|
9. [Divider](#divider)
|
|
16
|
-
10. [
|
|
17
|
-
11. [
|
|
16
|
+
10. [Button](#button)
|
|
17
|
+
11. [Scoped Theming](#scoped-theming)
|
|
18
|
+
12. [MJML Component Re-exports](#mjml-component-re-exports)
|
|
18
19
|
|
|
19
20
|
---
|
|
20
21
|
|
|
21
|
-
## Theme
|
|
22
|
-
|
|
23
|
-
`createTheme(overrides?)` merges partial overrides into the default theme:
|
|
24
|
-
|
|
25
|
-
| Path | Default | Description |
|
|
26
|
-
| --------------------------- | ----------------------------- | ----------------------------------------------------------- |
|
|
27
|
-
| `sizes.bodyWidth` | `600` | Email container width in pixels |
|
|
28
|
-
| `sizes.contentIndentation` | `{ default: 32, mobile: 16 }` | Left/right padding when `indent` is used |
|
|
29
|
-
| `breakpoints.default` | `createBreakpoint(bodyWidth)` | Auto-set to body width unless explicitly overridden |
|
|
30
|
-
| `breakpoints.mobile` | `createBreakpoint(420)` | Mobile breakpoint (`max-width: 419px`) |
|
|
31
|
-
| `text.fontFamily` | System default | Base font family |
|
|
32
|
-
| `text.fontSize` | `"16px"` | Base font size |
|
|
33
|
-
| `text.lineHeight` | `"20px"` | Base line height |
|
|
34
|
-
| `text.bottomSpacing` | `"16px"` | Default spacing below text when `bottomSpacing` prop is set |
|
|
35
|
-
| `text.defaultVariant` | `undefined` | Variant applied when no `variant` prop is specified |
|
|
36
|
-
| `text.variants` | `{}` | Named typography presets |
|
|
37
|
-
| `colors.background.body` | `"#F2F2F2"` | Email body background |
|
|
38
|
-
| `colors.background.content` | `"#FFFFFF"` | Section content background |
|
|
22
|
+
## Theme tokens
|
|
23
|
+
|
|
24
|
+
`createTheme(overrides?)` merges partial overrides into the default theme; every token is optional and the `Theme` type lists them. Defaults live in `createTheme`. One behavior isn't visible from the types: **the default breakpoint derives from `sizes.bodyWidth`** unless `breakpoints.default` is overridden — they describe the same boundary, so setting them apart silently desyncs the layout.
|
|
39
25
|
|
|
40
26
|
### Breakpoints
|
|
41
27
|
|
|
@@ -129,6 +115,34 @@ declare module "@comet/mail-react" {
|
|
|
129
115
|
|
|
130
116
|
Variant properties (`height`, `backgroundColor`, `backgroundImage`) accept responsive values.
|
|
131
117
|
|
|
118
|
+
### ButtonVariants
|
|
119
|
+
|
|
120
|
+
Controls the `variant` prop on `MjmlButton` and `HtmlButton`:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const theme = createTheme({
|
|
124
|
+
button: {
|
|
125
|
+
defaultVariant: "primary",
|
|
126
|
+
variants: {
|
|
127
|
+
primary: { backgroundColor: "#5B4FC7", color: "#FFFFFF" },
|
|
128
|
+
gradient: {
|
|
129
|
+
backgroundColor: "#5B4FC7",
|
|
130
|
+
backgroundImage: "linear-gradient(90deg, #5B4FC7, #9C5BC7)",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
declare module "@comet/mail-react" {
|
|
137
|
+
interface ButtonVariants {
|
|
138
|
+
primary: true;
|
|
139
|
+
gradient: true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Variant properties (`color`, `backgroundColor`, `backgroundImage`, `border`, `borderRadius`, `fontFamily`, `fontSize`, `fontWeight`, `lineHeight`, `padding`) accept responsive values.
|
|
145
|
+
|
|
132
146
|
### ThemeBreakpoints
|
|
133
147
|
|
|
134
148
|
Built-in keys are `default` and `mobile`. Add custom breakpoints:
|
|
@@ -181,14 +195,6 @@ declare module "@comet/mail-react" {
|
|
|
181
195
|
|
|
182
196
|
Root element for every email template. Renders the full MJML skeleton (`<mjml>`, `<mj-head>`, `<mj-body>`) and provides the theme to all descendant components.
|
|
183
197
|
|
|
184
|
-
**Props:**
|
|
185
|
-
|
|
186
|
-
| Prop | Type | Default | Description |
|
|
187
|
-
| ---------- | ----------- | --------------- | --------------------------------------------------------- |
|
|
188
|
-
| `theme` | `Theme` | `createTheme()` | Theme for the email |
|
|
189
|
-
| `config` | `Config` | — | Augmentable values exposed to descendants via `useConfig` |
|
|
190
|
-
| `children` | `ReactNode` | — | Email content |
|
|
191
|
-
|
|
192
198
|
**What it configures from the theme:**
|
|
193
199
|
|
|
194
200
|
- Body width from `theme.sizes.bodyWidth`
|
|
@@ -206,15 +212,6 @@ Root element for every email template. Renders the full MJML skeleton (`<mjml>`,
|
|
|
206
212
|
|
|
207
213
|
Full-width horizontal row with theme integration.
|
|
208
214
|
|
|
209
|
-
**Props** (in addition to standard MJML section props):
|
|
210
|
-
|
|
211
|
-
| Prop | Type | Default | Description |
|
|
212
|
-
| --------------------------- | ------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------- |
|
|
213
|
-
| `indent` | `boolean` | `false` | Applies theme-based left/right padding |
|
|
214
|
-
| `disableResponsiveBehavior` | `boolean` | `false` | Prevents columns from stacking on mobile |
|
|
215
|
-
| `slotProps` | `{ group?: Partial<MjmlGroupProps> }` | — | Forward props to internal `MjmlGroup` (when `disableResponsiveBehavior` is set) |
|
|
216
|
-
| `backgroundColor` | `string` | `theme.colors.background.content` | Override section background color |
|
|
217
|
-
|
|
218
215
|
**CSS classes:** `.mjmlSection`, `.mjmlSection--indented` (when `indent` is set).
|
|
219
216
|
|
|
220
217
|
```tsx
|
|
@@ -238,14 +235,7 @@ Indentation values come from `theme.sizes.contentIndentation`, which supports re
|
|
|
238
235
|
|
|
239
236
|
Groups multiple `MjmlSection`s that share a background. Must be a direct child of `MjmlBody`; sections go inside.
|
|
240
237
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
| Prop | Type | Default | Description |
|
|
244
|
-
| ----------------- | ----------- | --------------------------------- | --------------------------------------------------------------------- |
|
|
245
|
-
| `backgroundColor` | `string` | `theme.colors.background.content` | Background applied to the whole wrapper; shows through inner sections |
|
|
246
|
-
| `children` | `ReactNode` | — | Sections to group |
|
|
247
|
-
|
|
248
|
-
When a theme is present, `MjmlWrapper` applies `theme.colors.background.content` as its default `backgroundColor`. Inner `MjmlSection`s suppress their own theme-default background so the wrapper's color is visible; an explicit `backgroundColor` prop on an inner section still wins.
|
|
238
|
+
The wrapper takes the theme's content background by default. Inner `MjmlSection`s suppress their own theme-default background so the wrapper's color shows through; an explicit `backgroundColor` on an inner section still wins.
|
|
249
239
|
|
|
250
240
|
```tsx
|
|
251
241
|
<MjmlWrapper backgroundColor="#dddddd">
|
|
@@ -272,13 +262,6 @@ Typical uses: multi-section footers with their own color, or grouping sections b
|
|
|
272
262
|
|
|
273
263
|
MJML text component — use inside `MjmlColumn` following the standard layout model.
|
|
274
264
|
|
|
275
|
-
**Props** (in addition to standard MJML text props):
|
|
276
|
-
|
|
277
|
-
| Prop | Type | Description |
|
|
278
|
-
| --------------- | -------------------- | ----------------------------------------- |
|
|
279
|
-
| `variant` | `keyof TextVariants` | Named typography preset from theme |
|
|
280
|
-
| `bottomSpacing` | `boolean` | Add spacing below (from theme or variant) |
|
|
281
|
-
|
|
282
265
|
**CSS classes:** `.mjmlText`, `.mjmlText--{variant}`, `.mjmlText--bottomSpacing`.
|
|
283
266
|
|
|
284
267
|
```tsx
|
|
@@ -293,14 +276,6 @@ Variant styles merge on top of base theme text styles — properties not set by
|
|
|
293
276
|
|
|
294
277
|
Themed text for use inside ending tags (`MjmlText`, `MjmlRaw`) or custom HTML structures where MJML components can't be used. Renders a plain HTML element.
|
|
295
278
|
|
|
296
|
-
**Props:**
|
|
297
|
-
|
|
298
|
-
| Prop | Type | Default | Description |
|
|
299
|
-
| --------------- | -------------------- | ------- | ---------------------- |
|
|
300
|
-
| `variant` | `keyof TextVariants` | — | Typography preset |
|
|
301
|
-
| `bottomSpacing` | `boolean` | `false` | Add spacing below |
|
|
302
|
-
| `element` | `string` | `"td"` | HTML element to render |
|
|
303
|
-
|
|
304
279
|
**CSS classes:** `.htmlText`, `.htmlText--{variant}`, `.htmlText--bottomSpacing`.
|
|
305
280
|
|
|
306
281
|
```tsx
|
|
@@ -335,8 +310,6 @@ The base spacing value comes from `theme.text.bottomSpacing`. Variants can overr
|
|
|
335
310
|
|
|
336
311
|
`<a>` element for use inside `MjmlText` or `HtmlText`. Inherits parent's font styles — even on Outlook Desktop, which normally overrides link typography with its own defaults.
|
|
337
312
|
|
|
338
|
-
**Props:** Standard `<a>` props. Defaults to `target="_blank"` and `text-decoration: underline`.
|
|
339
|
-
|
|
340
313
|
**CSS class:** `.htmlInlineLink`.
|
|
341
314
|
|
|
342
315
|
```tsx
|
|
@@ -380,6 +353,23 @@ Themed horizontal line, styled from `theme.divider` (base styles plus variants).
|
|
|
380
353
|
|
|
381
354
|
---
|
|
382
355
|
|
|
356
|
+
## Button
|
|
357
|
+
|
|
358
|
+
Themed button, styled from `theme.button` (base styles plus variants). Falls back to a built-in default when no theme is in scope; only `variant` requires a theme.
|
|
359
|
+
|
|
360
|
+
- **`MjmlButton`** — inside `MjmlColumn`. Classes `.mjmlButton`, `.mjmlButton--{variant}`, `.mjmlButton--fullWidth`.
|
|
361
|
+
- **`HtmlButton`** — inside ending tags (`MjmlRaw`) or any non-MJML context. Classes `.htmlButton`, `.htmlButton--{variant}`, `.htmlButton--fullWidth`.
|
|
362
|
+
|
|
363
|
+
`theme.button.padding` is the inner spacing around the label; `MjmlButton`'s `padding` prop is the outer spacing. `fullWidth` makes the button span its container. A gradient `backgroundImage` overlays the solid `backgroundColor`, which stays the fallback for clients that drop `background-image` (Outlook). Outlook ignores `border-radius`, so rounded buttons render with square corners there.
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
<MjmlButton variant="primary" fullWidth href="https://example.com">
|
|
367
|
+
Click me
|
|
368
|
+
</MjmlButton>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
383
373
|
## Scoped Theming
|
|
384
374
|
|
|
385
375
|
`ThemeProvider` applies a different theme to a subtree. Common use: dark-background sections.
|
|
@@ -436,6 +426,6 @@ Theme-aware `registerStyles` entries always resolve against the **root theme** f
|
|
|
436
426
|
|
|
437
427
|
`@comet/mail-react` re-exports all MJML components from `@faire/mjml-react`. Consumers import everything from `@comet/mail-react` — never from `@faire/mjml-react` directly.
|
|
438
428
|
|
|
439
|
-
Common re-exports: `MjmlColumn`, `
|
|
429
|
+
Common re-exports: `MjmlColumn`, `MjmlSpacer`, `MjmlTable`, `MjmlRaw`, `MjmlGroup`, `MjmlAttributes`, `MjmlAll`, `MjmlClass`, `MjmlStyle`, `MjmlComment`, `MjmlConditionalComment`.
|
|
440
430
|
|
|
441
431
|
For the full MJML tag reference: https://documentation.mjml.io/
|