@sdxc/mail 2026.10.21 → 2026.10.23
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/dist/components.js +6 -1
- package/dist/lib/html-to-text.js +8 -5
- package/dist/previews.js +12 -7
- package/package.json +11 -10
package/dist/components.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "remix/component/jsx-runtime";
|
|
2
|
+
import { iife } from "@sdxc/iife";
|
|
2
3
|
/**
|
|
3
4
|
* Font stack that resolves to a native UI face in every major mail client. No family
|
|
4
5
|
* needs quoting, which keeps the inline style free of escaped character references.
|
|
@@ -144,7 +145,11 @@ export function Text(handle) {
|
|
|
144
145
|
return () => {
|
|
145
146
|
let { children, muted = false, color, size = 16, align = "left" } = handle.props;
|
|
146
147
|
let resolved = color ?? (muted ? MUTED_COLOR : TEXT_COLOR);
|
|
147
|
-
let className =
|
|
148
|
+
let className = iife(() => {
|
|
149
|
+
if (color === undefined)
|
|
150
|
+
return muted ? "mail-muted" : "mail-text";
|
|
151
|
+
return undefined;
|
|
152
|
+
});
|
|
148
153
|
return (_jsx("p", { class: className, style: `margin:0 0 16px;padding:0;font-family:inherit;font-size:${size}px;line-height:1.6;color:${resolved};text-align:${align};`, children: children }));
|
|
149
154
|
};
|
|
150
155
|
}
|
package/dist/lib/html-to-text.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @author [Sergio Xalambrí](https://sergiodxa.com)
|
|
8
8
|
* @copyright Sergio Xalambrí 2026
|
|
9
9
|
*/
|
|
10
|
+
import { iife } from "@sdxc/iife";
|
|
10
11
|
/** Elements whose content belongs to the document structure. */
|
|
11
12
|
const DROPPED_ELEMENTS = new Set(["head", "script", "style", "title"]);
|
|
12
13
|
/** Elements an email layout hides with `display:none`, such as a preheader. */
|
|
@@ -150,11 +151,13 @@ function dropInvisible(html) {
|
|
|
150
151
|
function decodeEntities(text) {
|
|
151
152
|
return text.replace(ENTITY, (match, reference) => {
|
|
152
153
|
let name = reference.toLowerCase();
|
|
153
|
-
let code =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
let code = iife(() => {
|
|
155
|
+
if (name.startsWith("#x"))
|
|
156
|
+
return Number.parseInt(name.slice(2), 16);
|
|
157
|
+
if (name.startsWith("#"))
|
|
158
|
+
return Number.parseInt(name.slice(1), 10);
|
|
159
|
+
return Number.NaN;
|
|
160
|
+
});
|
|
158
161
|
if (Number.isNaN(code))
|
|
159
162
|
return NAMED_ENTITIES[name] ?? match;
|
|
160
163
|
if (code < 1 || code > 0x10ffff)
|
package/dist/previews.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "remix/component/jsx-runtime";
|
|
2
|
+
import { iife } from "@sdxc/iife";
|
|
2
3
|
import { isFailure } from "@sdxc/result";
|
|
3
4
|
import { bg, border, borderEdge, colorScheme, fg } from "@sdxc/u/color";
|
|
4
5
|
import { block, flexWrap, grid, gridTemplate, grow, hstack, vstack } from "@sdxc/u/layout";
|
|
@@ -157,6 +158,16 @@ function PreviewInbox(handle) {
|
|
|
157
158
|
return () => {
|
|
158
159
|
let { base, locales, locale, entries, selected, requested, view, text, stylesheets } = handle.props;
|
|
159
160
|
let readable = selected?.previewable === true && selected.failed !== true;
|
|
161
|
+
let emptyTitle = iife(() => {
|
|
162
|
+
if (selected === undefined && requested !== undefined) {
|
|
163
|
+
return `No template is mapped for the "${requested}" email.`;
|
|
164
|
+
}
|
|
165
|
+
if (selected === undefined)
|
|
166
|
+
return "Select an email to read it.";
|
|
167
|
+
if (selected.failed === true)
|
|
168
|
+
return selected.subject ?? "";
|
|
169
|
+
return `The "${selected.name}" email has no preview(); add one to its template.`;
|
|
170
|
+
});
|
|
160
171
|
return (_jsxs("html", { lang: "en", class: "system", mix: colorScheme("light dark"), children: [_jsxs("head", { children: [_jsx("meta", { charset: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { children: readable && selected?.subject !== undefined
|
|
161
172
|
? `${selected.subject} · Email previews`
|
|
162
173
|
: "Email previews" }), stylesheets.map((href) => (_jsx("link", { rel: "stylesheet", href: href })))] }), _jsxs("body", { mix: [
|
|
@@ -204,13 +215,7 @@ function PreviewInbox(handle) {
|
|
|
204
215
|
]),
|
|
205
216
|
], children: _jsxs(Item, { children: [_jsx(Item.Media, { children: _jsx(Avatar, { children: _jsx(Avatar.Fallback, { children: (entry.name.split(".").pop() ?? entry.name).charAt(0).toUpperCase() }) }) }), _jsxs(Item.Content, { children: [_jsx(Text, { mix: [fontSize("xs"), fg("neutral.muted"), font("mono")], children: entry.name }), _jsx(Item.Title, { mix: [truncate(), weight("semibold")], children: entry.previewable ? (_jsx("span", { mix: entry.failed === true ? fg("danger") : [], children: entry.subject })) : (_jsx(Badge, { color: "warning", children: "No preview" })) }), _jsx(Item.Description, { mix: lineClamp(2), children: entry.previewable
|
|
206
217
|
? entry.snippet
|
|
207
|
-
: "Add preview() to its template to see it here." })] })] }) })))) }), _jsx("main", { mix: [vstack({ gap: 0 }), minBs(0), minIs(0)], children: !readable || selected === undefined ? (_jsx(Empty, { mix: m("auto"), color: selected?.failed === true ? "danger" : "neutral", children: _jsx(Empty.Title, { children:
|
|
208
|
-
? `No template is mapped for the "${requested}" email.`
|
|
209
|
-
: selected === undefined
|
|
210
|
-
? "Select an email to read it."
|
|
211
|
-
: selected.failed === true
|
|
212
|
-
? selected.subject
|
|
213
|
-
: `The "${selected.name}" email has no preview(); add one to its template.` }) })) : (_jsxs(_Fragment, { children: [_jsxs("div", { mix: [
|
|
218
|
+
: "Add preview() to its template to see it here." })] })] }) })))) }), _jsx("main", { mix: [vstack({ gap: 0 }), minBs(0), minIs(0)], children: !readable || selected === undefined ? (_jsx(Empty, { mix: m("auto"), color: selected?.failed === true ? "danger" : "neutral", children: _jsx(Empty.Title, { children: emptyTitle }) })) : (_jsxs(_Fragment, { children: [_jsxs("div", { mix: [
|
|
214
219
|
vstack({ gap: 2 }),
|
|
215
220
|
p(4, 5),
|
|
216
221
|
bg("neutral.bg"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdxc/mail",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.23",
|
|
4
4
|
"description": "Transport-agnostic transactional email with pluggable transports and remix/component rendering",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -17,19 +17,20 @@
|
|
|
17
17
|
"./unsubscribe": "./dist/unsubscribe.js"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@sdxc/crypto": "2026.10.
|
|
21
|
-
"@sdxc/highlight": "2026.10.
|
|
22
|
-
"@sdxc/
|
|
23
|
-
"@sdxc/
|
|
20
|
+
"@sdxc/crypto": "2026.10.23",
|
|
21
|
+
"@sdxc/highlight": "2026.10.23",
|
|
22
|
+
"@sdxc/iife": "2026.10.23",
|
|
23
|
+
"@sdxc/logger": "2026.10.23",
|
|
24
|
+
"@sdxc/markdown": "2026.10.23",
|
|
24
25
|
"@sdxc/result": "2026.10.13",
|
|
25
|
-
"@sdxc/u": "2026.10.
|
|
26
|
-
"@sdxc/ui": "2026.10.
|
|
26
|
+
"@sdxc/u": "2026.10.23",
|
|
27
|
+
"@sdxc/ui": "2026.10.23",
|
|
27
28
|
"@sdxc/uuid": "2026.10.13",
|
|
28
29
|
"@standard-schema/spec": "^1.1.0"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|
|
31
|
-
"@sdxc/cli": "2026.10.
|
|
32
|
-
"@sdxc/jobs": "2026.10.
|
|
32
|
+
"@sdxc/cli": "2026.10.23",
|
|
33
|
+
"@sdxc/jobs": "2026.10.23",
|
|
33
34
|
"remix": "3.0.0"
|
|
34
35
|
},
|
|
35
36
|
"peerDependenciesMeta": {
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"optional": true
|
|
41
42
|
}
|
|
42
43
|
},
|
|
43
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "8e428ddf15290d44500a9618ec4d04bd7629fa99",
|
|
44
45
|
"publishConfig": {
|
|
45
46
|
"access": "public"
|
|
46
47
|
},
|