react-tailwind-email-editor 0.0.15 → 0.0.17

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 CHANGED
@@ -1,11 +1,19 @@
1
1
  # React Email Editor
2
2
 
3
- A professional, fully customizable drag-and-drop email template editor built with React, Craft.js, Tailwind CSS.
3
+ Design professional email marketing templates on the fly with a powerful drag-and-drop editor.
4
+
5
+ A fully customizable email template builder built with React, Craft.js, and Tailwind CSS that allows developers to visually design responsive email layouts and export production-ready HTML compatible with major email clients.
6
+
7
+ Ideal for building marketing campaigns, newsletters, promotional emails, transactional emails, and invoice templates quickly without writing complex table-based email HTML.
4
8
 
5
9
  <p align="center">
6
10
  <img src="https://github.com/hemanth-user13/Email-Editor-Npm/blob/master/src/assets/emailEditor1.png" width="900"/>
7
11
  </p>
8
12
 
13
+ <p align="center">
14
+ <img src="https://github.com/hemanth-user13/Email-Editor-Npm/blob/master/src/assets/emailEditor3.png" width="900"/>
15
+ </p>
16
+
9
17
  <p align="center">
10
18
  <img src="https://github.com/hemanth-user13/Email-Editor-Npm/blob/master/src/assets/emailEditor2.png" width="900"/>
11
19
  </p>
@@ -146,6 +154,7 @@ function App() {
146
154
  | `templates` | `EmailTemplate[]` | `[]` | Pre-defined templates |
147
155
  | `callbacks` | `EditorCallbacks` | `{}` | Event handlers (onExport, onChange, etc.) |
148
156
  | `initialState` | `string` | — | Serialized Craft.js state to restore |
157
+ | `initialHtml` | `string` | — | HTML string to parse and load into the editor |
149
158
  | `defaultContent` | `ReactNode` | — | Default JSX content for the canvas |
150
159
  | `title` | `string` | `'Email Editor'` | Toolbar title |
151
160
  | `logo` | `ReactNode` | — | Custom logo element |
package/dist/index.d.cts CHANGED
@@ -97,6 +97,8 @@ interface EmailEditorProps {
97
97
  templates?: EmailTemplate[];
98
98
  callbacks?: EditorCallbacks;
99
99
  initialState?: string;
100
+ /** HTML string to parse and load into the editor on mount */
101
+ initialHtml?: string;
100
102
  defaultContent?: React.ReactNode;
101
103
  title?: string;
102
104
  logo?: React.ReactNode;
package/dist/index.d.ts CHANGED
@@ -97,6 +97,8 @@ interface EmailEditorProps {
97
97
  templates?: EmailTemplate[];
98
98
  callbacks?: EditorCallbacks;
99
99
  initialState?: string;
100
+ /** HTML string to parse and load into the editor on mount */
101
+ initialHtml?: string;
100
102
  defaultContent?: React.ReactNode;
101
103
  title?: string;
102
104
  logo?: React.ReactNode;
package/dist/index.js CHANGED
@@ -4024,6 +4024,160 @@ var TabsContent = React9__namespace.forwardRef(({ className, ...props }, ref) =>
4024
4024
  }
4025
4025
  ));
4026
4026
  TabsContent.displayName = TabsPrimitive__namespace.Content.displayName;
4027
+
4028
+ // src/lib/htmlImporter.ts
4029
+ var nodeCounter = 0;
4030
+ var generateNodeId = () => {
4031
+ nodeCounter++;
4032
+ return `imported_${nodeCounter}_${Math.random().toString(36).slice(2, 8)}`;
4033
+ };
4034
+ var decodeProps = (encoded) => {
4035
+ try {
4036
+ const json = atob(encoded);
4037
+ const parsed = JSON.parse(json);
4038
+ const { _type, ...props } = parsed;
4039
+ return props;
4040
+ } catch (e) {
4041
+ return null;
4042
+ }
4043
+ };
4044
+ var importHtmlToState = (html) => {
4045
+ nodeCounter = 0;
4046
+ const parser = new DOMParser();
4047
+ const doc = parser.parseFromString(html, "text/html");
4048
+ const componentEls = doc.querySelectorAll("[data-component]");
4049
+ const nodes = {};
4050
+ const childNodeIds = [];
4051
+ const topLevelComponents = [];
4052
+ componentEls.forEach((el) => {
4053
+ let parent = el.parentElement;
4054
+ let isNested = false;
4055
+ while (parent) {
4056
+ if (parent.hasAttribute("data-component")) {
4057
+ isNested = true;
4058
+ break;
4059
+ }
4060
+ parent = parent.parentElement;
4061
+ }
4062
+ if (!isNested) {
4063
+ topLevelComponents.push(el);
4064
+ }
4065
+ });
4066
+ if (topLevelComponents.length === 0) {
4067
+ const rawNodeId = generateNodeId();
4068
+ nodes[rawNodeId] = {
4069
+ type: { resolvedName: "RawHtml" },
4070
+ isCanvas: false,
4071
+ props: { html, padding: 0 },
4072
+ displayName: "RawHtml",
4073
+ custom: {},
4074
+ hidden: false,
4075
+ nodes: [],
4076
+ linkedNodes: {},
4077
+ parent: "ROOT"
4078
+ };
4079
+ childNodeIds.push(rawNodeId);
4080
+ } else {
4081
+ for (const el of topLevelComponents) {
4082
+ const typeName = el.getAttribute("data-component") || "RawHtml";
4083
+ const encodedProps = el.getAttribute("data-props") || "";
4084
+ const props = decodeProps(encodedProps);
4085
+ if (!props) continue;
4086
+ const nodeId = generateNodeId();
4087
+ const isCanvas = typeName === "Container" || typeName === "Paper";
4088
+ const nestedChildren = [];
4089
+ const nestedLinkedNodes = {};
4090
+ if (typeName === "Container") {
4091
+ const nestedEls = el.querySelectorAll(":scope > div > [data-component], :scope [data-component]");
4092
+ nestedEls.forEach((nestedEl) => {
4093
+ let nestedParent = nestedEl.parentElement;
4094
+ let belongsToThis = false;
4095
+ while (nestedParent && nestedParent !== el) {
4096
+ if (nestedParent.hasAttribute("data-component") && nestedParent !== el) {
4097
+ break;
4098
+ }
4099
+ if (nestedParent === el) {
4100
+ belongsToThis = true;
4101
+ }
4102
+ nestedParent = nestedParent.parentElement;
4103
+ }
4104
+ if (nestedParent === el) belongsToThis = true;
4105
+ if (belongsToThis) {
4106
+ const nestedType = nestedEl.getAttribute("data-component") || "RawHtml";
4107
+ const nestedEncoded = nestedEl.getAttribute("data-props") || "";
4108
+ const nestedProps = decodeProps(nestedEncoded);
4109
+ if (nestedProps) {
4110
+ const childId = generateNodeId();
4111
+ nodes[childId] = {
4112
+ type: { resolvedName: nestedType },
4113
+ isCanvas: false,
4114
+ props: nestedProps,
4115
+ displayName: nestedType,
4116
+ custom: {},
4117
+ hidden: false,
4118
+ nodes: [],
4119
+ linkedNodes: {},
4120
+ parent: nodeId
4121
+ };
4122
+ nestedChildren.push(childId);
4123
+ }
4124
+ }
4125
+ });
4126
+ }
4127
+ if (typeName === "TwoColumn") {
4128
+ const leftId = generateNodeId();
4129
+ const rightId = generateNodeId();
4130
+ nodes[leftId] = {
4131
+ type: { resolvedName: "Container" },
4132
+ isCanvas: true,
4133
+ props: { background: "#f9f9f9", padding: 10 },
4134
+ displayName: "Container",
4135
+ custom: {},
4136
+ hidden: false,
4137
+ nodes: [],
4138
+ linkedNodes: {},
4139
+ parent: nodeId
4140
+ };
4141
+ nodes[rightId] = {
4142
+ type: { resolvedName: "Container" },
4143
+ isCanvas: true,
4144
+ props: { background: "#f9f9f9", padding: 10 },
4145
+ displayName: "Container",
4146
+ custom: {},
4147
+ hidden: false,
4148
+ nodes: [],
4149
+ linkedNodes: {},
4150
+ parent: nodeId
4151
+ };
4152
+ nestedLinkedNodes["left-column"] = leftId;
4153
+ nestedLinkedNodes["right-column"] = rightId;
4154
+ }
4155
+ nodes[nodeId] = {
4156
+ type: { resolvedName: typeName },
4157
+ isCanvas,
4158
+ props,
4159
+ displayName: typeName,
4160
+ custom: {},
4161
+ hidden: false,
4162
+ nodes: nestedChildren,
4163
+ linkedNodes: nestedLinkedNodes,
4164
+ parent: "ROOT"
4165
+ };
4166
+ childNodeIds.push(nodeId);
4167
+ }
4168
+ }
4169
+ nodes["ROOT"] = {
4170
+ type: { resolvedName: "Paper" },
4171
+ isCanvas: true,
4172
+ props: { background: "#ffffff" },
4173
+ displayName: "Paper",
4174
+ custom: {},
4175
+ hidden: false,
4176
+ nodes: childNodeIds,
4177
+ linkedNodes: {}
4178
+ };
4179
+ return JSON.stringify(nodes);
4180
+ };
4027
4181
  var Modal = ({
4028
4182
  open,
4029
4183
  onClose,
@@ -4725,7 +4879,8 @@ var EmailEditor = ({
4725
4879
  showToolbox = true,
4726
4880
  darkMode = true,
4727
4881
  className,
4728
- style
4882
+ style,
4883
+ initialHtml
4729
4884
  }) => {
4730
4885
  var _a, _b, _c, _d;
4731
4886
  const mergedComponents = React9.useMemo(() => {
@@ -4843,7 +4998,7 @@ var EmailEditor = ({
4843
4998
  onClick: () => {
4844
4999
  setActiveTab("properties");
4845
5000
  },
4846
- children: /* @__PURE__ */ jsxRuntime.jsx(core.Frame, { data: initialState, children: defaultEmailContent })
5001
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8", children: initialState ? /* @__PURE__ */ jsxRuntime.jsx(core.Frame, { data: initialState, children: defaultEmailContent }) : initialHtml ? /* @__PURE__ */ jsxRuntime.jsx(core.Frame, { data: importHtmlToState(initialHtml), children: defaultEmailContent }) : /* @__PURE__ */ jsxRuntime.jsx(core.Frame, { children: defaultContent || defaultEmailContent }) })
4847
5002
  }
4848
5003
  )
4849
5004
  }