@comet/agent-features 9.0.0-canary-20260707121405 → 9.0.0
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
CHANGED
|
@@ -294,7 +294,7 @@ All components are imported from `@comet/mail-react` — never from `@faire/mjml
|
|
|
294
294
|
|
|
295
295
|
## Blocks
|
|
296
296
|
|
|
297
|
-
`@comet/mail-react` ships components that render Comet CMS block data — currently
|
|
297
|
+
`@comet/mail-react` ships components that render Comet CMS block data — currently pixel-image and rich-text blocks. Reach for these instead of hand-rolled markup whenever the source is a CMS block-data record.
|
|
298
298
|
|
|
299
299
|
### Pixel-image blocks
|
|
300
300
|
|
|
@@ -342,6 +342,94 @@ Without `aspectRatio`, the rendered ratio comes from the DAM crop area. Pass `as
|
|
|
342
342
|
|
|
343
343
|
When `data.damFile?.image` is absent, both blocks render nothing — no element, no error. Render a placeholder at the call site if you need one.
|
|
344
344
|
|
|
345
|
+
### Rich-text blocks
|
|
346
|
+
|
|
347
|
+
`createRichTextBlock` renders CMS RichText block data (draft-js raw content). **Call the factory once per configuration — at the top level of a file, never inside a component** — and export the returned pair; one configuration drives both rendering contexts.
|
|
348
|
+
|
|
349
|
+
```tsx title="src/emails/blocks/richText.ts"
|
|
350
|
+
export const { MjmlRichTextBlock, HtmlRichTextBlock } = createRichTextBlock({
|
|
351
|
+
blockTypes: {
|
|
352
|
+
"header-one": { variant: "heading1" },
|
|
353
|
+
"header-two": { variant: "heading2" },
|
|
354
|
+
"paragraph-standard": { variant: "body" },
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
| Component | Renders each draft block as | Use within |
|
|
360
|
+
| ------------------- | --------------------------- | ---------------------------------------------- |
|
|
361
|
+
| `MjmlRichTextBlock` | `MjmlText` | an `MjmlColumn` (standard MJML layout) |
|
|
362
|
+
| `HtmlRichTextBlock` | `HtmlText` (`<div>`) | raw HTML or MJML ending tags such as `MjmlRaw` |
|
|
363
|
+
|
|
364
|
+
Usage sites pass only `data`:
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
<MjmlSection indent>
|
|
368
|
+
<MjmlColumn>
|
|
369
|
+
<MjmlRichTextBlock data={richTextData} />
|
|
370
|
+
</MjmlColumn>
|
|
371
|
+
</MjmlSection>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Key behaviors:
|
|
375
|
+
|
|
376
|
+
- **Works without variants.** `createRichTextBlock()` with no options renders every draft block with the base `theme.text` styles — map block types to variants later as the theme grows. Unmapped block types also fall back to base styles.
|
|
377
|
+
- **`blockTypes` values are text-component props**: a theme `variant`, plain (non-responsive) style values (`color`, `fontSize`, `fontWeight`, …), and a `className`. For responsive styling without a variant, set a `className` and register CSS via `registerStyles`:
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
const { MjmlRichTextBlock } = createRichTextBlock({
|
|
381
|
+
blockTypes: { "header-one": { className: "richTextHeadlineOne" } },
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
registerStyles(
|
|
385
|
+
(theme) => css`
|
|
386
|
+
${theme.breakpoints.default.belowMediaQuery} {
|
|
387
|
+
.richTextHeadlineOne > div {
|
|
388
|
+
font-size: 24px !important;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
`,
|
|
392
|
+
);
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- **Multiple configurations per app.** Each factory call is independent — rename the destructured components per use case:
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
export const { MjmlRichTextBlock: MjmlHeadlineRichTextBlock, HtmlRichTextBlock: HtmlHeadlineRichTextBlock } = createRichTextBlock({
|
|
399
|
+
blockTypes: { "header-one": { variant: "heading1" }, "header-two": { variant: "heading2" } },
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
- **Links**: the `external` link type is built in — `LINK` entities with an `external` link block render as `HtmlInlineLink`. Add the application's other link types via `linkTypes`, a resolver per link block type that receives the link block's props and returns the `href` (or `undefined` for no link). Annotate the resolver parameter with the app's generated block-data type so the props are typed without redeclaring their shape. Unconfigured link types render as plain text:
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
import type { PhoneLinkBlockData } from "@src/blocks.generated";
|
|
407
|
+
|
|
408
|
+
const { MjmlRichTextBlock, HtmlRichTextBlock } = createRichTextBlock({
|
|
409
|
+
linkTypes: {
|
|
410
|
+
phone: (props: PhoneLinkBlockData) => (props.phone ? `tel:${props.phone}` : undefined),
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
- **Inline styles**: built-in styles (`BOLD`, `ITALIC`, `SUB`, `SUP`, `STRIKETHROUGH`) render out of the box. The `inline` option maps a draft-js inline style name to a renderer and merges over the built-ins — override one, or render a custom style the app adds to its RTE (`customInlineStyles` on `IRteOptions`). The RTE stores only the style name, so the email defines the appearance. Register under the exact style name, use an inline element known to render across email clients (`<span>`, `<strong>`, `<em>` — not `<mark>`), and set explicit styles (email clients apply little of their own):
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
const { MjmlRichTextBlock, HtmlRichTextBlock } = createRichTextBlock({
|
|
419
|
+
inline: {
|
|
420
|
+
HIGHLIGHT: (children, { key }) => (
|
|
421
|
+
<span key={key} style={{ backgroundColor: "#ff0000", color: "#ffffff" }}>
|
|
422
|
+
{children}
|
|
423
|
+
</span>
|
|
424
|
+
),
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
- **Lists** render flat (`<ul>` / `<ol>` inside one text component per list); nesting by draft depth isn't supported.
|
|
430
|
+
- Spacing between blocks comes from the theme's `bottomSpacing` (the last block gets none); headings are styled text, not semantic `<h1>` elements.
|
|
431
|
+
- Rendered elements carry `richTextBlock__text`, `richTextBlock__list`, `richTextBlock__listItem`, and `richTextBlock__link` class names for targeting with `registerStyles`.
|
|
432
|
+
|
|
345
433
|
---
|
|
346
434
|
|
|
347
435
|
## Custom Components
|