@kgalexander/mcreate 0.0.17 → 1.0.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/dist/index.mjs CHANGED
@@ -60,7 +60,7 @@ import {
60
60
  setupDragImage,
61
61
  useEditorStore,
62
62
  useSidebarContext
63
- } from "./chunk-GZLWB3EZ.mjs";
63
+ } from "./chunk-G7F7GRJC.mjs";
64
64
 
65
65
  // src/core/editor/components/email-template-v2/header.tsx
66
66
  import { ArrowLeftIcon, CopyIcon, MegaphoneIcon, MoreHorizontalIcon, PencilIcon, SendIcon, TrashIcon } from "lucide-react";
@@ -81,11 +81,20 @@ function TemplateJsonView() {
81
81
  }
82
82
 
83
83
  // src/core/editor/components/template-size-indicator.tsx
84
+ import { useEffect } from "react";
84
85
  import { jsxs as jsxs2 } from "react/jsx-runtime";
86
+ var POLLING_INTERVAL_MS = 3e4;
85
87
  function TemplateSizeIndicator() {
86
88
  const templateSize = useEditorStore((state) => state.templateSize);
87
89
  const isAtSizeLimit = useEditorStore((state) => state.isAtSizeLimit);
88
- console.log("templateSize", templateSize, isAtSizeLimit);
90
+ const sizeTrackingMode = useEditorStore((state) => state.sizeTrackingMode);
91
+ const recheckTemplateSize = useEditorStore((state) => state.recheckTemplateSize);
92
+ useEffect(() => {
93
+ if (sizeTrackingMode !== "polling") return;
94
+ const id = setInterval(recheckTemplateSize, POLLING_INTERVAL_MS);
95
+ return () => clearInterval(id);
96
+ }, [sizeTrackingMode, recheckTemplateSize]);
97
+ if (sizeTrackingMode === "polling") return null;
89
98
  const sizeKB = (templateSize / 1024).toFixed(0);
90
99
  const maxKB = (MAX_TEMPLATE_SIZE / 1024).toFixed(0);
91
100
  const percentage = templateSize / MAX_TEMPLATE_SIZE * 100;
@@ -203,6 +212,8 @@ function TemplateHeader() {
203
212
  const isSaving = useEditorStore((s) => s.isSaving);
204
213
  const setIsSaving = useEditorStore((s) => s.setIsSaving);
205
214
  const onExit = useEditorStore((s) => s.onExit);
215
+ const onDuplicate = useEditorStore((s) => s.onDuplicate);
216
+ const onDelete = useEditorStore((s) => s.onDelete);
206
217
  const templateName = useEditorStore((s) => s.template?.name);
207
218
  const handleExit = async () => {
208
219
  console.log("handleExit - templateId:", templateId);
@@ -252,12 +263,12 @@ function TemplateHeader() {
252
263
  /* @__PURE__ */ jsx4(MegaphoneIcon, { className: "w-4 h-4" }),
253
264
  "Start new campaign"
254
265
  ] }),
255
- /* @__PURE__ */ jsxs5(DropdownMenuItem, { className: "cursor-pointer", children: [
266
+ /* @__PURE__ */ jsxs5(DropdownMenuItem, { className: "cursor-pointer", onClick: () => templateId && onDuplicate?.(templateId, useEditorStore.getState().template), children: [
256
267
  /* @__PURE__ */ jsx4(CopyIcon, { className: "w-4 h-4" }),
257
268
  "Duplicate"
258
269
  ] }),
259
270
  /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
260
- /* @__PURE__ */ jsxs5(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", children: [
271
+ /* @__PURE__ */ jsxs5(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => templateId && onDelete?.(templateId), children: [
261
272
  /* @__PURE__ */ jsx4(TrashIcon, { className: "w-4 h-4" }),
262
273
  "Delete"
263
274
  ] })
@@ -272,7 +283,7 @@ function TemplateHeader() {
272
283
  }
273
284
 
274
285
  // src/core/editor/components/email-template-v2/sidebar/sidebar.tsx
275
- import { useCallback as useCallback18, useEffect as useEffect4, useRef as useRef6, useMemo as useMemo7, useState as useState10 } from "react";
286
+ import { useCallback as useCallback18, useEffect as useEffect5, useRef as useRef6, useMemo as useMemo7, useState as useState10 } from "react";
276
287
  import { BlocksIcon, Paintbrush, PanelLeftClose, PanelLeftOpen, FileIcon } from "lucide-react";
277
288
 
278
289
  // src/core/editor/components/email-template-v2/sidebar/view/elements/main.tsx
@@ -283,7 +294,7 @@ import { useCallback as useCallback3 } from "react";
283
294
  import { ArrowLeftIcon as ArrowLeftIcon2 } from "lucide-react";
284
295
 
285
296
  // src/core/editor/hooks/use-recently-used.ts
286
- import { useState as useState2, useCallback, useEffect } from "react";
297
+ import { useState as useState2, useCallback, useEffect as useEffect2 } from "react";
287
298
 
288
299
  // src/pre-elements/columns.json
289
300
  var columns_default = [
@@ -1208,7 +1219,7 @@ function resolveAll(refs) {
1208
1219
  }
1209
1220
  function useRecentlyUsed() {
1210
1221
  const [refs, setRefs] = useState2(() => readRefs());
1211
- useEffect(() => {
1222
+ useEffect2(() => {
1212
1223
  const handler = (e) => {
1213
1224
  if (e.key === STORAGE_KEY) {
1214
1225
  setRefs(readRefs());
@@ -1230,7 +1241,7 @@ function useRecentlyUsed() {
1230
1241
  }
1231
1242
 
1232
1243
  // src/core/editor/components/email-template-v2/sidebar/view/elements/_components/preview-section.tsx
1233
- import { useRef, useState as useState3, useCallback as useCallback2, useEffect as useEffect2 } from "react";
1244
+ import { useRef, useState as useState3, useCallback as useCallback2, useEffect as useEffect3 } from "react";
1234
1245
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
1235
1246
  import { jsx as jsx5, jsxs as jsxs6 } from "react/jsx-runtime";
1236
1247
  function PreviewSection({
@@ -1251,7 +1262,7 @@ function PreviewSection({
1251
1262
  setCanGoLeft(el.scrollLeft > 0);
1252
1263
  setCanGoRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
1253
1264
  }, []);
1254
- useEffect2(() => {
1265
+ useEffect3(() => {
1255
1266
  updateScrollState();
1256
1267
  const el = scrollRef.current;
1257
1268
  if (!el) return;
@@ -2710,7 +2721,7 @@ import {
2710
2721
  memo,
2711
2722
  useCallback as useCallback15,
2712
2723
  useContext,
2713
- useEffect as useEffect3,
2724
+ useEffect as useEffect4,
2714
2725
  useMemo as useMemo4,
2715
2726
  useRef as useRef3,
2716
2727
  useState as useState6
@@ -2750,7 +2761,7 @@ var ColorPicker = ({
2750
2761
  saturationRef.current = saturation;
2751
2762
  lightnessRef.current = lightness;
2752
2763
  alphaRef.current = alpha;
2753
- useEffect3(() => {
2764
+ useEffect4(() => {
2754
2765
  if (value) {
2755
2766
  const color = Color(value);
2756
2767
  const hsl = color.hsl().object();
@@ -2835,7 +2846,7 @@ var ColorPickerSelection = memo(({ className, ...props }) => {
2835
2846
  },
2836
2847
  [isDragging, updateColor]
2837
2848
  );
2838
- useEffect3(() => {
2849
+ useEffect4(() => {
2839
2850
  const handlePointerUp = () => setIsDragging(false);
2840
2851
  if (isDragging) {
2841
2852
  window.addEventListener("pointermove", handlePointerMove);
@@ -3697,7 +3708,7 @@ function TemplateSidebar({ editorLoading }) {
3697
3708
  const previousFocusIdxRef = useRef6(null);
3698
3709
  const [openSidebar, setOpenSidebar] = useState10(true);
3699
3710
  const [updateCounter, forceUpdate] = useState10(0);
3700
- useEffect4(() => {
3711
+ useEffect5(() => {
3701
3712
  if (!tiptapEditor) return;
3702
3713
  const handler = () => forceUpdate((n) => n + 1);
3703
3714
  tiptapEditor.on("selectionUpdate", handler);
@@ -3760,7 +3771,7 @@ function TemplateSidebar({ editorLoading }) {
3760
3771
  return null;
3761
3772
  }
3762
3773
  }, [colorTarget, focusIdx, focusedElementAttrs, parentElementAttrs, focusedElementType, pageBgColor, linkColor, tiptapEditor, updateCounter]);
3763
- useEffect4(() => {
3774
+ useEffect5(() => {
3764
3775
  if (!focusIdx || !focusedElementType) {
3765
3776
  previousElementTypeRef.current = void 0;
3766
3777
  return;
@@ -4338,7 +4349,7 @@ var PlainToolbar = () => {
4338
4349
  };
4339
4350
 
4340
4351
  // src/core/editor/components/element-gear/text/toolbar.tsx
4341
- import { useEffect as useEffect6, useState as useState17, useCallback as useCallback27, useMemo as useMemo14 } from "react";
4352
+ import { useEffect as useEffect7, useState as useState17, useCallback as useCallback27, useMemo as useMemo14 } from "react";
4342
4353
  import { BoldIcon, BracesIcon, CaseUpperIcon, CheckIcon as CheckIcon5, EllipsisIcon, HighlighterIcon, ItalicIcon, Strikethrough, Underline } from "lucide-react";
4343
4354
 
4344
4355
  // src/core/editor/components/paragraph-text-settings.tsx
@@ -4406,7 +4417,7 @@ function Slider2({
4406
4417
  }
4407
4418
 
4408
4419
  // src/core/editor/components/paragraph-text-settings.tsx
4409
- import { useState as useState12, useEffect as useEffect5, useMemo as useMemo11, useCallback as useCallback22, memo as memo2 } from "react";
4420
+ import { useState as useState12, useEffect as useEffect6, useMemo as useMemo11, useCallback as useCallback22, memo as memo2 } from "react";
4410
4421
 
4411
4422
  // src/core/editor/hooks/use-editable-value.ts
4412
4423
  import { useState as useState11, useCallback as useCallback21 } from "react";
@@ -4478,7 +4489,7 @@ var ParagraphTextSettings = memo2(function ParagraphTextSettings2() {
4478
4489
  const [isOpen, setIsOpen] = useState12(false);
4479
4490
  const tiptapEditor = useEditorStore((s) => s.tiptapEditor);
4480
4491
  const [updateCounter, forceUpdate] = useState12(0);
4481
- useEffect5(() => {
4492
+ useEffect6(() => {
4482
4493
  if (!tiptapEditor) return;
4483
4494
  const handler = () => forceUpdate((n) => n + 1);
4484
4495
  tiptapEditor.on("selectionUpdate", handler);
@@ -4932,7 +4943,7 @@ var BorderRadius = ({
4932
4943
  value,
4933
4944
  onChange,
4934
4945
  tooltipText = "Border Radius",
4935
- max = 100
4946
+ max = 50
4936
4947
  }) => {
4937
4948
  const [isOpen, setIsOpen] = useState14(false);
4938
4949
  const input = useEditableNumber({ value, onChange, min: 0, max });
@@ -5635,7 +5646,7 @@ var TextToolbar = () => {
5635
5646
  const section = getValueByIdx(template, sectionIdx);
5636
5647
  return section?.type === "section-column";
5637
5648
  }, [focusIdx, template]);
5638
- useEffect6(() => {
5649
+ useEffect7(() => {
5639
5650
  if (!tiptapEditor) return;
5640
5651
  const handler = () => forceUpdate((n) => n + 1);
5641
5652
  tiptapEditor.on("selectionUpdate", handler);
@@ -9408,18 +9419,25 @@ var PropertyEditMenu = () => {
9408
9419
  ) }),
9409
9420
  /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: !!currentIsDescription ? "Hide Description" : "Show Description" })
9410
9421
  ] }),
9411
- /* @__PURE__ */ jsx68(
9412
- Textarea,
9413
- {
9414
- disabled: !currentIsDescription,
9415
- placeholder: "Beautiful home in the heart of the New Jersey Shore",
9416
- className: "w-full shadow-none rounded-[12px] min-h-fit max-h-34",
9417
- value: descriptionInput.displayValue,
9418
- onChange: (e) => descriptionInput.setLocalValue(e.target.value),
9419
- onFocus: descriptionInput.handleFocus,
9420
- onBlur: descriptionInput.handleBlur
9421
- }
9422
- )
9422
+ /* @__PURE__ */ jsxs55("div", { className: "flex flex-col w-full gap-1", children: [
9423
+ /* @__PURE__ */ jsx68(
9424
+ Textarea,
9425
+ {
9426
+ disabled: !currentIsDescription,
9427
+ placeholder: "Beautiful home in the heart of the New Jersey Shore",
9428
+ className: "w-full shadow-none rounded-[12px] min-h-fit max-h-34",
9429
+ maxLength: 200,
9430
+ value: descriptionInput.displayValue,
9431
+ onChange: (e) => descriptionInput.setLocalValue(e.target.value.slice(0, 200)),
9432
+ onFocus: descriptionInput.handleFocus,
9433
+ onBlur: descriptionInput.handleBlur
9434
+ }
9435
+ ),
9436
+ /* @__PURE__ */ jsxs55("p", { className: "text-xs text-muted-foreground text-right", children: [
9437
+ (descriptionInput.displayValue || "").length,
9438
+ "/200"
9439
+ ] })
9440
+ ] })
9423
9441
  ] }) })
9424
9442
  ] })
9425
9443
  ] })
@@ -10042,11 +10060,11 @@ function Skeleton({ className, ...props }) {
10042
10060
  import { Suspense, useState as useState25, lazy } from "react";
10043
10061
 
10044
10062
  // src/core/editor/hooks/use-auto-save.ts
10045
- import { useEffect as useEffect7, useRef as useRef7 } from "react";
10063
+ import { useEffect as useEffect8, useRef as useRef7 } from "react";
10046
10064
  var AUTO_SAVE_INTERVAL = 30 * 1e3;
10047
10065
  function useAutoSave() {
10048
10066
  const intervalRef = useRef7(null);
10049
- useEffect7(() => {
10067
+ useEffect8(() => {
10050
10068
  intervalRef.current = setInterval(async () => {
10051
10069
  const { template, templateId, onSave, hasUnsavedChanges, markAsSaved, isSaving, setIsSaving } = useEditorStore.getState();
10052
10070
  if (isSaving || !templateId || !onSave || !hasUnsavedChanges()) {
@@ -10074,7 +10092,7 @@ function useAutoSave() {
10074
10092
  // src/core/editor/components/email-template-v2/template-page.tsx
10075
10093
  import "react-json-view-lite/dist/index.css";
10076
10094
  import { jsx as jsx74, jsxs as jsxs59 } from "react/jsx-runtime";
10077
- var Editor2 = lazy(() => import("./core-JDSYY73O.mjs").then((module) => ({
10095
+ var Editor2 = lazy(() => import("./core-P3XCQRWR.mjs").then((module) => ({
10078
10096
  default: module.Editor
10079
10097
  })));
10080
10098
  function TemplatePage({
@@ -10084,10 +10102,12 @@ function TemplatePage({
10084
10102
  onToast,
10085
10103
  onExit,
10086
10104
  onImageUpload,
10105
+ onDuplicate,
10106
+ onDelete,
10087
10107
  data
10088
10108
  }) {
10089
10109
  useState25(() => {
10090
- useEditorStore.getState().initializeWithTemplate(templateId, initialTemplate, onSave, onToast, data, onExit, onImageUpload);
10110
+ useEditorStore.getState().initializeWithTemplate(templateId, initialTemplate, onSave, onToast, data, onExit, onImageUpload, onDuplicate, onDelete);
10091
10111
  });
10092
10112
  useAutoSave();
10093
10113
  const [editorLoading, setEditorLoading] = useState25(false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kgalexander/mcreate",
3
- "version": "0.0.17",
3
+ "version": "1.0.0",
4
4
  "description": "Maillow email template editor",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -74,6 +74,7 @@
74
74
  "clsx": "^2.1.1",
75
75
  "cmdk": "^1.1.1",
76
76
  "color": "^5.0.3",
77
+ "html-to-image": "^1.11.13",
77
78
  "immer": "^11.1.3",
78
79
  "lodash": "^4.17.23",
79
80
  "lucide-react": "^0.563.0",