@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.
@@ -215,6 +215,7 @@ function formatOpenHouseTime(time24) {
215
215
  // src/core/editor/constant/configuration.ts
216
216
  import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, Heading1Icon, Heading2Icon, Heading3Icon, LinkIcon, ListIcon, ListOrderedIcon, MailIcon, PhoneIcon, Pilcrow } from "lucide-react";
217
217
  var MAX_TEMPLATE_SIZE = 50 * 1024;
218
+ var SIZE_TRACKING_THRESHOLD = 40 * 1024;
218
219
  var BUTTON_ALIGNMENTS = ["left", "center", "right"];
219
220
  var ALIGNMENT_ICONS = {
220
221
  left: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-left.svg",
@@ -472,8 +473,8 @@ function propertyCardMockMjml(block, context) {
472
473
  ${isBrokerage ? brokerageHtml : ""}
473
474
  ${isDescription && description ? `
474
475
  <tr>
475
- <td style="padding: 0px 0px 0px 0px; font-size: 14px; line-height: 1.5; text-align: left; color: ${textColor};">
476
- ${description}
476
+ <td style="padding: 0px 0px 0px 0px; font-size: 14px; line-height: 1.5; text-align: left; color: ${textColor}; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis;">
477
+ ${description.length > 200 ? description.slice(0, 200) + "..." : description}
477
478
  </td>
478
479
  </tr>
479
480
  ` : ""}
@@ -592,8 +593,8 @@ function propertyCardSingleTwoMockMjml(block, context) {
592
593
  ` : "";
593
594
  const descriptionHtml = description ? `
594
595
  <tr>
595
- <td style="padding: 0px 0px 0px 0px; font-weight: 400; font-size: 14px; line-height: 1.5; text-align: left; color: ${textColor};">
596
- ${description}
596
+ <td style="padding: 0px 0px 0px 0px; font-weight: 400; font-size: 14px; line-height: 1.5; text-align: left; color: ${textColor}; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis;">
597
+ ${description.length > 200 ? description.slice(0, 200) + "..." : description}
597
598
  </td>
598
599
  </tr>
599
600
  ` : "";
@@ -727,7 +728,7 @@ function renderCard(child, childIdx, context, uniqueId, borderRadius, imageHeigh
727
728
  <span style="color:#d1d1d5">|</span>
728
729
  <b>${sqft}</b>&nbsp;<abbr title="square feet" style="text-decoration:none">sqft</abbr>
729
730
  </p>
730
- <p style="font-family:${fontFamily};font-size:12px;line-height:16px;font-weight:400;color:${textColor};font-style:normal;margin:0;padding:0">${city}</p>
731
+ <p class="property-triple-city-${uniqueId}" style="width: 140px; font-family:${fontFamily};font-size:12px;line-height:16px;font-weight:400;color:${textColor};font-style:normal;margin:0;padding:0;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${city}</p>
731
732
  </td>
732
733
  </tr>
733
734
  </tbody>
@@ -803,6 +804,9 @@ function propertyCardTripleMockMjml(block, context) {
803
804
  .property-triple-section-column {
804
805
  width: 100% !important;
805
806
  }
807
+ .property-triple-city-${uniqueId} {
808
+ width: 135px !important;
809
+ }
806
810
  }
807
811
  </style>
808
812
  </mj-raw>
@@ -1817,6 +1821,8 @@ var useEditorStore = create()(
1817
1821
  onToast: null,
1818
1822
  onExit: null,
1819
1823
  onImageUpload: null,
1824
+ onDuplicate: null,
1825
+ onDelete: null,
1820
1826
  previewMode: false,
1821
1827
  focusIdx: null,
1822
1828
  hoverIdx: null,
@@ -1831,6 +1837,7 @@ var useEditorStore = create()(
1831
1837
  tiptapEditor: null,
1832
1838
  templateSize: calculateTemplateSize(defaultTemplate),
1833
1839
  isAtSizeLimit: false,
1840
+ sizeTrackingMode: calculateTemplateSize(defaultTemplate) >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling",
1834
1841
  // Undo/Redo history
1835
1842
  history: [],
1836
1843
  historyIndex: -1,
@@ -1847,8 +1854,16 @@ var useEditorStore = create()(
1847
1854
  mergeFields: [],
1848
1855
  // Render sync
1849
1856
  renderSyncNeeded: 0,
1857
+ // Unconditionally recalculate template size and update tracking mode
1858
+ recheckTemplateSize: () => {
1859
+ set((state) => {
1860
+ state.templateSize = calculateTemplateSize(state.template);
1861
+ state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
1862
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
1863
+ });
1864
+ },
1850
1865
  // Initialize store with external template (for npm package usage)
1851
- initializeWithTemplate: (templateId, template, onSave, onToast, data, onExit, onImageUpload) => {
1866
+ initializeWithTemplate: (templateId, template, onSave, onToast, data, onExit, onImageUpload, onDuplicate, onDelete) => {
1852
1867
  set((state) => {
1853
1868
  state.templateId = templateId;
1854
1869
  state.template = template;
@@ -1856,6 +1871,8 @@ var useEditorStore = create()(
1856
1871
  state.onToast = onToast ?? null;
1857
1872
  state.onExit = onExit ?? null;
1858
1873
  state.onImageUpload = onImageUpload ?? null;
1874
+ state.onDuplicate = onDuplicate ?? null;
1875
+ state.onDelete = onDelete ?? null;
1859
1876
  state.isPaidLevel = data?.isPaidLevel ?? 0;
1860
1877
  state.images = data?.images ?? [];
1861
1878
  state.userData = data?.userData ?? null;
@@ -1865,6 +1882,7 @@ var useEditorStore = create()(
1865
1882
  }));
1866
1883
  state.templateSize = calculateTemplateSize(template);
1867
1884
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
1885
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
1868
1886
  state.history = [cloneDeep(template)];
1869
1887
  state.historyIndex = 0;
1870
1888
  state.focusIdx = null;
@@ -2031,6 +2049,7 @@ var useEditorStore = create()(
2031
2049
  children.splice(positionIndex, 0, newElement);
2032
2050
  state.templateSize = calculateTemplateSize(state.template);
2033
2051
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2052
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2034
2053
  if (type !== "text") {
2035
2054
  state.focusIdx = `${parentIdx}.children.[${positionIndex}]`;
2036
2055
  }
@@ -2070,6 +2089,7 @@ var useEditorStore = create()(
2070
2089
  children.splice(sectionPositionIndex, 0, newSection);
2071
2090
  state.templateSize = calculateTemplateSize(state.template);
2072
2091
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2092
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2073
2093
  if (type !== "text") {
2074
2094
  state.focusIdx = `${pageIdx}.children.[${sectionPositionIndex}].children.[0].children.[0]`;
2075
2095
  }
@@ -2151,8 +2171,11 @@ var useEditorStore = create()(
2151
2171
  updateElementContent: (contentIdx, content) => {
2152
2172
  set((state) => {
2153
2173
  setValueAtPath(state.template, contentIdx, content);
2154
- state.templateSize = calculateTemplateSize(state.template);
2155
- state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2174
+ if (state.sizeTrackingMode === "realtime") {
2175
+ state.templateSize = calculateTemplateSize(state.template);
2176
+ state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2177
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2178
+ }
2156
2179
  });
2157
2180
  },
2158
2181
  // Delete element
@@ -2298,8 +2321,11 @@ var useEditorStore = create()(
2298
2321
  state.focusIdx = null;
2299
2322
  }
2300
2323
  }
2301
- state.templateSize = calculateTemplateSize(state.template);
2302
- state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2324
+ if (state.sizeTrackingMode === "realtime") {
2325
+ state.templateSize = calculateTemplateSize(state.template);
2326
+ state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2327
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2328
+ }
2303
2329
  });
2304
2330
  useEditorStore.getState().pushHistory();
2305
2331
  },
@@ -2324,6 +2350,7 @@ var useEditorStore = create()(
2324
2350
  children.splice(sourceIndex + 1, 0, clonedElement);
2325
2351
  state.templateSize = calculateTemplateSize(state.template);
2326
2352
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2353
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2327
2354
  state.focusIdx = `${parentIdx}.children.[${sourceIndex + 1}]`;
2328
2355
  });
2329
2356
  useEditorStore.getState().pushHistory();
@@ -2511,6 +2538,7 @@ var useEditorStore = create()(
2511
2538
  state.focusIdx = `${parentIdx}.children.[${adjustedIndex + 1}]`;
2512
2539
  state.templateSize = calculateTemplateSize(state.template);
2513
2540
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2541
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2514
2542
  });
2515
2543
  useEditorStore.getState().pushHistory();
2516
2544
  },
@@ -2617,6 +2645,7 @@ var useEditorStore = create()(
2617
2645
  state.focusIdx = `${pageIdx}.children.[${adjustedSectionIndex + 1}]`;
2618
2646
  state.templateSize = calculateTemplateSize(state.template);
2619
2647
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2648
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2620
2649
  });
2621
2650
  useEditorStore.getState().pushHistory();
2622
2651
  },
@@ -2705,6 +2734,7 @@ var useEditorStore = create()(
2705
2734
  }
2706
2735
  state.templateSize = calculateTemplateSize(state.template);
2707
2736
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2737
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2708
2738
  });
2709
2739
  useEditorStore.getState().pushHistory();
2710
2740
  },
@@ -2793,6 +2823,7 @@ var useEditorStore = create()(
2793
2823
  }
2794
2824
  state.templateSize = calculateTemplateSize(state.template);
2795
2825
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2826
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2796
2827
  });
2797
2828
  useEditorStore.getState().pushHistory();
2798
2829
  },
@@ -2956,6 +2987,7 @@ var useEditorStore = create()(
2956
2987
  state.textEditing = null;
2957
2988
  state.templateSize = calculateTemplateSize(state.template);
2958
2989
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
2990
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2959
2991
  });
2960
2992
  setTimeout(() => {
2961
2993
  set((state) => {
@@ -2975,6 +3007,7 @@ var useEditorStore = create()(
2975
3007
  state.textEditing = null;
2976
3008
  state.templateSize = calculateTemplateSize(state.template);
2977
3009
  state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
3010
+ state.sizeTrackingMode = state.templateSize >= SIZE_TRACKING_THRESHOLD ? "realtime" : "polling";
2978
3011
  });
2979
3012
  setTimeout(() => {
2980
3013
  set((state) => {
@@ -11697,6 +11730,27 @@ function focusAdjacentElement(adjacentIdx, storeRefs) {
11697
11730
  storeRefs.setFocusIdx.current(adjacentIdx);
11698
11731
  }
11699
11732
  }
11733
+ var SHADOW_INNER_DIV = ":scope > div";
11734
+ function syncShadowHeight(shadowEl, heightPx) {
11735
+ shadowEl.style.height = heightPx;
11736
+ shadowEl.style.minHeight = heightPx;
11737
+ shadowEl.style.overflow = "hidden";
11738
+ const inner = shadowEl.querySelector(SHADOW_INNER_DIV);
11739
+ if (inner) {
11740
+ inner.style.height = heightPx;
11741
+ inner.style.minHeight = "0";
11742
+ }
11743
+ }
11744
+ function clearShadowHeight(shadowEl) {
11745
+ shadowEl.style.height = "";
11746
+ shadowEl.style.minHeight = "";
11747
+ shadowEl.style.overflow = "";
11748
+ const inner = shadowEl.querySelector(SHADOW_INNER_DIV);
11749
+ if (inner) {
11750
+ inner.style.height = "";
11751
+ inner.style.minHeight = "";
11752
+ }
11753
+ }
11700
11754
  function handleDeleteEntireElement(currentElementIdx, storeRefs, event, skipAutoFocus) {
11701
11755
  event.preventDefault();
11702
11756
  const parentIdx = getParentIdx(currentElementIdx);
@@ -11833,19 +11887,27 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11833
11887
  if (!container) return;
11834
11888
  const observer = new ResizeObserver(() => {
11835
11889
  const shadowEl = getShadowElement();
11836
- if (shadowEl) {
11837
- shadowEl.style.height = `${container.offsetHeight}px`;
11838
- }
11890
+ if (shadowEl) syncShadowHeight(shadowEl, `${container.offsetHeight}px`);
11839
11891
  });
11840
11892
  observer.observe(container);
11841
11893
  return () => {
11842
11894
  observer.disconnect();
11843
11895
  const shadowEl = getShadowElement();
11844
- if (shadowEl) {
11845
- shadowEl.style.height = "";
11846
- }
11896
+ if (shadowEl) clearShadowHeight(shadowEl);
11847
11897
  };
11848
11898
  }, [getShadowElement]);
11899
+ const contentAtIdx = useEditorStore((s) => {
11900
+ const el = getValueByIdx(s.template, idx);
11901
+ return el?.data?.value?.content ?? "";
11902
+ });
11903
+ useEffect6(() => {
11904
+ const raf = requestAnimationFrame(() => {
11905
+ const container = containerRef.current;
11906
+ const shadowEl = getShadowElement();
11907
+ if (container && shadowEl) syncShadowHeight(shadowEl, `${container.offsetHeight}px`);
11908
+ });
11909
+ return () => cancelAnimationFrame(raf);
11910
+ }, [contentAtIdx, getShadowElement]);
11849
11911
  const cleanedContent = useMemo4(() => {
11850
11912
  return content.replace(NBSP_P_CONTENT_REGEX, "<p$1></p>").replace(IS_EMPTY_P_CLASS_REGEX, "").replace(IS_EMPTY_HEADING_CLASS_REGEX, "");
11851
11913
  }, [content]);
@@ -12013,6 +12075,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
12013
12075
  }
12014
12076
  return true;
12015
12077
  }
12078
+ requestAnimationFrame(() => useEditorStore.getState().recheckTemplateSize());
12016
12079
  return false;
12017
12080
  }
12018
12081
  },
@@ -12133,7 +12196,9 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
12133
12196
  style: {
12134
12197
  ...floatingStyles,
12135
12198
  width: initialWidth,
12136
- minHeight: initialHeight,
12199
+ // Do not use minHeight: initialHeight — it prevents the container from shrinking when
12200
+ // line spacing (or content) is reduced while editing; height only updated on exit otherwise.
12201
+ minHeight: 0,
12137
12202
  zIndex: 50,
12138
12203
  // Apply all container styles for exact matching
12139
12204
  fontFamily: styles.fontFamily,
@@ -5,7 +5,7 @@ import {
5
5
  MAILLOW_EMAIL_EDITOR_VERSION,
6
6
  Preview,
7
7
  useEditorStore
8
- } from "./chunk-GZLWB3EZ.mjs";
8
+ } from "./chunk-G7F7GRJC.mjs";
9
9
  export {
10
10
  Editor,
11
11
  History,
package/dist/index.d.mts CHANGED
@@ -290,6 +290,8 @@ interface MergeField {
290
290
  type OnSaveCallback = (templateId: string, template: TemplateJSON) => void | Promise<void>;
291
291
  type OnExitCallback = () => void;
292
292
  type OnImageUploadCallback = (file: File) => Promise<ImageData>;
293
+ type OnDuplicateCallback = (templateId: string, template: TemplateJSON) => void | Promise<void>;
294
+ type OnDeleteCallback = (templateId: string) => void | Promise<void>;
293
295
  type PaidLevel = 0 | 1 | 2 | 3;
294
296
 
295
297
  interface EditorProps {
@@ -298,13 +300,15 @@ interface EditorProps {
298
300
  }
299
301
  declare function Editor({ setEditorLoading }: EditorProps): react_jsx_runtime.JSX.Element;
300
302
 
301
- declare function TemplatePage({ templateId, initialTemplate, onSave, onToast, onExit, onImageUpload, data, }: {
303
+ declare function TemplatePage({ templateId, initialTemplate, onSave, onToast, onExit, onImageUpload, onDuplicate, onDelete, data, }: {
302
304
  templateId: string;
303
305
  initialTemplate: TemplateJSON;
304
306
  onSave?: OnSaveCallback;
305
307
  onToast?: OnToastCallback;
306
308
  onExit?: OnExitCallback;
307
309
  onImageUpload?: OnImageUploadCallback;
310
+ onDuplicate?: OnDuplicateCallback;
311
+ onDelete?: OnDeleteCallback;
308
312
  data?: {
309
313
  isPaidLevel?: PaidLevel;
310
314
  images?: ImageData[];
@@ -333,4 +337,4 @@ interface RenderOptions {
333
337
  */
334
338
  declare function json2mjml(template: TemplateJSON, mode?: RenderMode, options?: RenderOptions): string;
335
339
 
336
- export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, type PaidLevel, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, json2mjml };
340
+ export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type OnDeleteCallback, type OnDuplicateCallback, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, type PaidLevel, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, json2mjml };
package/dist/index.d.ts CHANGED
@@ -290,6 +290,8 @@ interface MergeField {
290
290
  type OnSaveCallback = (templateId: string, template: TemplateJSON) => void | Promise<void>;
291
291
  type OnExitCallback = () => void;
292
292
  type OnImageUploadCallback = (file: File) => Promise<ImageData>;
293
+ type OnDuplicateCallback = (templateId: string, template: TemplateJSON) => void | Promise<void>;
294
+ type OnDeleteCallback = (templateId: string) => void | Promise<void>;
293
295
  type PaidLevel = 0 | 1 | 2 | 3;
294
296
 
295
297
  interface EditorProps {
@@ -298,13 +300,15 @@ interface EditorProps {
298
300
  }
299
301
  declare function Editor({ setEditorLoading }: EditorProps): react_jsx_runtime.JSX.Element;
300
302
 
301
- declare function TemplatePage({ templateId, initialTemplate, onSave, onToast, onExit, onImageUpload, data, }: {
303
+ declare function TemplatePage({ templateId, initialTemplate, onSave, onToast, onExit, onImageUpload, onDuplicate, onDelete, data, }: {
302
304
  templateId: string;
303
305
  initialTemplate: TemplateJSON;
304
306
  onSave?: OnSaveCallback;
305
307
  onToast?: OnToastCallback;
306
308
  onExit?: OnExitCallback;
307
309
  onImageUpload?: OnImageUploadCallback;
310
+ onDuplicate?: OnDuplicateCallback;
311
+ onDelete?: OnDeleteCallback;
308
312
  data?: {
309
313
  isPaidLevel?: PaidLevel;
310
314
  images?: ImageData[];
@@ -333,4 +337,4 @@ interface RenderOptions {
333
337
  */
334
338
  declare function json2mjml(template: TemplateJSON, mode?: RenderMode, options?: RenderOptions): string;
335
339
 
336
- export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, type PaidLevel, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, json2mjml };
340
+ export { Editor, type ImageData, MAX_TEMPLATE_SIZE, type MergeField, type OnDeleteCallback, type OnDuplicateCallback, type OnExitCallback, type OnImageUploadCallback, type OnSaveCallback, type OnToastCallback, type PaidLevel, type TemplateJSON, TemplatePage, type ToastOptions, type ToastType, json2mjml };