@one-million-lines/email-builder 0.2.1 → 0.3.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/README.md +43 -0
- package/dist/core/plugins.d.ts +40 -1
- package/dist/core/types.d.ts +5 -1
- package/dist/core/utils.d.ts +7 -0
- package/dist/core/validation.d.ts +4 -0
- package/dist/email-builder.cjs +16 -15
- package/dist/email-builder.cjs.map +1 -1
- package/dist/email-builder.js +2903 -1967
- package/dist/email-builder.js.map +1 -1
- package/dist/index.d.ts +21 -1
- package/dist/modules/helpers.d.ts +6 -1
- package/dist/plugins/productSearch/ProductSearchModal.d.ts +13 -0
- package/dist/plugins/productSearch/index.d.ts +45 -0
- package/dist/plugins/productSearch/state.d.ts +11 -0
- package/dist/plugins/productSearch/useProductSearch.d.ts +2 -0
- package/dist/plugins/voucherSelect/VoucherPanel.d.ts +10 -0
- package/dist/plugins/voucherSelect/index.d.ts +45 -0
- package/dist/plugins/voucherSelect/logic.d.ts +16 -0
- package/dist/plugins/voucherSelect/state.d.ts +24 -0
- package/dist/plugins/voucherSelect/useVouchers.d.ts +15 -0
- package/dist/styles.css +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -155,6 +155,49 @@ response is validated with Zod before it is applied. See
|
|
|
155
155
|
[`src/ai/README.md`](./src/ai/README.md) and
|
|
156
156
|
[`backend/README.md`](./backend/README.md).
|
|
157
157
|
|
|
158
|
+
### Product search
|
|
159
|
+
|
|
160
|
+
Connect product cards to your catalog. When a product provider is configured, a
|
|
161
|
+
**Find** button appears on any product grid (and a search icon on each card).
|
|
162
|
+
Searching opens a modal, previews the returned product, and — on **Save** —
|
|
163
|
+
populates the card's fields (which stay fully editable afterwards).
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
<EmailBuilder productEndpoint="http://localhost:3001/products/search" />
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { registerPlugin, productSearchPlugin } from "@one-million-lines/email-builder";
|
|
171
|
+
registerPlugin(productSearchPlugin({ endpoint: "http://localhost:3001/products/search" }));
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The demo backend in [`backend/`](./backend) ships a `/products/search` endpoint
|
|
175
|
+
over a small in-memory catalog. Product fields are `title`, `final_price`,
|
|
176
|
+
`old_price` (optional), `description`, `link`, `image` and `stars` (optional).
|
|
177
|
+
See [`src/plugins/productSearch/README.md`](./src/plugins/productSearch/README.md)
|
|
178
|
+
for the wire protocol and response mapping.
|
|
179
|
+
|
|
180
|
+
### Voucher select
|
|
181
|
+
|
|
182
|
+
Let users pick a discount code from your backend instead of typing it. When a
|
|
183
|
+
voucher provider is configured, selecting a **voucher block** (the built-in
|
|
184
|
+
**Voucher Code** module, or any module with a `voucherCode` text element) shows a
|
|
185
|
+
**Select voucher** dropdown that fills the code. The list is fetched once and
|
|
186
|
+
cached (lazily, or eagerly with `preload`).
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
<EmailBuilder voucherEndpoint="http://localhost:3001/vouchers" />
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { registerPlugin, voucherPlugin } from "@one-million-lines/email-builder";
|
|
194
|
+
registerPlugin(voucherPlugin({ endpoint: "http://localhost:3001/vouchers", preload: true }));
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The demo backend ships a `GET /vouchers` endpoint. See
|
|
198
|
+
[`src/plugins/voucherSelect/README.md`](./src/plugins/voucherSelect/README.md)
|
|
199
|
+
for the wire protocol and response mapping.
|
|
200
|
+
|
|
158
201
|
### Styling & isolation
|
|
159
202
|
|
|
160
203
|
The stylesheet at `@one-million-lines/email-builder/styles.css` is designed to
|
package/dist/core/plugins.d.ts
CHANGED
|
@@ -7,13 +7,50 @@ export interface AssetProvider {
|
|
|
7
7
|
alt?: string;
|
|
8
8
|
}>;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* A single product returned by a {@link ProductProvider} search. Field names
|
|
12
|
+
* match the builder's `Product` model so results drop straight into a card.
|
|
13
|
+
*/
|
|
14
|
+
export interface ProductSearchResult {
|
|
15
|
+
name: string;
|
|
16
|
+
finalPrice: string;
|
|
17
|
+
oldPrice?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
link?: string;
|
|
20
|
+
image?: string;
|
|
21
|
+
imageAlt?: string;
|
|
22
|
+
stars?: number;
|
|
23
|
+
/** Optional external identifier echoed back from the backend. */
|
|
24
|
+
sku?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ProductProvider {
|
|
27
|
+
/** Look up a single product for a free-text query. Resolves null if none. */
|
|
28
|
+
search: (query: string) => Promise<ProductSearchResult | null>;
|
|
29
|
+
}
|
|
30
|
+
/** A discount/voucher entry returned by a {@link VoucherProvider}. */
|
|
31
|
+
export interface Voucher {
|
|
32
|
+
/** Stable identifier (used to remember the selection). */
|
|
33
|
+
id: string;
|
|
34
|
+
/** Human label shown in the select dropdown. */
|
|
35
|
+
title: string;
|
|
36
|
+
/** The code (or merge tag) inserted into the voucher block. */
|
|
37
|
+
code: string;
|
|
38
|
+
/** Optional longer description. */
|
|
39
|
+
description?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface VoucherProvider {
|
|
42
|
+
/** Load the list of vouchers to choose from. */
|
|
43
|
+
list: () => Promise<Voucher[]>;
|
|
44
|
+
}
|
|
10
45
|
export interface BuilderHandle {
|
|
11
46
|
registerModule: (def: ModuleDefinition) => void;
|
|
12
47
|
registerTheme: (theme: Theme) => void;
|
|
13
48
|
registerAssetProvider: (provider: AssetProvider) => void;
|
|
49
|
+
registerProductProvider: (provider: ProductProvider) => void;
|
|
50
|
+
registerVoucherProvider: (provider: VoucherProvider) => void;
|
|
14
51
|
setAIProvider: (provider: AIProvider) => void;
|
|
15
52
|
}
|
|
16
|
-
export type PluginType = "modules" | "themes" | "asset-provider" | "ai-provider";
|
|
53
|
+
export type PluginType = "modules" | "themes" | "asset-provider" | "product-provider" | "voucher-provider" | "ai-provider";
|
|
17
54
|
export interface Plugin {
|
|
18
55
|
name: string;
|
|
19
56
|
type: PluginType;
|
|
@@ -23,4 +60,6 @@ export declare const builder: BuilderHandle;
|
|
|
23
60
|
export declare function registerPlugin(plugin: Plugin): void;
|
|
24
61
|
export declare function getRegisteredThemes(): Theme[];
|
|
25
62
|
export declare function getAssetProvider(): AssetProvider | null;
|
|
63
|
+
export declare function getProductProvider(): ProductProvider | null;
|
|
64
|
+
export declare function getVoucherProvider(): VoucherProvider | null;
|
|
26
65
|
export declare function getAIProvider(): AIProvider | null;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface BaseStyle {
|
|
|
18
18
|
export interface TextElement {
|
|
19
19
|
id: string;
|
|
20
20
|
type: "text";
|
|
21
|
-
role?: "headline" | "subheadline" | "body" | "caption";
|
|
21
|
+
role?: "headline" | "subheadline" | "body" | "caption" | "voucherCode";
|
|
22
22
|
content: string;
|
|
23
23
|
style?: BaseStyle & {
|
|
24
24
|
fontFamily?: string;
|
|
@@ -79,6 +79,8 @@ export interface Product {
|
|
|
79
79
|
description?: string;
|
|
80
80
|
link?: string;
|
|
81
81
|
buttonLabel?: string;
|
|
82
|
+
/** Optional 0–5 rating. Rendered as star glyphs when the grid shows stars. */
|
|
83
|
+
stars?: number;
|
|
82
84
|
}
|
|
83
85
|
export interface ProductGridElement {
|
|
84
86
|
id: string;
|
|
@@ -88,6 +90,8 @@ export interface ProductGridElement {
|
|
|
88
90
|
showOldPrice: boolean;
|
|
89
91
|
showButton: boolean;
|
|
90
92
|
showDescription: boolean;
|
|
93
|
+
/** Show the star rating on each product card. Optional for back-compat. */
|
|
94
|
+
showStars?: boolean;
|
|
91
95
|
buttonLabel?: string;
|
|
92
96
|
style?: BaseStyle & {
|
|
93
97
|
nameColor?: string;
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
export declare function uid(prefix?: string): string;
|
|
2
2
|
export declare function escapeHtml(s: string): string;
|
|
3
3
|
export declare function safeUrl(url: string | undefined): string;
|
|
4
|
+
/** Default gold used for product star ratings. */
|
|
5
|
+
export declare const STAR_COLOR = "#F5A623";
|
|
6
|
+
/**
|
|
7
|
+
* Build a 5-glyph star string for a 0–5 rating (rounded to the nearest whole
|
|
8
|
+
* star). Uses ★ (full) and ☆ (empty) so it renders in any email client.
|
|
9
|
+
*/
|
|
10
|
+
export declare function starGlyphs(rating: number): string;
|
|
@@ -44,11 +44,13 @@ export declare const moduleSchema: z.ZodObject<{
|
|
|
44
44
|
description: z.ZodOptional<z.ZodString>;
|
|
45
45
|
link: z.ZodOptional<z.ZodString>;
|
|
46
46
|
buttonLabel: z.ZodOptional<z.ZodString>;
|
|
47
|
+
stars: z.ZodOptional<z.ZodNumber>;
|
|
47
48
|
}, z.core.$strip>>;
|
|
48
49
|
columns: z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>;
|
|
49
50
|
showOldPrice: z.ZodBoolean;
|
|
50
51
|
showButton: z.ZodBoolean;
|
|
51
52
|
showDescription: z.ZodBoolean;
|
|
53
|
+
showStars: z.ZodOptional<z.ZodBoolean>;
|
|
52
54
|
buttonLabel: z.ZodOptional<z.ZodString>;
|
|
53
55
|
style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodAny>]>>>;
|
|
54
56
|
}, z.core.$strip>], "type">>;
|
|
@@ -130,11 +132,13 @@ export declare const documentSchema: z.ZodObject<{
|
|
|
130
132
|
description: z.ZodOptional<z.ZodString>;
|
|
131
133
|
link: z.ZodOptional<z.ZodString>;
|
|
132
134
|
buttonLabel: z.ZodOptional<z.ZodString>;
|
|
135
|
+
stars: z.ZodOptional<z.ZodNumber>;
|
|
133
136
|
}, z.core.$strip>>;
|
|
134
137
|
columns: z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>;
|
|
135
138
|
showOldPrice: z.ZodBoolean;
|
|
136
139
|
showButton: z.ZodBoolean;
|
|
137
140
|
showDescription: z.ZodBoolean;
|
|
141
|
+
showStars: z.ZodOptional<z.ZodBoolean>;
|
|
138
142
|
buttonLabel: z.ZodOptional<z.ZodString>;
|
|
139
143
|
style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodAny>]>>>;
|
|
140
144
|
}, z.core.$strip>], "type">>;
|