@aglyn/plugins-email 1.0.0-beta.143

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.
Files changed (144) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +58 -0
  4. package/src/index.d.ts +35 -0
  5. package/src/index.js +35 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/campaign-design-create-widget.d.ts +21 -0
  8. package/src/lib/components/campaign-design-create-widget.js +61 -0
  9. package/src/lib/components/campaign-design-create-widget.js.map +1 -0
  10. package/src/lib/components/campaign-sender-editor-widget.d.ts +18 -0
  11. package/src/lib/components/campaign-sender-editor-widget.js +39 -0
  12. package/src/lib/components/campaign-sender-editor-widget.js.map +1 -0
  13. package/src/lib/components/campaign-topic-options-widget.d.ts +19 -0
  14. package/src/lib/components/campaign-topic-options-widget.js +48 -0
  15. package/src/lib/components/campaign-topic-options-widget.js.map +1 -0
  16. package/src/lib/components/campaign-topic-select.d.ts +32 -0
  17. package/src/lib/components/campaign-topic-select.js +87 -0
  18. package/src/lib/components/campaign-topic-select.js.map +1 -0
  19. package/src/lib/components/dynamic-list-rule-fields.d.ts +173 -0
  20. package/src/lib/components/dynamic-list-rule-fields.js +1473 -0
  21. package/src/lib/components/dynamic-list-rule-fields.js.map +1 -0
  22. package/src/lib/components/email-blocks.d.ts +111 -0
  23. package/src/lib/components/email-blocks.js +875 -0
  24. package/src/lib/components/email-blocks.js.map +1 -0
  25. package/src/lib/components/email-design-preview.d.ts +62 -0
  26. package/src/lib/components/email-design-preview.js +174 -0
  27. package/src/lib/components/email-design-preview.js.map +1 -0
  28. package/src/lib/components/email-screens-card.d.ts +42 -0
  29. package/src/lib/components/email-screens-card.js +277 -0
  30. package/src/lib/components/email-screens-card.js.map +1 -0
  31. package/src/lib/components/email-template-detail.d.ts +48 -0
  32. package/src/lib/components/email-template-detail.js +681 -0
  33. package/src/lib/components/email-template-detail.js.map +1 -0
  34. package/src/lib/components/email-topic-detail.d.ts +32 -0
  35. package/src/lib/components/email-topic-detail.js +293 -0
  36. package/src/lib/components/email-topic-detail.js.map +1 -0
  37. package/src/lib/components/email-topics-card.d.ts +46 -0
  38. package/src/lib/components/email-topics-card.js +327 -0
  39. package/src/lib/components/email-topics-card.js.map +1 -0
  40. package/src/lib/components/email-zones.d.ts +28 -0
  41. package/src/lib/components/email-zones.js +20 -0
  42. package/src/lib/components/email-zones.js.map +1 -0
  43. package/src/lib/components/emails-console-page.d.ts +32 -0
  44. package/src/lib/components/emails-console-page.js +229 -0
  45. package/src/lib/components/emails-console-page.js.map +1 -0
  46. package/src/lib/components/emails-console-sections.d.ts +36 -0
  47. package/src/lib/components/emails-console-sections.js +108 -0
  48. package/src/lib/components/emails-console-sections.js.map +1 -0
  49. package/src/lib/components/list-detail-card.d.ts +47 -0
  50. package/src/lib/components/list-detail-card.js +273 -0
  51. package/src/lib/components/list-detail-card.js.map +1 -0
  52. package/src/lib/components/list-edit-card.d.ts +11 -0
  53. package/src/lib/components/list-edit-card.js +287 -0
  54. package/src/lib/components/list-edit-card.js.map +1 -0
  55. package/src/lib/components/list-import-drawer.d.ts +22 -0
  56. package/src/lib/components/list-import-drawer.js +662 -0
  57. package/src/lib/components/list-import-drawer.js.map +1 -0
  58. package/src/lib/components/list-members-panel.d.ts +94 -0
  59. package/src/lib/components/list-members-panel.js +686 -0
  60. package/src/lib/components/list-members-panel.js.map +1 -0
  61. package/src/lib/components/lists-card.d.ts +28 -0
  62. package/src/lib/components/lists-card.js +377 -0
  63. package/src/lib/components/lists-card.js.map +1 -0
  64. package/src/lib/components/sending-domain-detail.d.ts +26 -0
  65. package/src/lib/components/sending-domain-detail.js +496 -0
  66. package/src/lib/components/sending-domain-detail.js.map +1 -0
  67. package/src/lib/components/sending-domains-card.d.ts +33 -0
  68. package/src/lib/components/sending-domains-card.js +962 -0
  69. package/src/lib/components/sending-domains-card.js.map +1 -0
  70. package/src/lib/components/sending-sender-drawer.d.ts +94 -0
  71. package/src/lib/components/sending-sender-drawer.js +543 -0
  72. package/src/lib/components/sending-sender-drawer.js.map +1 -0
  73. package/src/lib/components/suppressions-card.d.ts +49 -0
  74. package/src/lib/components/suppressions-card.js +639 -0
  75. package/src/lib/components/suppressions-card.js.map +1 -0
  76. package/src/lib/components/use-org-email-topics.d.ts +79 -0
  77. package/src/lib/components/use-org-email-topics.js +111 -0
  78. package/src/lib/components/use-org-email-topics.js.map +1 -0
  79. package/src/lib/constants/bundle-common.d.ts +18 -0
  80. package/src/lib/constants/bundle-common.js +18 -0
  81. package/src/lib/constants/bundle-common.js.map +1 -0
  82. package/src/lib/hooks/use-org-company-options.d.ts +20 -0
  83. package/src/lib/hooks/use-org-company-options.js +138 -0
  84. package/src/lib/hooks/use-org-company-options.js.map +1 -0
  85. package/src/lib/hooks/use-org-contact-fields.d.ts +40 -0
  86. package/src/lib/hooks/use-org-contact-fields.js +91 -0
  87. package/src/lib/hooks/use-org-contact-fields.js.map +1 -0
  88. package/src/lib/hooks/use-org-contact-segments.d.ts +16 -0
  89. package/src/lib/hooks/use-org-contact-segments.js +55 -0
  90. package/src/lib/hooks/use-org-contact-segments.js.map +1 -0
  91. package/src/lib/hooks/use-org-crm-views.d.ts +8 -0
  92. package/src/lib/hooks/use-org-crm-views.js +74 -0
  93. package/src/lib/hooks/use-org-crm-views.js.map +1 -0
  94. package/src/lib/hooks/use-org-lists.d.ts +8 -0
  95. package/src/lib/hooks/use-org-lists.js +47 -0
  96. package/src/lib/hooks/use-org-lists.js.map +1 -0
  97. package/src/lib/model/email-design-document.d.ts +52 -0
  98. package/src/lib/model/email-design-document.js +62 -0
  99. package/src/lib/model/email-design-document.js.map +1 -0
  100. package/src/lib/model/index.d.ts +64 -0
  101. package/src/lib/model/index.js +71 -0
  102. package/src/lib/model/index.js.map +1 -0
  103. package/src/lib/model/sending-domain-status.d.ts +99 -0
  104. package/src/lib/model/sending-domain-status.js +196 -0
  105. package/src/lib/model/sending-domain-status.js.map +1 -0
  106. package/src/lib/model/template-provenance.d.ts +113 -0
  107. package/src/lib/model/template-provenance.js +107 -0
  108. package/src/lib/model/template-provenance.js.map +1 -0
  109. package/src/lib/model/template-report.d.ts +158 -0
  110. package/src/lib/model/template-report.js +249 -0
  111. package/src/lib/model/template-report.js.map +1 -0
  112. package/src/lib/plugin.d.ts +27 -0
  113. package/src/lib/plugin.js +163 -0
  114. package/src/lib/plugin.js.map +1 -0
  115. package/src/lib/server-console.d.ts +116 -0
  116. package/src/lib/server-console.js +422 -0
  117. package/src/lib/server-console.js.map +1 -0
  118. package/src/lib/server-email-drafts.d.ts +104 -0
  119. package/src/lib/server-email-drafts.js +381 -0
  120. package/src/lib/server-email-drafts.js.map +1 -0
  121. package/src/lib/server-list-gate.d.ts +183 -0
  122. package/src/lib/server-list-gate.js +365 -0
  123. package/src/lib/server-list-gate.js.map +1 -0
  124. package/src/lib/server-list-import.d.ts +199 -0
  125. package/src/lib/server-list-import.js +632 -0
  126. package/src/lib/server-list-import.js.map +1 -0
  127. package/src/lib/server-suppressions.d.ts +135 -0
  128. package/src/lib/server-suppressions.js +295 -0
  129. package/src/lib/server-suppressions.js.map +1 -0
  130. package/src/lib/server.d.ts +19 -0
  131. package/src/lib/server.js +834 -0
  132. package/src/lib/server.js.map +1 -0
  133. package/src/lib/site.d.ts +26 -0
  134. package/src/lib/site.js +81 -0
  135. package/src/lib/site.js.map +1 -0
  136. package/src/lib/unsubscribe-link.d.ts +311 -0
  137. package/src/lib/unsubscribe-link.js +398 -0
  138. package/src/lib/unsubscribe-link.js.map +1 -0
  139. package/src/lib/utils/create-email-screen.d.ts +59 -0
  140. package/src/lib/utils/create-email-screen.js +59 -0
  141. package/src/lib/utils/create-email-screen.js.map +1 -0
  142. package/src/lib/utils/generate-preset-id.d.ts +19 -0
  143. package/src/lib/utils/generate-preset-id.js +25 -0
  144. package/src/lib/utils/generate-preset-id.js.map +1 -0
@@ -0,0 +1,875 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiCardTextOutline, mdiEmailOutline, mdiFormatText, mdiImageOutline, mdiMinus, mdiPackageVariantClosed, mdiArrowExpandVertical, mdiGestureTapButton, mdiCodeTags } from "@aglyn/shared-data-mdi";
21
+ import { sanitizeAuthorHtml } from "@aglyn/aglyn/app-utils/author-html";
22
+ import { mergeSxProps } from "@aglyn/shared-ui-theme";
23
+ import Box from "@mui/material/Box";
24
+ import Typography from "@mui/material/Typography";
25
+ import { forwardRef } from "react";
26
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
27
+ import { generatePresetId } from "../utils/generate-preset-id.js";
28
+ // ---------------------------------------------------------------- section
29
+ export const SECTION_ID = 'emailSection';
30
+ export const EmailSection = /*#__PURE__*/ forwardRef((props, ref)=>{
31
+ const { backgroundColor, padding, align, children, sx } = props, rest = _object_without_properties_loose(props, [
32
+ "backgroundColor",
33
+ "padding",
34
+ "align",
35
+ "children",
36
+ "sx"
37
+ ]);
38
+ return /*#__PURE__*/ _jsx(Box, _extends({
39
+ ref: ref
40
+ }, rest, {
41
+ sx: mergeSxProps({
42
+ maxWidth: 600,
43
+ mx: 'auto',
44
+ backgroundColor: backgroundColor || '#ffffff',
45
+ p: `${padding != null ? padding : 24}px`,
46
+ textAlign: align != null ? align : 'left'
47
+ }, sx),
48
+ children: children
49
+ }));
50
+ });
51
+ EmailSection.displayName = 'EmailSection';
52
+ export const emailSectionSchema = {
53
+ $id: SECTION_ID,
54
+ pluginId: BUNDLE_ID,
55
+ displayName: 'Email section',
56
+ description: 'An email-safe band with its own background color and padding.',
57
+ category: Aglyn.ComponentCategory.LAYOUT,
58
+ icon: {
59
+ path: mdiEmailOutline.path,
60
+ sx: {
61
+ color: '#f57c00'
62
+ }
63
+ },
64
+ attributes: [
65
+ {
66
+ name: 'backgroundColor',
67
+ label: 'Background color',
68
+ description: 'Solid colors only — gradients are unreliable in email.',
69
+ component: Aglyn.FieldComponentType.COLOR_PICKER
70
+ },
71
+ {
72
+ name: 'padding',
73
+ label: 'Padding (px)',
74
+ description: 'Inner spacing around the section content.',
75
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
76
+ type: 'number'
77
+ },
78
+ {
79
+ name: 'align',
80
+ label: 'Content alignment',
81
+ description: 'How every block inside this section lines up. Each block can still ' + 'override it with its own alignment.',
82
+ component: Aglyn.FieldComponentType.SELECT,
83
+ options: [
84
+ {
85
+ value: 'left',
86
+ label: 'Left'
87
+ },
88
+ {
89
+ value: 'center',
90
+ label: 'Center'
91
+ },
92
+ {
93
+ value: 'right',
94
+ label: 'Right'
95
+ }
96
+ ]
97
+ }
98
+ ]
99
+ };
100
+ // ------------------------------------------------------------------- text
101
+ export const TEXT_ID = 'emailText';
102
+ const TEXT_PRESETS = {
103
+ heading: {
104
+ fontSize: 28,
105
+ fontWeight: 700,
106
+ lineHeight: 1.25
107
+ },
108
+ subheading: {
109
+ fontSize: 20,
110
+ fontWeight: 600,
111
+ lineHeight: 1.3
112
+ },
113
+ body: {
114
+ fontSize: 15,
115
+ fontWeight: 400,
116
+ lineHeight: 1.55
117
+ },
118
+ caption: {
119
+ fontSize: 12,
120
+ fontWeight: 400,
121
+ lineHeight: 1.4
122
+ }
123
+ };
124
+ export const EmailText = /*#__PURE__*/ forwardRef((props, ref)=>{
125
+ const { children, variant, color, align, sx } = props, rest = _object_without_properties_loose(props, [
126
+ "children",
127
+ "variant",
128
+ "color",
129
+ "align",
130
+ "sx"
131
+ ]);
132
+ const preset = TEXT_PRESETS[variant != null ? variant : 'body'];
133
+ return /*#__PURE__*/ _jsx(Typography, _extends({
134
+ ref: ref,
135
+ component: "div"
136
+ }, rest, {
137
+ sx: mergeSxProps({
138
+ fontSize: preset.fontSize,
139
+ fontWeight: preset.fontWeight,
140
+ lineHeight: preset.lineHeight,
141
+ color: color || '#1a1a1a',
142
+ textAlign: align != null ? align : 'left',
143
+ fontFamily: 'Helvetica, Arial, sans-serif',
144
+ mb: 1
145
+ }, sx),
146
+ children: children != null ? children : 'Email text'
147
+ }));
148
+ });
149
+ EmailText.displayName = 'EmailText';
150
+ export const emailTextSchema = {
151
+ $id: TEXT_ID,
152
+ pluginId: BUNDLE_ID,
153
+ displayName: 'Email text',
154
+ description: 'A paragraph of email copy in one of the preset styles.',
155
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
156
+ icon: {
157
+ path: mdiFormatText.path,
158
+ sx: {
159
+ color: '#f57c00'
160
+ }
161
+ },
162
+ flags: {
163
+ textEditable: Aglyn.FEATURE_FLAG.ENABLED
164
+ },
165
+ attributes: [
166
+ {
167
+ name: 'children',
168
+ label: 'Text',
169
+ description: 'Supports merge tokens: {{contact.firstName}}, {{contact.email}}, ' + '{{org.name}}, {{unsubscribeUrl}}.',
170
+ component: Aglyn.FieldComponentType.TEXTAREA
171
+ },
172
+ {
173
+ name: 'variant',
174
+ label: 'Style',
175
+ description: 'Size and weight of this text — Heading and Subheading also give it ' + 'the spacing above and below that a heading needs.',
176
+ component: Aglyn.FieldComponentType.SELECT,
177
+ options: [
178
+ {
179
+ value: 'heading',
180
+ label: 'Heading'
181
+ },
182
+ {
183
+ value: 'subheading',
184
+ label: 'Subheading'
185
+ },
186
+ {
187
+ value: 'body',
188
+ label: 'Body'
189
+ },
190
+ {
191
+ value: 'caption',
192
+ label: 'Caption'
193
+ }
194
+ ]
195
+ },
196
+ {
197
+ name: 'color',
198
+ label: 'Color',
199
+ description: 'Text color. Keep it dark on a light background: many clients ' + 'ignore dark mode overrides and show your color as-is.',
200
+ component: Aglyn.FieldComponentType.COLOR_PICKER
201
+ },
202
+ {
203
+ name: 'align',
204
+ label: 'Alignment',
205
+ description: 'How this block of text lines up within the section.',
206
+ component: Aglyn.FieldComponentType.SELECT,
207
+ options: [
208
+ {
209
+ value: 'left',
210
+ label: 'Left'
211
+ },
212
+ {
213
+ value: 'center',
214
+ label: 'Center'
215
+ },
216
+ {
217
+ value: 'right',
218
+ label: 'Right'
219
+ }
220
+ ]
221
+ }
222
+ ]
223
+ };
224
+ // --------------------------------------------------------------- richtext
225
+ export const RICHTEXT_ID = 'emailRichtext';
226
+ export const EmailRichtext = /*#__PURE__*/ forwardRef((props, ref)=>{
227
+ const { html, sx } = props, rest = _object_without_properties_loose(props, [
228
+ "html",
229
+ "sx"
230
+ ]);
231
+ if (!(html == null ? void 0 : html.trim())) {
232
+ return /*#__PURE__*/ _jsx(Box, _extends({
233
+ ref: ref
234
+ }, rest, {
235
+ sx: mergeSxProps({
236
+ p: 2,
237
+ border: '1px dashed',
238
+ borderColor: 'divider',
239
+ color: 'text.secondary',
240
+ fontSize: 13
241
+ }, sx),
242
+ children: 'Rich text — add HTML in the attributes panel'
243
+ }));
244
+ }
245
+ return /*#__PURE__*/ _jsx(Box, _extends({
246
+ ref: ref
247
+ }, rest, {
248
+ sx: mergeSxProps({
249
+ fontFamily: 'Helvetica, Arial, sans-serif',
250
+ fontSize: 15
251
+ }, sx),
252
+ // Sanitized on every render — same policy as the custom HTML block.
253
+ // The `typeof window` guard this replaced existed only because that
254
+ // policy was DOMPurify, which needs a DOM; it is now a pure function
255
+ // (AGL-1901), so the body survives a server render instead of being
256
+ // blanked — which for an email is the render that gets SENT.
257
+ dangerouslySetInnerHTML: {
258
+ __html: sanitizeAuthorHtml(html)
259
+ }
260
+ }));
261
+ });
262
+ EmailRichtext.displayName = 'EmailRichtext';
263
+ export const emailRichtextSchema = {
264
+ $id: RICHTEXT_ID,
265
+ pluginId: BUNDLE_ID,
266
+ displayName: 'Email rich text',
267
+ description: 'An HTML fragment in an email, sanitised on render.',
268
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
269
+ icon: {
270
+ path: mdiCardTextOutline.path,
271
+ sx: {
272
+ color: '#f57c00'
273
+ }
274
+ },
275
+ flags: {
276
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
277
+ },
278
+ attributes: [
279
+ {
280
+ name: 'html',
281
+ label: 'HTML',
282
+ description: 'Formatted content (p, b, i, a, ul/ol, h1-h4). Scripts and forms ' + 'are stripped; keep styling simple for email clients. Merge ' + 'tokens work here too.',
283
+ component: Aglyn.FieldComponentType.TEXTAREA
284
+ }
285
+ ]
286
+ };
287
+ // ------------------------------------------------------------------ image
288
+ export const IMAGE_ID = 'emailImage';
289
+ export const EmailImage = /*#__PURE__*/ forwardRef((props, ref)=>{
290
+ const { src: storedSrc, alt, width, href, align, sx } = props, rest = _object_without_properties_loose(props, [
291
+ "src",
292
+ "alt",
293
+ "width",
294
+ "href",
295
+ "align",
296
+ "sx"
297
+ ]);
298
+ // A media-picker target, so it can hold a media reference (AGL-1215).
299
+ // This is the CANVAS preview only — the sent HTML is built by
300
+ // `email-render`, which needs an absolute URL and cannot resolve either
301
+ // a reference or the relative CDN path it replaces.
302
+ const src = Aglyn.resolveMediaSrc(storedSrc);
303
+ return /*#__PURE__*/ _jsx(Box, _extends({
304
+ ref: ref
305
+ }, rest, {
306
+ sx: mergeSxProps({
307
+ textAlign: align != null ? align : 'center',
308
+ my: 1
309
+ }, sx),
310
+ children: src ? /*#__PURE__*/ _jsx(Box, {
311
+ component: "img",
312
+ src: src,
313
+ alt: alt != null ? alt : '',
314
+ sx: {
315
+ maxWidth: '100%',
316
+ width: width ? `${width}px` : '100%'
317
+ }
318
+ }) : /*#__PURE__*/ _jsx(Box, {
319
+ sx: {
320
+ height: 120,
321
+ display: 'flex',
322
+ alignItems: 'center',
323
+ justifyContent: 'center',
324
+ border: '1px dashed',
325
+ borderColor: 'divider',
326
+ color: 'text.secondary',
327
+ fontSize: 13
328
+ },
329
+ children: 'Image — pick from the media library'
330
+ })
331
+ }));
332
+ });
333
+ EmailImage.displayName = 'EmailImage';
334
+ export const emailImageSchema = {
335
+ $id: IMAGE_ID,
336
+ pluginId: BUNDLE_ID,
337
+ displayName: 'Email image',
338
+ description: 'An email-safe image, capped at 600px wide, optionally linked.',
339
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
340
+ icon: {
341
+ path: mdiImageOutline.path,
342
+ sx: {
343
+ color: '#f57c00'
344
+ }
345
+ },
346
+ flags: {
347
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
348
+ },
349
+ attributes: [
350
+ {
351
+ name: 'src',
352
+ label: 'Source URL',
353
+ description: 'Use an absolute URL — email clients cannot resolve relative paths.',
354
+ component: Aglyn.FieldComponentType.TEXT_FIELD
355
+ },
356
+ {
357
+ name: 'alt',
358
+ label: 'Alt text',
359
+ // AGL-1896: the same "Browse media" default the site Image element
360
+ // gets. It matters MORE here — most clients block images by default,
361
+ // so for most recipients the alt text IS the block.
362
+ description: 'Shown while images are blocked — most clients block by default. ' + 'Filled in from the media library when you pick a file that has ' + 'alt text.',
363
+ component: Aglyn.FieldComponentType.TEXT_FIELD
364
+ },
365
+ {
366
+ name: 'width',
367
+ label: 'Width (px)',
368
+ description: 'How wide the image renders. Blank fills the section — which is ' + 'usually right, since a phone is narrower than any number you pick.',
369
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
370
+ type: 'number'
371
+ },
372
+ {
373
+ name: 'href',
374
+ label: 'Link URL',
375
+ description: 'Where the image goes when it is clicked. Blank leaves it as a ' + 'plain picture.',
376
+ component: Aglyn.FieldComponentType.TEXT_FIELD
377
+ },
378
+ {
379
+ name: 'align',
380
+ label: 'Alignment',
381
+ description: 'Where the image sits when it is narrower than the section.',
382
+ component: Aglyn.FieldComponentType.SELECT,
383
+ options: [
384
+ {
385
+ value: 'left',
386
+ label: 'Left'
387
+ },
388
+ {
389
+ value: 'center',
390
+ label: 'Center'
391
+ },
392
+ {
393
+ value: 'right',
394
+ label: 'Right'
395
+ }
396
+ ]
397
+ }
398
+ ]
399
+ };
400
+ // ----------------------------------------------------------------- button
401
+ export const BUTTON_ID = 'emailButton';
402
+ export const EmailButton = /*#__PURE__*/ forwardRef((props, ref)=>{
403
+ const { children, href, backgroundColor, color, align, sx } = props, rest = _object_without_properties_loose(props, [
404
+ "children",
405
+ "href",
406
+ "backgroundColor",
407
+ "color",
408
+ "align",
409
+ "sx"
410
+ ]);
411
+ return /*#__PURE__*/ _jsx(Box, _extends({
412
+ ref: ref
413
+ }, rest, {
414
+ sx: mergeSxProps({
415
+ textAlign: align != null ? align : 'center',
416
+ my: 1.5
417
+ }, sx),
418
+ children: /*#__PURE__*/ _jsx(Box, {
419
+ component: "span",
420
+ sx: {
421
+ display: 'inline-block',
422
+ px: 3,
423
+ py: 1.25,
424
+ borderRadius: 1,
425
+ backgroundColor: backgroundColor || '#1a73e8',
426
+ color: color || '#ffffff',
427
+ fontFamily: 'Helvetica, Arial, sans-serif',
428
+ fontSize: 15,
429
+ fontWeight: 600
430
+ },
431
+ children: children != null ? children : 'Call to action'
432
+ })
433
+ }));
434
+ });
435
+ EmailButton.displayName = 'EmailButton';
436
+ export const emailButtonSchema = {
437
+ $id: BUTTON_ID,
438
+ pluginId: BUNDLE_ID,
439
+ displayName: 'Email button',
440
+ description: 'A call-to-action button that survives every mail client.',
441
+ category: Aglyn.ComponentCategory.INPUT,
442
+ icon: {
443
+ path: mdiGestureTapButton.path,
444
+ sx: {
445
+ color: '#f57c00'
446
+ }
447
+ },
448
+ flags: {
449
+ textEditable: Aglyn.FEATURE_FLAG.ENABLED
450
+ },
451
+ attributes: [
452
+ {
453
+ name: 'children',
454
+ label: 'Label',
455
+ description: 'The words on the button. Say what happens next — "See the report" ' + 'reads as a destination where "Click here" does not.',
456
+ component: Aglyn.FieldComponentType.TEXT_FIELD
457
+ },
458
+ {
459
+ name: 'href',
460
+ label: 'Link URL',
461
+ description: 'Absolute URL (https://…). Merge tokens allowed.',
462
+ component: Aglyn.FieldComponentType.TEXT_FIELD
463
+ },
464
+ {
465
+ name: 'backgroundColor',
466
+ label: 'Button color',
467
+ description: 'The fill behind the label. Check it against the label color — a ' + 'button nobody can read is a link nobody clicks.',
468
+ component: Aglyn.FieldComponentType.COLOR_PICKER
469
+ },
470
+ {
471
+ name: 'color',
472
+ label: 'Label color',
473
+ description: 'The color of the words on the button.',
474
+ component: Aglyn.FieldComponentType.COLOR_PICKER
475
+ },
476
+ {
477
+ name: 'align',
478
+ label: 'Alignment',
479
+ description: 'Where the button sits across the width of the section.',
480
+ component: Aglyn.FieldComponentType.SELECT,
481
+ options: [
482
+ {
483
+ value: 'left',
484
+ label: 'Left'
485
+ },
486
+ {
487
+ value: 'center',
488
+ label: 'Center'
489
+ },
490
+ {
491
+ value: 'right',
492
+ label: 'Right'
493
+ }
494
+ ]
495
+ }
496
+ ]
497
+ };
498
+ // ---------------------------------------------------------------- divider
499
+ export const DIVIDER_ID = 'emailDivider';
500
+ export const EmailDivider = /*#__PURE__*/ forwardRef((props, ref)=>{
501
+ const { color, sx } = props, rest = _object_without_properties_loose(props, [
502
+ "color",
503
+ "sx"
504
+ ]);
505
+ return /*#__PURE__*/ _jsx(Box, _extends({
506
+ ref: ref,
507
+ component: "hr"
508
+ }, rest, {
509
+ sx: mergeSxProps({
510
+ border: 0,
511
+ // Split shorthand so a palette token path from the theme-
512
+ // reference color picker (AGL-588) resolves through the sx
513
+ // system instead of dying inside a template string.
514
+ borderTopStyle: 'solid',
515
+ borderTopWidth: 1,
516
+ borderTopColor: color || '#e0e0e0',
517
+ my: 2
518
+ }, sx)
519
+ }));
520
+ });
521
+ EmailDivider.displayName = 'EmailDivider';
522
+ export const emailDividerSchema = {
523
+ $id: DIVIDER_ID,
524
+ pluginId: BUNDLE_ID,
525
+ displayName: 'Email divider',
526
+ description: 'A horizontal rule between email sections.',
527
+ category: Aglyn.ComponentCategory.LAYOUT,
528
+ icon: {
529
+ path: mdiMinus.path,
530
+ sx: {
531
+ color: '#f57c00'
532
+ }
533
+ },
534
+ flags: {
535
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
536
+ },
537
+ attributes: [
538
+ {
539
+ name: 'color',
540
+ label: 'Line color',
541
+ description: 'The color of the rule. A light grey separates sections without ' + 'drawing the eye to the line itself.',
542
+ component: Aglyn.FieldComponentType.COLOR_PICKER
543
+ }
544
+ ]
545
+ };
546
+ // ----------------------------------------------------------------- spacer
547
+ export const SPACER_ID = 'emailSpacer';
548
+ export const EmailSpacer = /*#__PURE__*/ forwardRef((props, ref)=>{
549
+ const { height, sx } = props, rest = _object_without_properties_loose(props, [
550
+ "height",
551
+ "sx"
552
+ ]);
553
+ return /*#__PURE__*/ _jsx(Box, _extends({
554
+ ref: ref
555
+ }, rest, {
556
+ sx: mergeSxProps({
557
+ height: height != null ? height : 24
558
+ }, sx)
559
+ }));
560
+ });
561
+ EmailSpacer.displayName = 'EmailSpacer';
562
+ export const emailSpacerSchema = {
563
+ $id: SPACER_ID,
564
+ pluginId: BUNDLE_ID,
565
+ displayName: 'Email spacer',
566
+ description: 'Fixed vertical whitespace between email blocks.',
567
+ category: Aglyn.ComponentCategory.LAYOUT,
568
+ icon: {
569
+ path: mdiArrowExpandVertical.path,
570
+ sx: {
571
+ color: '#f57c00'
572
+ }
573
+ },
574
+ flags: {
575
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
576
+ },
577
+ attributes: [
578
+ {
579
+ name: 'height',
580
+ label: 'Height (px)',
581
+ description: 'How much empty vertical space this block adds. Email clients drop ' + 'CSS margins, so a spacer is how you get reliable breathing room.',
582
+ component: Aglyn.FieldComponentType.TEXT_FIELD,
583
+ type: 'number'
584
+ }
585
+ ]
586
+ };
587
+ // ---------------------------------------------------------------- product
588
+ export const PRODUCT_ID = 'emailProduct';
589
+ export const EmailProduct = /*#__PURE__*/ forwardRef((props, ref)=>{
590
+ const { productId, buttonLabel, sx } = props, rest = _object_without_properties_loose(props, [
591
+ "productId",
592
+ "buttonLabel",
593
+ "sx"
594
+ ]);
595
+ return /*#__PURE__*/ _jsxs(Box, _extends({
596
+ ref: ref
597
+ }, rest, {
598
+ sx: mergeSxProps({
599
+ border: '1px solid',
600
+ borderColor: 'divider',
601
+ borderRadius: 1,
602
+ p: 2,
603
+ my: 1,
604
+ textAlign: 'center',
605
+ color: 'text.secondary',
606
+ fontSize: 13
607
+ }, sx),
608
+ children: [
609
+ productId ? `Product card (${productId}) — name, price, image fill in at send` : 'Product card — pick a product in the attributes panel',
610
+ /*#__PURE__*/ _jsx(Box, {
611
+ sx: {
612
+ mt: 1,
613
+ fontWeight: 600
614
+ },
615
+ children: buttonLabel != null ? buttonLabel : 'Shop now'
616
+ })
617
+ ]
618
+ }));
619
+ });
620
+ EmailProduct.displayName = 'EmailProduct';
621
+ export const emailProductSchema = {
622
+ $id: PRODUCT_ID,
623
+ pluginId: BUNDLE_ID,
624
+ displayName: 'Email product',
625
+ description: 'A product card resolved at send time, so it never goes stale.',
626
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
627
+ icon: {
628
+ path: mdiPackageVariantClosed.path,
629
+ sx: {
630
+ color: '#f57c00'
631
+ }
632
+ },
633
+ flags: {
634
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
635
+ },
636
+ attributes: [
637
+ {
638
+ name: 'productId',
639
+ label: 'Product',
640
+ description: 'Stored by id — the current name, price, and image render at send.',
641
+ component: Aglyn.FieldComponentType.PRODUCT_SELECT
642
+ },
643
+ {
644
+ name: 'buttonLabel',
645
+ label: 'Button label',
646
+ description: 'The words on the card’s button. Blank uses the block’s default, ' + 'and the link always points at this product’s page.',
647
+ component: Aglyn.FieldComponentType.TEXT_FIELD
648
+ }
649
+ ]
650
+ };
651
+ // ------------------------------------------------------------ custom html
652
+ export const HTML_ID = 'emailHtml';
653
+ export const EmailHtml = /*#__PURE__*/ forwardRef((props, ref)=>{
654
+ const { html, sx } = props, rest = _object_without_properties_loose(props, [
655
+ "html",
656
+ "sx"
657
+ ]);
658
+ return /*#__PURE__*/ _jsx(Box, _extends({
659
+ ref: ref
660
+ }, rest, {
661
+ sx: mergeSxProps({
662
+ fontFamily: 'Helvetica, Arial, sans-serif'
663
+ }, sx),
664
+ // No `typeof window` guard any more (AGL-1901): the sanitizer needs
665
+ // no DOM, so a server-rendered email keeps its custom HTML.
666
+ dangerouslySetInnerHTML: {
667
+ __html: html ? sanitizeAuthorHtml(html) : ''
668
+ }
669
+ }));
670
+ });
671
+ EmailHtml.displayName = 'EmailHtml';
672
+ export const emailHtmlSchema = {
673
+ $id: HTML_ID,
674
+ pluginId: BUNDLE_ID,
675
+ displayName: 'Email custom HTML',
676
+ description: 'Hand-written HTML for an email, used as-is.',
677
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
678
+ icon: {
679
+ path: mdiCodeTags.path,
680
+ sx: {
681
+ color: '#f57c00'
682
+ }
683
+ },
684
+ flags: {
685
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
686
+ },
687
+ attributes: [
688
+ {
689
+ name: 'html',
690
+ label: 'HTML',
691
+ description: 'Raw table markup for advanced layouts. Sanitized with the ' + 'custom-html policy; the render pipeline passes it through as-is ' + 'after sanitization.',
692
+ component: Aglyn.FieldComponentType.TEXTAREA
693
+ }
694
+ ]
695
+ };
696
+ export const emailPresets = [
697
+ {
698
+ $id: generatePresetId(SECTION_ID),
699
+ type: Aglyn.NodeType.PRESET,
700
+ displayName: 'Email section',
701
+ pluginId: BUNDLE_ID,
702
+ category: Aglyn.ComponentCategory.LAYOUT,
703
+ icon: {
704
+ path: mdiEmailOutline.path,
705
+ sx: {
706
+ color: '#f57c00'
707
+ }
708
+ },
709
+ data: {
710
+ $id: null,
711
+ componentId: SECTION_ID,
712
+ pluginId: BUNDLE_ID,
713
+ props: {}
714
+ }
715
+ },
716
+ {
717
+ $id: generatePresetId(TEXT_ID),
718
+ type: Aglyn.NodeType.PRESET,
719
+ displayName: 'Email text',
720
+ pluginId: BUNDLE_ID,
721
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
722
+ icon: {
723
+ path: mdiFormatText.path,
724
+ sx: {
725
+ color: '#f57c00'
726
+ }
727
+ },
728
+ data: {
729
+ $id: null,
730
+ componentId: TEXT_ID,
731
+ pluginId: BUNDLE_ID,
732
+ props: {
733
+ children: 'Hello {{contact.firstName}},',
734
+ variant: 'body'
735
+ }
736
+ }
737
+ },
738
+ {
739
+ $id: generatePresetId(RICHTEXT_ID),
740
+ type: Aglyn.NodeType.PRESET,
741
+ displayName: 'Email rich text',
742
+ pluginId: BUNDLE_ID,
743
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
744
+ icon: {
745
+ path: mdiCardTextOutline.path,
746
+ sx: {
747
+ color: '#f57c00'
748
+ }
749
+ },
750
+ data: {
751
+ $id: null,
752
+ componentId: RICHTEXT_ID,
753
+ pluginId: BUNDLE_ID,
754
+ props: {}
755
+ }
756
+ },
757
+ {
758
+ $id: generatePresetId(IMAGE_ID),
759
+ type: Aglyn.NodeType.PRESET,
760
+ displayName: 'Email image',
761
+ pluginId: BUNDLE_ID,
762
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
763
+ icon: {
764
+ path: mdiImageOutline.path,
765
+ sx: {
766
+ color: '#f57c00'
767
+ }
768
+ },
769
+ data: {
770
+ $id: null,
771
+ componentId: IMAGE_ID,
772
+ pluginId: BUNDLE_ID,
773
+ props: {}
774
+ }
775
+ },
776
+ {
777
+ $id: generatePresetId(BUTTON_ID),
778
+ type: Aglyn.NodeType.PRESET,
779
+ displayName: 'Email button',
780
+ pluginId: BUNDLE_ID,
781
+ category: Aglyn.ComponentCategory.INPUT,
782
+ icon: {
783
+ path: mdiGestureTapButton.path,
784
+ sx: {
785
+ color: '#f57c00'
786
+ }
787
+ },
788
+ data: {
789
+ $id: null,
790
+ componentId: BUTTON_ID,
791
+ pluginId: BUNDLE_ID,
792
+ props: {
793
+ children: 'Shop now'
794
+ }
795
+ }
796
+ },
797
+ {
798
+ $id: generatePresetId(DIVIDER_ID),
799
+ type: Aglyn.NodeType.PRESET,
800
+ displayName: 'Email divider',
801
+ pluginId: BUNDLE_ID,
802
+ category: Aglyn.ComponentCategory.LAYOUT,
803
+ icon: {
804
+ path: mdiMinus.path,
805
+ sx: {
806
+ color: '#f57c00'
807
+ }
808
+ },
809
+ data: {
810
+ $id: null,
811
+ componentId: DIVIDER_ID,
812
+ pluginId: BUNDLE_ID,
813
+ props: {}
814
+ }
815
+ },
816
+ {
817
+ $id: generatePresetId(SPACER_ID),
818
+ type: Aglyn.NodeType.PRESET,
819
+ displayName: 'Email spacer',
820
+ pluginId: BUNDLE_ID,
821
+ category: Aglyn.ComponentCategory.LAYOUT,
822
+ icon: {
823
+ path: mdiArrowExpandVertical.path,
824
+ sx: {
825
+ color: '#f57c00'
826
+ }
827
+ },
828
+ data: {
829
+ $id: null,
830
+ componentId: SPACER_ID,
831
+ pluginId: BUNDLE_ID,
832
+ props: {}
833
+ }
834
+ },
835
+ {
836
+ $id: generatePresetId(PRODUCT_ID),
837
+ type: Aglyn.NodeType.PRESET,
838
+ displayName: 'Email product',
839
+ pluginId: BUNDLE_ID,
840
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
841
+ icon: {
842
+ path: mdiPackageVariantClosed.path,
843
+ sx: {
844
+ color: '#f57c00'
845
+ }
846
+ },
847
+ data: {
848
+ $id: null,
849
+ componentId: PRODUCT_ID,
850
+ pluginId: BUNDLE_ID,
851
+ props: {}
852
+ }
853
+ },
854
+ {
855
+ $id: generatePresetId(HTML_ID),
856
+ type: Aglyn.NodeType.PRESET,
857
+ displayName: 'Email custom HTML',
858
+ pluginId: BUNDLE_ID,
859
+ category: Aglyn.ComponentCategory.DATA_DISPLAY,
860
+ icon: {
861
+ path: mdiCodeTags.path,
862
+ sx: {
863
+ color: '#f57c00'
864
+ }
865
+ },
866
+ data: {
867
+ $id: null,
868
+ componentId: HTML_ID,
869
+ pluginId: BUNDLE_ID,
870
+ props: {}
871
+ }
872
+ }
873
+ ];
874
+
875
+ //# sourceMappingURL=email-blocks.js.map