@kgalexander/mcreate 1.0.9 → 1.0.12

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.
@@ -142,6 +142,57 @@ var SOCIAL_OPTIONS = [
142
142
  }
143
143
  ];
144
144
 
145
+ // src/core/editor/constant/fonts.ts
146
+ var emailSafeFonts = [
147
+ { name: "Arial", value: "arial" },
148
+ { name: "Helvetica", value: "helvetica" },
149
+ { name: "Times New Roman", value: "times-new-roman" },
150
+ { name: "Tahoma", value: "tahoma" },
151
+ { name: "Trebuchet MS", value: "trebuchet-ms" },
152
+ { name: "Lucida Console", value: "lucida-console" },
153
+ { name: "Courier New", value: "courier-new" },
154
+ { name: "Georgia", value: "georgia" },
155
+ { name: "Verdana", value: "verdana" }
156
+ ];
157
+ var OtherFonts = [
158
+ { name: "Abril Fatface", value: "abril-fatface-regular", url: "https://fonts.googleapis.com/css?family=Abril+Fatface" },
159
+ { name: "Alegreya", value: "alegreya", url: "https://fonts.googleapis.com/css?family=Alegreya" },
160
+ { name: "Alegreya Sans", value: "alegreya-sans", url: "https://fonts.googleapis.com/css?family=Alegreya+Sans" },
161
+ { name: "Anton", value: "anton", url: "https://fonts.googleapis.com/css?family=Anton" },
162
+ { name: "Arimo", value: "arimo", url: "https://fonts.googleapis.com/css?family=Arimo" },
163
+ { name: "Arvo", value: "arvo", url: "https://fonts.googleapis.com/css?family=Arvo" },
164
+ { name: "Catamaran", value: "catamaran", url: "https://fonts.googleapis.com/css?family=Catamaran" },
165
+ { name: "Comic Neue", value: "comic-neue", url: "https://fonts.googleapis.com/css?family=Comic+Neue" },
166
+ { name: "Della Respira", value: "della-respira", url: "https://fonts.googleapis.com/css2?family=Della+Respira&display=swap" },
167
+ { name: "DM Sans", value: "dm-sans", url: "https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700&display=swap" },
168
+ { name: "Gilda Display", value: "gilda-display", url: "https://fonts.googleapis.com/css2?family=Gilda+Display&display=swap" },
169
+ { name: "Lato", value: "lato", url: "https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap" },
170
+ { name: "Lora", value: "lora", url: "https://fonts.googleapis.com/css2?family=Lora:wght@400;500;600;700&display=swap" },
171
+ { name: "Marcellus", value: "marcellus", url: "https://fonts.googleapis.com/css2?family=Marcellus&display=swap" },
172
+ { name: "Merriweather", value: "merriweather", url: "https://fonts.googleapis.com/css2?family=Merriweather:wght@300;400;700&display=swap" },
173
+ { name: "Merriweather Sans", value: "merriweather-sans", url: "https://fonts.googleapis.com/css2?family=Merriweather+Sans:wght@300;400;500;600;700&display=swap" },
174
+ { name: "Nanum Gothic Coding", value: "nanum-gothic-coding", url: "https://fonts.googleapis.com/css2?family=Nanum+Gothic+Coding:wght@400;700&display=swap" },
175
+ { name: "Neuton", value: "neuton", url: "https://fonts.googleapis.com/css2?family=Neuton:wght@300;400;700&display=swap" },
176
+ { name: "Noticia Text", value: "noticia-text", url: "https://fonts.googleapis.com/css2?family=Noticia+Text:wght@400;700&display=swap" },
177
+ { name: "Noto Sans", value: "noto-sans", url: "https://fonts.googleapis.com/css2?family=Noto+Sans:wght@300;400;500;600;700&display=swap" },
178
+ { name: "Open Sans", value: "open-sans", url: "https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap" },
179
+ { name: "Playfair Display", value: "playfair-display", url: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&display=swap" },
180
+ { name: "Raleway", value: "raleway", url: "https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;500;600;700&display=swap" },
181
+ { name: "Recursive", value: "recursive", url: "https://fonts.googleapis.com/css2?family=Recursive:wght@300;400;500;600;700&display=swap" },
182
+ { name: "Roboto", value: "roboto", url: "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" },
183
+ { name: "Source Sans 3", value: "source-sans-3", url: "https://fonts.googleapis.com/css2?family=Source+Sans+3:wght@300;400;500;600;700&display=swap" },
184
+ { name: "Source Code Pro", value: "source-code-pro", url: "https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@300;400;500;600;700&display=swap" },
185
+ { name: "Space Mono", value: "space-mono", url: "https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" },
186
+ { name: "Syncopate", value: "syncopate", url: "https://fonts.googleapis.com/css2?family=Syncopate:wght@400;700&display=swap" },
187
+ { name: "Work Sans", value: "work-sans", url: "https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400;500;600;700&display=swap" }
188
+ ];
189
+ function getGoogleFont(fontName) {
190
+ return OtherFonts.find((f) => f.name.toLowerCase() === fontName.toLowerCase());
191
+ }
192
+ function getGoogleFontUrl(fontName) {
193
+ return getGoogleFont(fontName)?.url;
194
+ }
195
+
145
196
  // src/core/editor/utils/border.ts
146
197
  var DEFAULT_BORDER = {
147
198
  width: 0,
@@ -222,16 +273,6 @@ var ALIGNMENT_ICONS = {
222
273
  center: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-center.svg",
223
274
  right: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-right.svg"
224
275
  };
225
- var FONTS = [
226
- "Arial",
227
- "Helvetica",
228
- "Times New Roman",
229
- "Courier New",
230
- "Verdana",
231
- "Tahoma",
232
- "Trebuchet MS",
233
- "Georgia"
234
- ];
235
276
  var TEXT_ALIGNMENT_ICONS = {
236
277
  left: AlignLeftIcon,
237
278
  center: AlignCenterIcon,
@@ -1120,6 +1161,35 @@ function rootChildrenToMjml(children, parentContext) {
1120
1161
  return "";
1121
1162
  }).join("\n");
1122
1163
  }
1164
+ function collectUsedGoogleFonts(template) {
1165
+ const fontNames = /* @__PURE__ */ new Set();
1166
+ const googleFontNames = new Set(OtherFonts.map((f) => f.name.toLowerCase()));
1167
+ function extractFromFontFamily(fontFamily) {
1168
+ if (!fontFamily) return;
1169
+ const fonts = fontFamily.split(",").map((f) => f.trim().replace(/['"]/g, ""));
1170
+ for (const f of fonts) {
1171
+ if (googleFontNames.has(f.toLowerCase())) {
1172
+ const original = OtherFonts.find((of) => of.name.toLowerCase() === f.toLowerCase());
1173
+ if (original) fontNames.add(original.name);
1174
+ }
1175
+ }
1176
+ }
1177
+ function scanElement(el) {
1178
+ if (!el) return;
1179
+ extractFromFontFamily(el.attributes?.["font-family"]);
1180
+ const content = el.data?.value?.content;
1181
+ if (typeof content === "string") {
1182
+ const matches = content.matchAll(/font-family:\s*([^;"]+)/gi);
1183
+ for (const m of matches) extractFromFontFamily(m[1]);
1184
+ }
1185
+ if (Array.isArray(el.children)) el.children.forEach(scanElement);
1186
+ }
1187
+ template.content.forEach(scanElement);
1188
+ return [...fontNames].map((name) => {
1189
+ const url = getGoogleFontUrl(name);
1190
+ return url ? { name, url } : null;
1191
+ }).filter((f) => f !== null);
1192
+ }
1123
1193
  function json2mjml(template, mode = "production", options = {}) {
1124
1194
  const showCompanyFooter = template.content[0]?.data?.value?.showCompanyFooter ?? true;
1125
1195
  const footerMutation = needsCompanyFooterMutation(template);
@@ -1165,12 +1235,17 @@ function json2mjml(template, mode = "production", options = {}) {
1165
1235
  allContent += pageContent;
1166
1236
  }
1167
1237
  const linkColor = template.content[0]?.data?.value?.linkColor || "#0000ff";
1238
+ const usedGoogleFonts = collectUsedGoogleFonts(template);
1239
+ const mjFontTags = usedGoogleFonts.map((f) => `<mj-font name="${f.name}" href="${f.url}" />`).join("\n ");
1168
1240
  return `
1169
1241
  <mjml>
1170
1242
 
1171
1243
  <mj-head>
1172
1244
 
1173
1245
  <mj-breakpoint width="480px" />
1246
+ <mj-preview>${options.previewText ?? template?.preview ?? ""}</mj-preview>
1247
+
1248
+ ${mjFontTags}
1174
1249
 
1175
1250
  <mj-style>
1176
1251
  p { margin: 0px 0px 0px 0px !important; }
@@ -3527,6 +3602,26 @@ var ShadowDomRenderer = memo(function ShadowDomRenderer2({
3527
3602
  shadowRootRef.current.appendChild(styleEl);
3528
3603
  shadowRootRef.current.appendChild(contentWrapper);
3529
3604
  }, [html]);
3605
+ useEffect(() => {
3606
+ const templateState = useEditorStore.getState().template;
3607
+ if (!templateState) return;
3608
+ const htmlStr = html + JSON.stringify(templateState);
3609
+ const neededUrls = /* @__PURE__ */ new Set();
3610
+ for (const font of OtherFonts) {
3611
+ if (font.url && htmlStr.includes(font.name)) {
3612
+ neededUrls.add(font.url);
3613
+ }
3614
+ }
3615
+ for (const url of neededUrls) {
3616
+ if (!document.querySelector(`link[data-google-font][href="${url}"]`)) {
3617
+ const link = document.createElement("link");
3618
+ link.rel = "stylesheet";
3619
+ link.href = url;
3620
+ link.setAttribute("data-google-font", "true");
3621
+ document.head.appendChild(link);
3622
+ }
3623
+ }
3624
+ }, [html]);
3530
3625
  useEffect(() => {
3531
3626
  if (!shadowRootRef.current) return;
3532
3627
  const styleEl = shadowRootRef.current.querySelector("#editor-styles");
@@ -12942,13 +13037,14 @@ import { MoreHorizontalIcon as MoreHorizontalIcon3, PlusCircleIcon } from "lucid
12942
13037
  import { createContext, useContext, useState as useState5 } from "react";
12943
13038
  import { jsx as jsx31 } from "react/jsx-runtime";
12944
13039
  var SidebarContext = createContext(null);
12945
- var PICKER_VIEWS = ["color", "images", "add-social"];
13040
+ var PICKER_VIEWS = ["color", "images", "add-social", "fonts"];
12946
13041
  function SidebarProvider({ children }) {
12947
13042
  const [activeView, setActiveViewState] = useState5("elements");
12948
13043
  const [lastView, setLastView] = useState5("elements");
12949
13044
  const [colorType, setColorType] = useState5("Color");
12950
13045
  const [colorTarget, setColorTarget] = useState5(null);
12951
13046
  const [imageTarget, setImageTarget] = useState5(null);
13047
+ const [fontTarget, setFontTarget] = useState5(null);
12952
13048
  const setActiveView = (view) => {
12953
13049
  if (view !== activeView) {
12954
13050
  if (!PICKER_VIEWS.includes(activeView)) {
@@ -12957,7 +13053,7 @@ function SidebarProvider({ children }) {
12957
13053
  }
12958
13054
  setActiveViewState(view);
12959
13055
  };
12960
- return /* @__PURE__ */ jsx31(SidebarContext.Provider, { value: { activeView, setActiveView, lastView, colorType, setColorType, colorTarget, setColorTarget, imageTarget, setImageTarget }, children });
13056
+ return /* @__PURE__ */ jsx31(SidebarContext.Provider, { value: { activeView, setActiveView, lastView, colorType, setColorType, colorTarget, setColorTarget, imageTarget, setImageTarget, fontTarget, setFontTarget }, children });
12961
13057
  }
12962
13058
  function useSidebarContext() {
12963
13059
  const context = useContext(SidebarContext);
@@ -16036,13 +16132,14 @@ export {
16036
16132
  getParentByIdx,
16037
16133
  SOCIAL_ITEMS,
16038
16134
  SOCIAL_OPTIONS,
16135
+ emailSafeFonts,
16136
+ OtherFonts,
16039
16137
  parseBorder,
16040
16138
  formatBorder,
16041
16139
  parsePrice,
16042
16140
  MAX_TEMPLATE_SIZE,
16043
16141
  BUTTON_ALIGNMENTS,
16044
16142
  ALIGNMENT_ICONS,
16045
- FONTS,
16046
16143
  TEXT_ALIGNMENT_ICONS,
16047
16144
  TEXT_TYPE_OPTIONS,
16048
16145
  DEFAULT_FONT_SIZE,
@@ -5,7 +5,7 @@ import {
5
5
  MAILLOW_EMAIL_EDITOR_VERSION,
6
6
  Preview,
7
7
  useEditorStore
8
- } from "./chunk-R3LRNUKL.mjs";
8
+ } from "./chunk-RKZFFE24.mjs";
9
9
  export {
10
10
  Editor,
11
11
  History,
package/dist/index.d.mts CHANGED
@@ -254,6 +254,7 @@ type TemplateJSON = {
254
254
  id: string;
255
255
  name: string;
256
256
  image: string;
257
+ preview: string;
257
258
  version: string;
258
259
  published: boolean;
259
260
  creator: string;
@@ -320,6 +321,14 @@ declare function TemplatePage({ templateId, initialTemplate, onSave, onToast, on
320
321
 
321
322
  declare const MAX_TEMPLATE_SIZE: number;
322
323
 
324
+ type FontEntry = {
325
+ name: string;
326
+ value: string;
327
+ url?: string;
328
+ };
329
+ declare const emailSafeFonts: FontEntry[];
330
+ declare const OtherFonts: FontEntry[];
331
+
323
332
  interface MergeFieldType {
324
333
  label: string;
325
334
  value: string;
@@ -360,6 +369,7 @@ declare function campaign_validation_warnings(): {
360
369
  type RenderMode = 'production' | 'editing';
361
370
  interface RenderOptions {
362
371
  isPaidLevel?: number;
372
+ previewText?: string;
363
373
  }
364
374
  /**
365
375
  * Convert template JSON to MJML string
@@ -370,4 +380,4 @@ interface RenderOptions {
370
380
  */
371
381
  declare function json2mjml(template: TemplateJSON, mode?: RenderMode, options?: RenderOptions): string;
372
382
 
373
- export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type MergeFieldType, type MissingLinkType, type OnDeleteCallback, type OnDuplicateCallback, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, type PaidLevel, type PreviewValidationType, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, campaign_validation_warnings, json2mjml, validate_campaign_onCreate, validate_editor_onPreview };
383
+ export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type MergeFieldType, type MissingLinkType, type OnDeleteCallback, type OnDuplicateCallback, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, OtherFonts, type PaidLevel, type PreviewValidationType, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, campaign_validation_warnings, emailSafeFonts, json2mjml, validate_campaign_onCreate, validate_editor_onPreview };
package/dist/index.d.ts CHANGED
@@ -254,6 +254,7 @@ type TemplateJSON = {
254
254
  id: string;
255
255
  name: string;
256
256
  image: string;
257
+ preview: string;
257
258
  version: string;
258
259
  published: boolean;
259
260
  creator: string;
@@ -320,6 +321,14 @@ declare function TemplatePage({ templateId, initialTemplate, onSave, onToast, on
320
321
 
321
322
  declare const MAX_TEMPLATE_SIZE: number;
322
323
 
324
+ type FontEntry = {
325
+ name: string;
326
+ value: string;
327
+ url?: string;
328
+ };
329
+ declare const emailSafeFonts: FontEntry[];
330
+ declare const OtherFonts: FontEntry[];
331
+
323
332
  interface MergeFieldType {
324
333
  label: string;
325
334
  value: string;
@@ -360,6 +369,7 @@ declare function campaign_validation_warnings(): {
360
369
  type RenderMode = 'production' | 'editing';
361
370
  interface RenderOptions {
362
371
  isPaidLevel?: number;
372
+ previewText?: string;
363
373
  }
364
374
  /**
365
375
  * Convert template JSON to MJML string
@@ -370,4 +380,4 @@ interface RenderOptions {
370
380
  */
371
381
  declare function json2mjml(template: TemplateJSON, mode?: RenderMode, options?: RenderOptions): string;
372
382
 
373
- export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type MergeFieldType, type MissingLinkType, type OnDeleteCallback, type OnDuplicateCallback, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, type PaidLevel, type PreviewValidationType, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, campaign_validation_warnings, json2mjml, validate_campaign_onCreate, validate_editor_onPreview };
383
+ export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type MergeFieldType, type MissingLinkType, type OnDeleteCallback, type OnDuplicateCallback, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, OtherFonts, type PaidLevel, type PreviewValidationType, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, campaign_validation_warnings, emailSafeFonts, json2mjml, validate_campaign_onCreate, validate_editor_onPreview };