@ivanholiak/easy-email-extensions 4.16.9 → 4.16.11

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.
@@ -0,0 +1,3 @@
1
+ export declare const GOOGLE_FONTS: string[];
2
+ export declare function loadGoogleFont(fontFamily: string): void;
3
+ export declare function loadGoogleFontsPreview(fontFamilies: string[]): void;
package/lib/index2.js CHANGED
@@ -52,7 +52,7 @@ var __async = (__this, __arguments, generator) => {
52
52
  };
53
53
  import * as React$1 from "react";
54
54
  import React__default, { createContext, useContext, isValidElement, Children, cloneElement, Component, useRef, useMemo, memo, forwardRef, createRef, useState, useImperativeHandle, useEffect, useLayoutEffect, useCallback, PureComponent, useReducer, Fragment, Suspense } from "react";
55
- import { IconFont, useEditorProps, Stack as Stack$4, useRefState, getShadowRoot, DATA_CONTENT_EDITABLE_TYPE, ContentEditableType, TextStyle, useEditorContext, useBlock, useFocusIdx, DATA_CONTENT_EDITABLE_IDX, useFocusBlockLayout, MergeTagBadge, AvailableTools, FIXED_CONTAINER_ID, getPluginElement, RICH_TEXT_BAR_ID, CONTENT_EDITABLE_CLASS_NAME, getEditorRoot, scrollBlockEleIntoView, useHoverIdx, useDataTransfer, getBlockNodeByChildEle, getDirectionPosition, DATA_ATTRIBUTE_DROP_CONTAINER, BlockAvatarWrapper, isTextBlock, getBlockNodeByIdx, useLazyState, useActiveTab, ActiveTabKeys } from "@ivanholiak/easy-email-editor";
55
+ import { IconFont, useEditorProps, Stack as Stack$4, useRefState, getShadowRoot, DATA_CONTENT_EDITABLE_TYPE, ContentEditableType, MergeTagBadge, TextStyle, useEditorContext, useBlock, useFocusIdx, DATA_CONTENT_EDITABLE_IDX, useFocusBlockLayout, AvailableTools, FIXED_CONTAINER_ID, getPluginElement, RICH_TEXT_BAR_ID, CONTENT_EDITABLE_CLASS_NAME, getEditorRoot, scrollBlockEleIntoView, useHoverIdx, useDataTransfer, getBlockNodeByChildEle, getDirectionPosition, DATA_ATTRIBUTE_DROP_CONTAINER, BlockAvatarWrapper, isTextBlock, getBlockNodeByIdx, useLazyState, useActiveTab, ActiveTabKeys } from "@ivanholiak/easy-email-editor";
56
56
  import { BasicType, ImageManager, EMAIL_BLOCK_CLASS_NAME, BlockManager, createBlockDataByType, AdvancedType, Operator, OperatorSymbol, isAdvancedBlock, getParentByIdx, getParentIdx, getIndexByIdx, getSiblingIdx, getNodeIdxFromClassName, getNodeIdxClassName, getPageIdx, getChildIdx, JsonToMjml, getNodeTypeFromClassName } from "@ivanholiak/easy-email-core";
57
57
  import ReactDOM$1, { createPortal } from "react-dom";
58
58
  import { Field, useForm as useForm$1, useField, Form as Form$3, version as version$2, useFormState as useFormState$2 } from "react-final-form";
@@ -35980,6 +35980,7 @@ function InlineText({ idx, onChange, children }) {
35980
35980
  const {
35981
35981
  mutators: { setFieldTouched }
35982
35982
  } = useForm$1();
35983
+ const { enabledMergeTagsBadge, mergeTagGenerate } = useEditorProps();
35983
35984
  useField(idx);
35984
35985
  useEffect(() => {
35985
35986
  const shadowRoot = getShadowRoot();
@@ -36008,13 +36009,57 @@ function InlineText({ idx, onChange, children }) {
36008
36009
  }
36009
36010
  }
36010
36011
  };
36012
+ const onDrop = (e2) => {
36013
+ var _a2, _b2, _c;
36014
+ const target2 = e2.target;
36015
+ if (!target2 || !target2.getAttribute("contenteditable"))
36016
+ return;
36017
+ const mergeTagText = ((_a2 = e2.dataTransfer) == null ? void 0 : _a2.getData("text/merge-tag")) || ((_b2 = e2.dataTransfer) == null ? void 0 : _b2.getData("text/plain"));
36018
+ if (mergeTagText && (mergeTagText.startsWith("{{") || mergeTagText.includes("{{"))) {
36019
+ e2.preventDefault();
36020
+ e2.stopPropagation();
36021
+ const contentEditableType = target2.getAttribute(DATA_CONTENT_EDITABLE_TYPE);
36022
+ let insertText = mergeTagText;
36023
+ if (enabledMergeTagsBadge && mergeTagGenerate) {
36024
+ const match = mergeTagText.match(/{{([^}]+)}}/);
36025
+ if (match && match[1]) {
36026
+ const mergeTagKey = match[1].trim();
36027
+ const generatedTag = mergeTagGenerate(mergeTagKey);
36028
+ insertText = MergeTagBadge.transform(generatedTag);
36029
+ } else {
36030
+ insertText = MergeTagBadge.transform(mergeTagText);
36031
+ }
36032
+ }
36033
+ document.execCommand("insertHTML", false, insertText);
36034
+ if (contentEditableType === ContentEditableType.RichText) {
36035
+ onChange(target2.innerHTML || "");
36036
+ } else if (contentEditableType === ContentEditableType.Text) {
36037
+ onChange(((_c = target2.textContent) == null ? void 0 : _c.trim()) || "");
36038
+ }
36039
+ }
36040
+ };
36041
+ const onDragOver = (e2) => {
36042
+ var _a2, _b2;
36043
+ const target2 = e2.target;
36044
+ if (target2 && target2.getAttribute("contenteditable")) {
36045
+ const mergeTagText = ((_a2 = e2.dataTransfer) == null ? void 0 : _a2.getData("text/merge-tag")) || ((_b2 = e2.dataTransfer) == null ? void 0 : _b2.getData("text/plain"));
36046
+ if (mergeTagText && (mergeTagText.startsWith("{{") || mergeTagText.includes("{{"))) {
36047
+ e2.preventDefault();
36048
+ e2.dataTransfer.dropEffect = "copy";
36049
+ }
36050
+ }
36051
+ };
36011
36052
  shadowRoot.addEventListener("paste", onPaste, true);
36012
36053
  shadowRoot.addEventListener("input", onInput);
36054
+ shadowRoot.addEventListener("drop", onDrop, true);
36055
+ shadowRoot.addEventListener("dragover", onDragOver, true);
36013
36056
  return () => {
36014
36057
  shadowRoot.removeEventListener("paste", onPaste, true);
36015
36058
  shadowRoot.removeEventListener("input", onInput);
36059
+ shadowRoot.removeEventListener("drop", onDrop, true);
36060
+ shadowRoot.removeEventListener("dragover", onDragOver, true);
36016
36061
  };
36017
- }, [onChange, setFieldTouched]);
36062
+ }, [onChange, setFieldTouched, enabledMergeTagsBadge, mergeTagGenerate]);
36018
36063
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children);
36019
36064
  }
36020
36065
  function AutoComplete(props) {
@@ -38056,18 +38101,289 @@ function Link$1(props) {
38056
38101
  }));
38057
38102
  });
38058
38103
  }
38104
+ const GOOGLE_FONTS = [
38105
+ "ABeeZee",
38106
+ "Abel",
38107
+ "Abril Fatface",
38108
+ "Acme",
38109
+ "Alata",
38110
+ "Alegreya",
38111
+ "Alegreya Sans",
38112
+ "Alfa Slab One",
38113
+ "Alice",
38114
+ "Alike",
38115
+ "Allan",
38116
+ "Amiri",
38117
+ "Anek Latin",
38118
+ "Anton",
38119
+ "Architects Daughter",
38120
+ "Archivo",
38121
+ "Archivo Black",
38122
+ "Archivo Narrow",
38123
+ "Arimo",
38124
+ "Arsenal",
38125
+ "Arvo",
38126
+ "Asap",
38127
+ "Asap Condensed",
38128
+ "Assistant",
38129
+ "Babylonica",
38130
+ "Balsamiq Sans",
38131
+ "Bangers",
38132
+ "Barlow",
38133
+ "Barlow Condensed",
38134
+ "Barlow Semi Condensed",
38135
+ "Be Vietnam Pro",
38136
+ "Bebas Neue",
38137
+ "Bitter",
38138
+ "Black Ops One",
38139
+ "Bodoni Moda",
38140
+ "Bree Serif",
38141
+ "Cabin",
38142
+ "Cairo",
38143
+ "Cantarell",
38144
+ "Cardo",
38145
+ "Catamaran",
38146
+ "Caveat",
38147
+ "Chakra Petch",
38148
+ "Chivo",
38149
+ "Cinzel",
38150
+ "Comfortaa",
38151
+ "Commissioner",
38152
+ "Concert One",
38153
+ "Cormorant",
38154
+ "Cormorant Garamond",
38155
+ "Courgette",
38156
+ "Crete Round",
38157
+ "Crimson Pro",
38158
+ "Crimson Text",
38159
+ "Cuprum",
38160
+ "DM Mono",
38161
+ "DM Sans",
38162
+ "DM Serif Display",
38163
+ "DM Serif Text",
38164
+ "Dancing Script",
38165
+ "Darker Grotesque",
38166
+ "Didact Gothic",
38167
+ "Domine",
38168
+ "Dosis",
38169
+ "EB Garamond",
38170
+ "Eczar",
38171
+ "El Messiri",
38172
+ "Encode Sans",
38173
+ "Encode Sans Condensed",
38174
+ "Exo",
38175
+ "Exo 2",
38176
+ "Fira Code",
38177
+ "Fira Sans",
38178
+ "Fira Sans Condensed",
38179
+ "Fjalla One",
38180
+ "Francois One",
38181
+ "Frank Ruhl Libre",
38182
+ "Fraunces",
38183
+ "Fredoka",
38184
+ "Gelasio",
38185
+ "Gloria Hallelujah",
38186
+ "Gothic A1",
38187
+ "Great Vibes",
38188
+ "Gruppo",
38189
+ "Heebo",
38190
+ "Hind",
38191
+ "Hind Madurai",
38192
+ "Hind Siliguri",
38193
+ "IBM Plex Mono",
38194
+ "IBM Plex Sans",
38195
+ "IBM Plex Sans Arabic",
38196
+ "IBM Plex Sans Condensed",
38197
+ "IBM Plex Serif",
38198
+ "Inconsolata",
38199
+ "Indie Flower",
38200
+ "Inter",
38201
+ "Inter Tight",
38202
+ "Italiana",
38203
+ "Jost",
38204
+ "Josefin Sans",
38205
+ "Josefin Slab",
38206
+ "Kalam",
38207
+ "Kanit",
38208
+ "Karla",
38209
+ "Kaushan Script",
38210
+ "Khand",
38211
+ "Lato",
38212
+ "League Spartan",
38213
+ "Lexend",
38214
+ "Lexend Deca",
38215
+ "Libre Baskerville",
38216
+ "Libre Caslon Text",
38217
+ "Libre Franklin",
38218
+ "Lilita One",
38219
+ "Lobster",
38220
+ "Lobster Two",
38221
+ "Lora",
38222
+ "Lusitana",
38223
+ "Macondo",
38224
+ "Manrope",
38225
+ "Marcellus",
38226
+ "Martel",
38227
+ "Maven Pro",
38228
+ "Merienda",
38229
+ "Merriweather",
38230
+ "Merriweather Sans",
38231
+ "Mitr",
38232
+ "Montserrat",
38233
+ "Montserrat Alternates",
38234
+ "Mukta",
38235
+ "Mulish",
38236
+ "Nanum Gothic",
38237
+ "Nanum Myeongjo",
38238
+ "Neuton",
38239
+ "Noto Sans",
38240
+ "Noto Sans Arabic",
38241
+ "Noto Sans Display",
38242
+ "Noto Sans HK",
38243
+ "Noto Sans JP",
38244
+ "Noto Sans KR",
38245
+ "Noto Sans SC",
38246
+ "Noto Sans TC",
38247
+ "Noto Serif",
38248
+ "Noto Serif JP",
38249
+ "Nunito",
38250
+ "Nunito Sans",
38251
+ "Old Standard TT",
38252
+ "Oleo Script",
38253
+ "Open Sans",
38254
+ "Orbitron",
38255
+ "Oswald",
38256
+ "Outfit",
38257
+ "Overpass",
38258
+ "Oxygen",
38259
+ "PT Mono",
38260
+ "PT Sans",
38261
+ "PT Sans Caption",
38262
+ "PT Sans Narrow",
38263
+ "PT Serif",
38264
+ "Pacifico",
38265
+ "Passion One",
38266
+ "Pathway Gothic One",
38267
+ "Patrick Hand",
38268
+ "Patua One",
38269
+ "Permanent Marker",
38270
+ "Philosopher",
38271
+ "Play",
38272
+ "Playfair Display",
38273
+ "Plus Jakarta Sans",
38274
+ "Poppins",
38275
+ "Prata",
38276
+ "Prompt",
38277
+ "Public Sans",
38278
+ "Quattrocento",
38279
+ "Quattrocento Sans",
38280
+ "Questrial",
38281
+ "Quicksand",
38282
+ "Rajdhani",
38283
+ "Raleway",
38284
+ "Readex Pro",
38285
+ "Red Hat Display",
38286
+ "Righteous",
38287
+ "Roboto",
38288
+ "Roboto Condensed",
38289
+ "Roboto Flex",
38290
+ "Roboto Mono",
38291
+ "Roboto Serif",
38292
+ "Roboto Slab",
38293
+ "Rokkitt",
38294
+ "Rowdies",
38295
+ "Rubik",
38296
+ "Rufina",
38297
+ "Russo One",
38298
+ "Sacramento",
38299
+ "Saira",
38300
+ "Saira Condensed",
38301
+ "Sarabun",
38302
+ "Satisfy",
38303
+ "Sawarabi Gothic",
38304
+ "Secular One",
38305
+ "Sen",
38306
+ "Shadows Into Light",
38307
+ "Signika",
38308
+ "Signika Negative",
38309
+ "Silkscreen",
38310
+ "Slabo 27px",
38311
+ "Sora",
38312
+ "Source Code Pro",
38313
+ "Source Sans 3",
38314
+ "Source Serif 4",
38315
+ "Space Grotesk",
38316
+ "Space Mono",
38317
+ "Spectral",
38318
+ "Tajawal",
38319
+ "Tangerine",
38320
+ "Teko",
38321
+ "Tinos",
38322
+ "Titillium Web",
38323
+ "Ubuntu",
38324
+ "Ubuntu Condensed",
38325
+ "Ubuntu Mono",
38326
+ "Unbounded",
38327
+ "Urbanist",
38328
+ "Varela Round",
38329
+ "Vollkorn",
38330
+ "Work Sans",
38331
+ "Yanone Kaffeesatz",
38332
+ "Yellowtail",
38333
+ "Zen Kaku Gothic New",
38334
+ "Zilla Slab"
38335
+ ];
38336
+ const loadedFonts = /* @__PURE__ */ new Set();
38337
+ function loadGoogleFont(fontFamily) {
38338
+ if (loadedFonts.has(fontFamily))
38339
+ return;
38340
+ loadedFonts.add(fontFamily);
38341
+ const link2 = document.createElement("link");
38342
+ link2.rel = "stylesheet";
38343
+ link2.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontFamily)}:wght@400;700&display=swap`;
38344
+ document.head.appendChild(link2);
38345
+ }
38346
+ function loadGoogleFontsPreview(fontFamilies) {
38347
+ const unloaded = fontFamilies.filter((f2) => !loadedFonts.has(f2));
38348
+ if (unloaded.length === 0)
38349
+ return;
38350
+ for (const font of unloaded) {
38351
+ loadedFonts.add(font);
38352
+ }
38353
+ const families = unloaded.map((f2) => `family=${encodeURIComponent(f2)}`).join("&");
38354
+ const link2 = document.createElement("link");
38355
+ link2.rel = "stylesheet";
38356
+ link2.href = `https://fonts.googleapis.com/css2?${families}&display=swap`;
38357
+ document.head.appendChild(link2);
38358
+ }
38059
38359
  function useFontFamily() {
38060
38360
  const { fontList: defaultFontList } = useEditorProps();
38061
38361
  const { pageData: pageData2 } = useEditorContext();
38062
38362
  const addFonts = pageData2.data.value.fonts;
38063
38363
  const fontList2 = useMemo(() => {
38064
38364
  const fonts = [];
38365
+ const seen = /* @__PURE__ */ new Set();
38366
+ if (addFonts) {
38367
+ for (const item2 of addFonts) {
38368
+ if (!seen.has(item2.name)) {
38369
+ seen.add(item2.name);
38370
+ fonts.push({ value: item2.name, label: item2.name });
38371
+ }
38372
+ }
38373
+ }
38065
38374
  if (defaultFontList) {
38066
- fonts.push(...defaultFontList);
38375
+ for (const item2 of defaultFontList) {
38376
+ if (!seen.has(item2.value)) {
38377
+ seen.add(item2.value);
38378
+ fonts.push({ value: item2.value, label: item2.label });
38379
+ }
38380
+ }
38067
38381
  }
38068
- if (addFonts) {
38069
- const options2 = addFonts.map((item2) => ({ value: item2.name, label: item2.name }));
38070
- fonts.unshift(...options2);
38382
+ for (const font of GOOGLE_FONTS) {
38383
+ if (!seen.has(font)) {
38384
+ seen.add(font);
38385
+ fonts.push({ value: font, label: font });
38386
+ }
38071
38387
  }
38072
38388
  return fonts.map((item2) => ({ value: item2.value, label: /* @__PURE__ */ React__default.createElement("span", {
38073
38389
  style: { fontFamily: item2.value }
@@ -38382,16 +38698,84 @@ function EyeIcon() {
38382
38698
  }
38383
38699
  function FontFamily({ name: name2 }) {
38384
38700
  const { focusIdx: focusIdx2 } = useFocusIdx();
38385
- const { fontList: fontList2 } = useFontFamily();
38386
- return useMemo(() => {
38387
- return /* @__PURE__ */ React__default.createElement(AutoCompleteField, {
38388
- style: { minWidth: 100, flex: 1 },
38389
- showSearch: true,
38390
- label: t("Font family"),
38391
- name: name2 || `${focusIdx2}.attributes.font-family`,
38392
- options: fontList2
38393
- });
38394
- }, [focusIdx2, fontList2, name2]);
38701
+ const { fontList: defaultFontList } = useEditorProps();
38702
+ const { pageData: pageData2 } = useEditorContext();
38703
+ const [searchValue, setSearchValue] = useState("");
38704
+ const addFonts = pageData2.data.value.fonts;
38705
+ const allOptions = useMemo(() => {
38706
+ const options2 = [];
38707
+ const seen = /* @__PURE__ */ new Set();
38708
+ if (addFonts) {
38709
+ for (const font of addFonts) {
38710
+ if (!seen.has(font.name)) {
38711
+ seen.add(font.name);
38712
+ options2.push({ value: font.name, label: font.name });
38713
+ }
38714
+ }
38715
+ }
38716
+ if (defaultFontList) {
38717
+ for (const font of defaultFontList) {
38718
+ if (!seen.has(font.value)) {
38719
+ seen.add(font.value);
38720
+ options2.push({ value: font.value, label: font.label });
38721
+ }
38722
+ }
38723
+ }
38724
+ for (const font of GOOGLE_FONTS) {
38725
+ if (!seen.has(font)) {
38726
+ seen.add(font);
38727
+ options2.push({ value: font, label: font });
38728
+ }
38729
+ }
38730
+ return options2;
38731
+ }, [addFonts, defaultFontList]);
38732
+ useEffect(() => {
38733
+ const search = searchValue.toLowerCase();
38734
+ const visible = search ? allOptions.filter((opt2) => opt2.value.toLowerCase().includes(search)) : allOptions;
38735
+ const fontsToLoad = visible.slice(0, 15).map((opt2) => opt2.value).filter((f2) => GOOGLE_FONTS.includes(f2));
38736
+ if (fontsToLoad.length > 0) {
38737
+ loadGoogleFontsPreview(fontsToLoad);
38738
+ }
38739
+ }, [searchValue, allOptions]);
38740
+ const handleSearch = useCallback((val) => {
38741
+ setSearchValue(val);
38742
+ }, []);
38743
+ const fieldName = name2 || `${focusIdx2}.attributes.font-family`;
38744
+ return /* @__PURE__ */ React__default.createElement(Field, {
38745
+ name: fieldName
38746
+ }, ({ input: { onChange, onBlur: onBlur3, value } }) => /* @__PURE__ */ React__default.createElement(Form.Item, {
38747
+ label: t("Font family"),
38748
+ labelCol: { span: 24, style: { paddingRight: 0 } },
38749
+ wrapperCol: { span: 24 },
38750
+ labelAlign: "left",
38751
+ style: { margin: 0 }
38752
+ }, /* @__PURE__ */ React__default.createElement(Select$2, {
38753
+ showSearch: true,
38754
+ allowCreate: true,
38755
+ value: value || void 0,
38756
+ placeholder: t("Font family"),
38757
+ onSearch: handleSearch,
38758
+ onChange: (val) => {
38759
+ loadGoogleFont(val);
38760
+ onChange(val);
38761
+ onBlur3();
38762
+ setSearchValue("");
38763
+ },
38764
+ filterOption: (inputValue, option) => {
38765
+ var _a2;
38766
+ const optValue = (((_a2 = option.props) == null ? void 0 : _a2.value) || "").toLowerCase();
38767
+ return optValue.includes(inputValue.toLowerCase());
38768
+ },
38769
+ virtualListProps: { height: 256 },
38770
+ style: { width: "100%" },
38771
+ dropdownMenuClassName: "easy-email-overlay",
38772
+ allowClear: true
38773
+ }, allOptions.map((font) => /* @__PURE__ */ React__default.createElement(Select$2.Option, {
38774
+ key: font.value,
38775
+ value: font.value
38776
+ }, /* @__PURE__ */ React__default.createElement("span", {
38777
+ style: { fontFamily: font.value }
38778
+ }, font.label))))));
38395
38779
  }
38396
38780
  function Page({ hideSubTitle, hideSubject }) {
38397
38781
  const { focusIdx: focusIdx2 } = useFocusIdx();