@menapo/email 0.0.0-stage → 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 menapo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,32 @@
1
- # Temporary Holding Version
1
+ # @menapo/email
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Transactional mail as HTML and text, from standard HTML and your own styles.
4
+
5
+ ```ts
6
+ import { email, html, render } from "@menapo/email";
7
+
8
+ export const verify = email(({ name, url }: { name: string; url: string }) => ({
9
+ subject: t("Verify your email"),
10
+ preheader: t("One click to confirm your address"),
11
+ body: html`<div class=${card}>
12
+ <p class=${text}>${t("Hi {name},", { name })}</p>
13
+ <a href=${url} class=${cta({ intent: "primary" })}>${t("Verify email")}</a>
14
+ </div>`,
15
+ }));
16
+
17
+ const { subject, html, text } = await render(verify, { name, url }, { locale: "de" });
18
+ ```
19
+
20
+ ```ts
21
+ // vite.config.ts: no options
22
+ import { email } from "@menapo/email/vite";
23
+ export default { plugins: [vicss(), vi18n(), email()] };
24
+ ```
25
+
26
+ - **Your styles, made safe for mail:** vicss tokens and recipes become literal inline styles; buttons, boxes and flex rows become Outlook-safe tables; dark mode and breakpoints go in one `<style>`.
27
+ - **Warnings, not guesses:** what a client would drop warns in dev and tests, naming the clients and the fix.
28
+ - **Per recipient:** `t()` runs in the recipient's locale; `lang` and `dir` follow.
29
+ - **Small and fast:** no framework; one mail renders in about 0.14 ms and ships in about 7 KB gzip, against React Email's 4 ms and 49 KB ([bench](../../bench/README.md#menapoemail)).
30
+ - **Preview and snapshots:** `/__email` in the dev server; `renderSamples()` in tests.
31
+
32
+ Status: built, private until 1.0. [Guide](docs/guide/README.md) · [Plan](docs/PLAN.md).
@@ -0,0 +1,82 @@
1
+ //#region ../markup/src/index.d.ts
2
+ /** A style object of literal CSS values; numbers are px where CSS takes a length. */
3
+ type Style = {
4
+ readonly [property: string]: string | number | undefined;
5
+ };
6
+ /** What `class` takes: what vicss produces (a `css()` style, a recipe's result), class names, or a list of them. */
7
+ type ClassValue = string | {
8
+ readonly [id: string]: string;
9
+ } | {
10
+ readonly $c: {
11
+ readonly [id: string]: string;
12
+ };
13
+ readonly $s?: {
14
+ readonly [name: string]: string;
15
+ };
16
+ } | false | null | undefined | 0 | readonly ClassValue[];
17
+ type Props = {
18
+ readonly [name: string]: unknown;
19
+ };
20
+ /** An element. `class` is merged to one string and `style` to one object. */
21
+ interface Node {
22
+ readonly type: string;
23
+ readonly props: Props & {
24
+ readonly class?: string;
25
+ readonly style?: Style;
26
+ };
27
+ readonly children: readonly Child[];
28
+ }
29
+ type Child = Node | string;
30
+ /** What a template returns: one element, text, or several (several roots). */
31
+ type Markup = Child | readonly Child[];
32
+ /** A component: a function from its attributes and children to markup. */
33
+ type Component<P = Props> = (props: P & {
34
+ children: readonly Child[];
35
+ }) => Markup;
36
+ /**
37
+ * A template: `` html`<p class=${card} ...${attrs}>${text}</p>` `` → a node
38
+ * tree. Several roots give an array.
39
+ */
40
+ declare const html: (strings: TemplateStringsArray, ...values: readonly unknown[]) => Markup;
41
+ //#endregion
42
+ //#region src/email.d.ts
43
+ /** What a template returns. */
44
+ interface Message {
45
+ readonly subject: string;
46
+ /** The line inbox lists show after the subject; hidden in the mail itself. */
47
+ readonly preheader?: string;
48
+ readonly body: Markup;
49
+ }
50
+ interface EmailOptions<P> {
51
+ /** Named props for the dev preview and `renderSamples()`: `{ default: { name: "Ada" } }`. */
52
+ readonly samples?: Readonly<Record<string, P>>;
53
+ }
54
+ declare const KIND: unique symbol;
55
+ /** A defined email: pass it to `render()`. */
56
+ declare class Email<P> {
57
+ readonly [KIND] = true;
58
+ readonly template: (props: P) => Message | Promise<Message>;
59
+ readonly samples: Readonly<Record<string, P>>;
60
+ constructor(template: (props: P) => Message | Promise<Message>, samples?: Readonly<Record<string, P>>);
61
+ }
62
+ /** Defines an email. The props type is the parameter's. */
63
+ declare function email<P>(template: (props: P) => Message | Promise<Message>, options?: EmailOptions<P>): Email<P>;
64
+ //#endregion
65
+ //#region src/index.d.ts
66
+ interface RenderOptions {
67
+ /** The recipient's locale: `t()` runs in it, and `<html lang dir>` follow it. */
68
+ readonly locale?: string;
69
+ /** The recipient's IANA zone for dates, with vi18n. */
70
+ readonly timeZone?: string;
71
+ /** For warnings: the export's name. The preview and `renderSamples()` pass it. */
72
+ readonly name?: string;
73
+ }
74
+ interface Rendered {
75
+ readonly subject: string;
76
+ readonly html: string;
77
+ readonly text: string;
78
+ }
79
+ /** Renders an email for one recipient: its subject, HTML and plain text. */
80
+ declare function render<P>(mail: Email<P>, props: P, options?: RenderOptions): Promise<Rendered>;
81
+ //#endregion
82
+ export { EmailOptions as a, Child as c, Markup as d, Node as f, Email as i, ClassValue as l, html as m, Rendered as n, Message as o, Style as p, render as r, email as s, RenderOptions as t, Component as u };
@@ -0,0 +1,2 @@
1
+ import { a as EmailOptions, c as Child, d as Markup, f as Node, i as Email, l as ClassValue, m as html, n as Rendered, o as Message, p as Style, r as render, s as email, t as RenderOptions, u as Component } from "./index-CSAt1cGc.js";
2
+ export { type Child, type ClassValue, type Component, type Email, type EmailOptions, type Markup, type Message, type Node, RenderOptions, Rendered, type Style, email, html, render };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { n as email, i as html, t as render } from "./src-nwP-sVbY.js";