@kgalexander/mcreate 0.0.14 → 0.0.16

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.
@@ -1,5 +1,5 @@
1
1
  // src/core/index.tsx
2
- import { useMemo as useMemo17, useState as useState16, useEffect as useEffect20, useCallback as useCallback17, useRef as useRef11 } from "react";
2
+ import { useMemo as useMemo18, useState as useState17, useEffect as useEffect21, useCallback as useCallback18, useRef as useRef12 } from "react";
3
3
  import { cloneDeep as cloneDeep2, isEqual, debounce } from "lodash";
4
4
 
5
5
  // src/core/utils/idx.ts
@@ -212,6 +212,117 @@ function formatOpenHouseTime(time24) {
212
212
  return `${hour12}${period}`;
213
213
  }
214
214
 
215
+ // src/core/editor/constant/configuration.ts
216
+ import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, Heading1Icon, Heading2Icon, Heading3Icon, LinkIcon, ListIcon, ListOrderedIcon, MailIcon, PhoneIcon, Pilcrow } from "lucide-react";
217
+ var MAX_TEMPLATE_SIZE = 50 * 1024;
218
+ var BUTTON_ALIGNMENTS = ["left", "center", "right"];
219
+ var ALIGNMENT_ICONS = {
220
+ left: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-left.svg",
221
+ center: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-center.svg",
222
+ right: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-right.svg"
223
+ };
224
+ var FONTS = [
225
+ "Arial",
226
+ "Helvetica",
227
+ "Times New Roman",
228
+ "Courier New",
229
+ "Verdana",
230
+ "Tahoma",
231
+ "Trebuchet MS",
232
+ "Georgia"
233
+ ];
234
+ var TEXT_ALIGNMENT_ICONS = {
235
+ left: AlignLeftIcon,
236
+ center: AlignCenterIcon,
237
+ right: AlignRightIcon,
238
+ justify: AlignJustifyIcon
239
+ };
240
+ var TEXT_TYPE_OPTIONS = [
241
+ { type: "paragraph", label: "Paragraph", Icon: Pilcrow, disabled: false },
242
+ { type: "h1", label: "Heading 1", Icon: Heading1Icon, disabled: false },
243
+ { type: "h2", label: "Heading 2", Icon: Heading2Icon, disabled: false },
244
+ { type: "h3", label: "Heading 3", Icon: Heading3Icon, disabled: false },
245
+ { type: "list", label: "Bulleted", Icon: ListIcon, disabled: true },
246
+ { type: "ordered", label: "Numbered", Icon: ListOrderedIcon, disabled: true }
247
+ ];
248
+ var DEFAULT_FONT_SIZE = 14;
249
+ var MIN_FONT_SIZE = 6;
250
+ var MAX_FONT_SIZE = 72;
251
+ var FONT_SIZE_STEP = 1;
252
+ var LINK_TYPES = [
253
+ {
254
+ name: "Email",
255
+ placeholder: "email@example.com",
256
+ icon: MailIcon,
257
+ inputType: "email",
258
+ prefix: "mailto:"
259
+ },
260
+ {
261
+ name: "Website",
262
+ placeholder: "https://example.com",
263
+ icon: LinkIcon,
264
+ inputType: "url",
265
+ prefix: ""
266
+ },
267
+ {
268
+ name: "Phone",
269
+ placeholder: "+1234567890",
270
+ icon: PhoneIcon,
271
+ inputType: "tel",
272
+ prefix: "tel:"
273
+ }
274
+ ];
275
+ var LINK_PRESETS = {
276
+ Phone: [
277
+ { label: "Personal Phone", key: "personal_phone_number" },
278
+ { label: "Office Phone", key: "office_phone_number" },
279
+ { label: "Business Phone", key: "business_phone_number" }
280
+ ],
281
+ Website: [
282
+ { label: "Team Website", key: "team_website" },
283
+ { label: "Brokerage Website", key: "brokerage_website" }
284
+ ]
285
+ };
286
+ var detectLinkType = (href) => {
287
+ if (href.startsWith("mailto:")) return LINK_TYPES[0];
288
+ if (href.startsWith("tel:")) return LINK_TYPES[2];
289
+ return LINK_TYPES[1];
290
+ };
291
+ var stripPrefix = (href) => {
292
+ if (href.startsWith("mailto:")) return href.slice(7);
293
+ if (href.startsWith("tel:")) return href.slice(4);
294
+ return href;
295
+ };
296
+ var normalizeWebsiteUrl = (url) => {
297
+ if (!url) return "";
298
+ if (url.match(/^https?:\/\//i)) return url;
299
+ if (url.startsWith("mailto:") || url.startsWith("tel:")) return url;
300
+ return "https://" + url;
301
+ };
302
+ var DEFAULT_LETTER_SPACING = 0;
303
+ var MIN_LETTER_SPACING = -2;
304
+ var MAX_LETTER_SPACING = 10;
305
+ var LETTER_SPACING_STEP = 0.1;
306
+ var DEFAULT_LINE_HEIGHT = 1.4;
307
+ var MIN_LINE_HEIGHT = 0.8;
308
+ var MAX_LINE_HEIGHT = 3;
309
+ var LINE_HEIGHT_STEP = 0.1;
310
+ var HIDDEN_SELECTION_VISUAL_ELEMENTS = ["text", "divider", "column"];
311
+ var NOT_DRAGGABLE_ELEMENTS = ["page", "social-item", "text", "property-card", "property-card-single-two", "property-card-triple", "property-card-triple-item"];
312
+ var EDITOR_COLORS = {
313
+ /** Purple — drag/drop state */
314
+ drag: {
315
+ solid: "rgb(59, 130, 246)",
316
+ half: "rgba(59, 130, 246, 0.5)"
317
+ },
318
+ /** Blue — hover/selection state */
319
+ hover: {
320
+ solid: "rgb(59, 130, 246)",
321
+ half: "rgba(59, 130, 246, 0.5)"
322
+ }
323
+ };
324
+ var DEFAULT_PROPERTY_PLACEHOLDER_IMAGE = "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg";
325
+
215
326
  // src/render/Mockup/mock-property-better.ts
216
327
  function propertyCardMockMjml(block, context) {
217
328
  const a = block.attributes;
@@ -225,7 +336,7 @@ function propertyCardMockMjml(block, context) {
225
336
  const baths = formatNumber(a["baths"] || "");
226
337
  const sqft = formatNumber(a["sqft"] || "");
227
338
  const description = a["description"] || "";
228
- const imageSrc = a["image-src"] || "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg";
339
+ const imageSrc = a["image-src"] || DEFAULT_PROPERTY_PLACEHOLDER_IMAGE;
229
340
  const imageAlt = a["image-alt"] || "Photo of a Property";
230
341
  const status = a["status"] || "Empty";
231
342
  const statusColor = a["status-color"] || "#B8B8B8";
@@ -393,7 +504,7 @@ function propertyCardSingleTwoMockMjml(block, context) {
393
504
  const baths = formatNumber(a["baths"] || "");
394
505
  const sqft = formatNumber(a["sqft"] || "");
395
506
  const description = a["description"] || "";
396
- const imageSrc = a["image-src"] || "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg";
507
+ const imageSrc = a["image-src"] || DEFAULT_PROPERTY_PLACEHOLDER_IMAGE;
397
508
  const imageAlt = a["image-alt"] || "Photo of a Property";
398
509
  const status = a["status"] || "Empty";
399
510
  const statusColor = a["status-color"] || "#B8B8B8";
@@ -583,7 +694,7 @@ function renderCard(child, childIdx, context, uniqueId, borderRadius, imageHeigh
583
694
  const baths = formatNumber(attrs["baths"] || "--");
584
695
  const sqft = formatNumber(attrs["sqft"] || "--");
585
696
  const city = attrs["city"] || "City";
586
- const imageSrc = attrs["image-src"] || "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg";
697
+ const imageSrc = attrs["image-src"] || DEFAULT_PROPERTY_PLACEHOLDER_IMAGE;
587
698
  const childTrackingClasses = context.mode === "editing" ? getTrackingClasses(childIdx, "property-card-triple-item") : "";
588
699
  return `
589
700
  <table class="property-triple-card-${uniqueId} property-triple-table ${childTrackingClasses}" role="presentation" align="center" cellpadding="0" cellspacing="0" border="0" style="width:100%; border:${border}; border-radius:${borderRadius}; border-collapse:separate;${backgroundColor !== "transparent" ? ` background-color:${backgroundColor};` : ""}">
@@ -1249,7 +1360,7 @@ function createImageElement(payload) {
1249
1360
  type: "image",
1250
1361
  tagName: "mj-image",
1251
1362
  attributes: {
1252
- src: "https://placehold.co/600x200",
1363
+ src: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/placeholder_image.png",
1253
1364
  alt: "",
1254
1365
  padding: "0px 0px",
1255
1366
  "fluid-on-mobile": "true",
@@ -1397,7 +1508,7 @@ function createPropertyCardElement(payload) {
1397
1508
  tagName: "mj-colproperty",
1398
1509
  data: { value: {} },
1399
1510
  attributes: {
1400
- "image-src": "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg",
1511
+ "image-src": DEFAULT_PROPERTY_PLACEHOLDER_IMAGE,
1401
1512
  "image-alt": "Property image",
1402
1513
  "price": "$0",
1403
1514
  "address": "123 Main Street",
@@ -1426,7 +1537,7 @@ function createPropertyCardSingleTwoElement(payload) {
1426
1537
  tagName: "mj-propertysingletwo",
1427
1538
  data: { value: {} },
1428
1539
  attributes: {
1429
- "image-src": "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg",
1540
+ "image-src": DEFAULT_PROPERTY_PLACEHOLDER_IMAGE,
1430
1541
  "image-alt": "Property image",
1431
1542
  "price": "$0",
1432
1543
  "address": "123 Main Street",
@@ -1521,7 +1632,7 @@ function createPropertyCardTripleItemElement(payload) {
1521
1632
  tagName: "mj-propertytripleitem",
1522
1633
  data: { value: {} },
1523
1634
  attributes: {
1524
- "image-src": payload?.attributes?.["image-src"] || "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg",
1635
+ "image-src": payload?.attributes?.["image-src"] || DEFAULT_PROPERTY_PLACEHOLDER_IMAGE,
1525
1636
  "href": payload?.attributes?.["href"] || "",
1526
1637
  "price": payload?.attributes?.["price"] || "$0",
1527
1638
  "beds": payload?.attributes?.["beds"] || "--",
@@ -1587,8 +1698,8 @@ function createSectionPropertyTripleElement(payload) {
1587
1698
 
1588
1699
  // templates/empty.json
1589
1700
  var empty_default = {
1590
- id: "-1",
1591
- name: "Empty Template",
1701
+ id: "1",
1702
+ name: "Playground Demo",
1592
1703
  version: "1.0.0",
1593
1704
  published: true,
1594
1705
  creator: "Kevin Guerrero",
@@ -1633,7 +1744,7 @@ var empty_default = {
1633
1744
  tagName: "mj-text",
1634
1745
  data: {
1635
1746
  value: {
1636
- content: '<p class="paragraph" style=" padding: 4px 0; font-family: Arial, sans-serif;">&nbsp;</p>'
1747
+ content: '<p class="paragraph" style=" padding: 4px 0; font-family: Arial, sans-serif;">Welcome to our Open House! Please join us for a tour of this beautiful home.</p>'
1637
1748
  }
1638
1749
  },
1639
1750
  attributes: {
@@ -1646,180 +1757,6 @@ var empty_default = {
1646
1757
  }
1647
1758
  ]
1648
1759
  },
1649
- {
1650
- type: "section-property-km",
1651
- tagName: "mj-section",
1652
- data: { value: { columnRows: 1, columnWidths: [] } },
1653
- attributes: { "background-color": "#FFFFFF", padding: "12px 12px 12px 12px" },
1654
- children: [
1655
- {
1656
- type: "column",
1657
- tagName: "mj-column",
1658
- data: { value: {} },
1659
- attributes: { "background-color": "#FFFFFF", width: "500px", padding: "0px", border: "1px solid #dddddd", "border-radius": "0px" },
1660
- children: [
1661
- {
1662
- type: "property-card",
1663
- tagName: "mj-colproperty",
1664
- data: { value: {} },
1665
- attributes: {
1666
- "image-src": "https://cornerstonepropertymgmt.com/wp-content/themes/cornerstone/assets/img/nofeaturedimage.jpg",
1667
- "image-alt": "Beautiful modern home with pool",
1668
- description: "Beautiful modern home with pool",
1669
- price: "1000000",
1670
- address: "123 Main Street",
1671
- city: "Austin, TX 78701",
1672
- beds: "",
1673
- baths: "2",
1674
- sqft: "1,850",
1675
- href: "https://www.zillow.com/homedetails/126-Cara-Mia-Ln-Galloway-NJ-08205/68297408_zpid/?rtoken=6acd62a8-1848-41ed-919b-0034083eafca~X1-ZUu7aphk9l2689_9ej1i&utm_campaign=emo-instantsearchdigest&utm_source=email&utm_term=urn%3Amsg%3A20251026011813e84b11d632bb8725&utm_medium=email&utm_content=forsaleimage&sse=X1-SSsyx4z97dhglz0000000000_1pt02&srp=H4sIAAAAAAAAAHWRwXKDIBCGn8ZjokKQeOh0YpOZ9Nihh94yRNfozAoOYFrz9FXR1h7KgVn%2B799lF8JKN2DDUpuLlQjhswVp8uqtA9MLJx08BTwLCGlkm%2BlOFXaIA3rw4idY588bvtuyNElSEpCXQQK5JpTtk4h6YnXnKo9ouiWcUco8UdqsSMIp2fOAHz00cKu1EoCQuyGYu2CZb8TT18LLSRwtt3nw3rfg0VSQzTXLGh2Yacr1VLU9IJ7HZ1mrd4ndbHNmiJbGQMkrgsgrrfG%2FhFKi%2Fc24wt9XbOp5HDZaFpeVdyjE9BknZTRiA8otEw77R7wRwvZfu0fKi%2BqGj%2BhnXeLWRWR08uM33zV%2BmeABAAA%3D",
1676
- status: "Empty",
1677
- "status-color": "#B8B8B8",
1678
- "is-new": "",
1679
- "is-open-house": "1",
1680
- "open-house-date": "2026-01-29",
1681
- "open-house-time": "01:00-13:07",
1682
- brokerage: "Keller Williams Atlantic Shore",
1683
- "mls-logo": "https://t4.ftcdn.net/jpg/06/71/92/37/360_F_671923740_x0zOL3OIuUAnSF6sr7PuznCI5bQFKhI0.jpg",
1684
- "border-radius": "0px",
1685
- border: "1px solid #dddddd",
1686
- "font-family": "Arial, sans-serif",
1687
- "text-color": "#000000",
1688
- "price-text-color": "",
1689
- "details-text-color": "",
1690
- "address-text-color": "",
1691
- "brokerage-text-color": "#535364",
1692
- "description-text-color": "",
1693
- "mls-logo-text-color": "",
1694
- "status-text-color": "",
1695
- "new-text-color": "",
1696
- "open-house-text-color": ""
1697
- }
1698
- }
1699
- ]
1700
- }
1701
- ]
1702
- },
1703
- {
1704
- type: "section-property-single-two",
1705
- tagName: "mj-section",
1706
- data: { value: { columnRows: 1, columnWidths: [] } },
1707
- attributes: { "background-color": "#FFFFFF", padding: "12px 12px 12px 12px" },
1708
- children: [
1709
- {
1710
- type: "column",
1711
- tagName: "mj-column",
1712
- data: { value: {} },
1713
- attributes: { "background-color": "#FFFFFF", width: "500px", padding: "0px", border: "1px solid #dddddd", "border-radius": "12px" },
1714
- children: [
1715
- {
1716
- type: "property-card-single-two",
1717
- tagName: "mj-propertysingletwo",
1718
- data: { value: {} },
1719
- attributes: {
1720
- "image-src": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRXddI94MwjUVz5M4CyDxZhSkIIwWbyDF59_w&s",
1721
- "image-alt": "Beautiful modern home with pool",
1722
- description: "Beautiful modern home with pool",
1723
- price: "324203492034",
1724
- address: "123 Main Street",
1725
- city: "Austin, TX 78701",
1726
- beds: "",
1727
- baths: "",
1728
- sqft: "",
1729
- href: "https://www.zillow.com/homedetails/126-Cara-Mia-Ln-Galloway-NJ-08205/68297408_zpid/?rtoken=6acd62a8-1848-41ed-919b-0034083eafca~X1-ZUu7aphk9l2689_9ej1i&utm_campaign=emo-instantsearchdigest&utm_source=email&utm_term=urn%3Amsg%3A20251026011813e84b11d632bb8725&utm_medium=email&utm_content=forsaleimage&sse=X1-SSsyx4z97dhglz0000000000_1pt02&srp=H4sIAAAAAAAAAHWRwXKDIBCGn8ZjokKQeOh0YpOZ9Nihh94yRNfozAoOYFrz9FXR1h7KgVn%2B799lF8JKN2DDUpuLlQjhswVp8uqtA9MLJx08BTwLCGlkm%2BlOFXaIA3rw4idY588bvtuyNElSEpCXQQK5JpTtk4h6YnXnKo9ouiWcUco8UdqsSMIp2fOAHz00cKu1EoCQuyGYu2CZb8TT18LLSRwtt3nw3rfg0VSQzTXLGh2Yacr1VLU9IJ7HZ1mrd4ndbHNmiJbGQMkrgsgrrfG%2FhFKi%2Fc24wt9XbOp5HDZaFpeVdyjE9BknZTRiA8otEw77R7wRwvZfu0fKi%2BqGj%2BhnXeLWRWR08uM33zV%2BmeABAAA%3D",
1730
- status: "Just Listed",
1731
- "status-color": "#008000",
1732
- "is-new": "1",
1733
- "is-open-house": "",
1734
- "open-house-date": "03/25",
1735
- "open-house-time": "12pm-1pm",
1736
- brokerage: "Keller Williams Atlantic Shore",
1737
- "mls-logo": "https://t4.ftcdn.net/jpg/06/71/92/37/360_F_671923740_x0zOL3OIuUAnSF6sr7PuznCI5bQFKhI0.jpg",
1738
- "border-radius": "12px",
1739
- border: "1x solid #dddddd",
1740
- "font-family": "Arial, sans-serif",
1741
- "text-color": "#000000"
1742
- }
1743
- }
1744
- ]
1745
- }
1746
- ]
1747
- },
1748
- {
1749
- type: "section-property-triple",
1750
- tagName: "mj-section",
1751
- data: { value: { columnRows: 1, columnWidths: [] } },
1752
- attributes: { "background-color": "#FFFFFF", padding: "12px" },
1753
- children: [
1754
- {
1755
- type: "column",
1756
- tagName: "mj-column",
1757
- data: { value: {} },
1758
- attributes: { "background-color": "transparent", padding: "0px", "css-class": "property-triple-section-column", width: "500px" },
1759
- children: [
1760
- {
1761
- type: "property-card-triple",
1762
- tagName: "mj-propertytriple",
1763
- data: { value: {} },
1764
- attributes: {
1765
- width: "100%",
1766
- gap: "24px",
1767
- "border-radius": "8px",
1768
- border: "1px solid #d1d1d5",
1769
- "image-height": "102px",
1770
- "font-family": "Arial, sans-serif",
1771
- "text-color": "#000000",
1772
- "background-color": "#FFFFFF"
1773
- },
1774
- children: [
1775
- {
1776
- type: "property-card-triple-item",
1777
- tagName: "mj-propertytripleitem",
1778
- data: { value: {} },
1779
- attributes: {
1780
- "image-src": "https://photos.zillowstatic.com/fp/a8e605d336d0b5a94d91828aee3c0afb-p_i.jpg",
1781
- href: "",
1782
- price: "$320,000",
1783
- beds: "3",
1784
- baths: "2",
1785
- sqft: "1,385",
1786
- city: "Egg Harbor City"
1787
- }
1788
- },
1789
- {
1790
- type: "property-card-triple-item",
1791
- tagName: "mj-propertytripleitem",
1792
- data: { value: {} },
1793
- attributes: {
1794
- "image-src": "https://photos.zillowstatic.com/fp/4d72133271685e778a0126b3defd9854-p_i.jpg",
1795
- href: "",
1796
- price: "$282,000",
1797
- beds: "2",
1798
- baths: "2",
1799
- sqft: "1,224",
1800
- city: "Egg Harbor"
1801
- }
1802
- },
1803
- {
1804
- type: "property-card-triple-item",
1805
- tagName: "mj-propertytripleitem",
1806
- data: { value: {} },
1807
- attributes: {
1808
- "image-src": "https://photos.zillowstatic.com/fp/26e69f22548989c0e4d1ec372ce178e0-p_i.jpg",
1809
- href: "",
1810
- price: "$484,900",
1811
- beds: "3",
1812
- baths: "1",
1813
- sqft: "1,417",
1814
- city: "Egg Harbor"
1815
- }
1816
- }
1817
- ]
1818
- }
1819
- ]
1820
- }
1821
- ]
1822
- },
1823
1760
  {
1824
1761
  type: "section",
1825
1762
  tagName: "mj-section",
@@ -1859,7 +1796,6 @@ var empty_default = {
1859
1796
 
1860
1797
  // src/core/editor/state/editor.ts
1861
1798
  var SECTION_INDEX_REGEX = /^content\.children\.\[(\d+)\]/;
1862
- var MAX_TEMPLATE_SIZE = 50 * 1024;
1863
1799
  function calculateTemplateSize(template) {
1864
1800
  const str = JSON.stringify(template);
1865
1801
  return new Blob([str]).size;
@@ -1880,6 +1816,7 @@ var useEditorStore = create()(
1880
1816
  onSave: null,
1881
1817
  onToast: null,
1882
1818
  onExit: null,
1819
+ onImageUpload: null,
1883
1820
  previewMode: false,
1884
1821
  focusIdx: null,
1885
1822
  hoverIdx: null,
@@ -1888,6 +1825,7 @@ var useEditorStore = create()(
1888
1825
  dataTransfer: null,
1889
1826
  isScaling: false,
1890
1827
  slashCommand: null,
1828
+ mergeFieldSuggestion: null,
1891
1829
  textEditing: null,
1892
1830
  pendingTextEditRequest: null,
1893
1831
  tiptapEditor: null,
@@ -1906,19 +1844,27 @@ var useEditorStore = create()(
1906
1844
  // User data
1907
1845
  images: [],
1908
1846
  userData: null,
1847
+ mergeFields: [],
1848
+ // Render sync
1849
+ renderSyncNeeded: 0,
1909
1850
  // Initialize store with external template (for npm package usage)
1910
- initializeWithTemplate: (templateId, template, onSave, onToast, data, onExit) => {
1851
+ initializeWithTemplate: (templateId, template, onSave, onToast, data, onExit, onImageUpload) => {
1911
1852
  set((state) => {
1912
1853
  state.templateId = templateId;
1913
1854
  state.template = template;
1914
1855
  state.onSave = onSave ?? null;
1915
1856
  state.onToast = onToast ?? null;
1916
1857
  state.onExit = onExit ?? null;
1858
+ state.onImageUpload = onImageUpload ?? null;
1917
1859
  state.isPaidLevel = data?.isPaidLevel ?? 0;
1918
1860
  state.images = data?.images ?? [];
1919
1861
  state.userData = data?.userData ?? null;
1862
+ state.mergeFields = (data?.mergefields ?? []).map((f) => ({
1863
+ label: (f.name || "").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
1864
+ value: (f.merge_tag || "").replace(/^\{\{|\}\}$/g, "")
1865
+ }));
1920
1866
  state.templateSize = calculateTemplateSize(template);
1921
- state.isAtSizeLimit = false;
1867
+ state.isAtSizeLimit = state.templateSize >= MAX_TEMPLATE_SIZE;
1922
1868
  state.history = [cloneDeep(template)];
1923
1869
  state.historyIndex = 0;
1924
1870
  state.focusIdx = null;
@@ -1927,6 +1873,11 @@ var useEditorStore = create()(
1927
1873
  state.lastSavedSnapshot = JSON.stringify(template);
1928
1874
  });
1929
1875
  },
1876
+ addImage: (image2) => {
1877
+ set((state) => {
1878
+ state.images.push(castDraft(image2));
1879
+ });
1880
+ },
1930
1881
  // Template metadata actions
1931
1882
  setTemplateName: (name) => {
1932
1883
  set((state) => {
@@ -2007,6 +1958,17 @@ var useEditorStore = create()(
2007
1958
  }, 0);
2008
1959
  }
2009
1960
  },
1961
+ // Merge field suggestion actions
1962
+ setMergeFieldSuggestion: (suggestionState) => {
1963
+ set((state) => {
1964
+ state.mergeFieldSuggestion = suggestionState;
1965
+ });
1966
+ },
1967
+ clearMergeFieldSuggestion: () => {
1968
+ set((state) => {
1969
+ state.mergeFieldSuggestion = null;
1970
+ });
1971
+ },
2010
1972
  // Text editing actions (Tiptap overlay)
2011
1973
  startTextEditing: (textEditingState) => {
2012
1974
  set((state) => {
@@ -2182,6 +2144,7 @@ var useEditorStore = create()(
2182
2144
  return;
2183
2145
  }
2184
2146
  Object.assign(element, updates);
2147
+ state2.renderSyncNeeded += 1;
2185
2148
  });
2186
2149
  },
2187
2150
  // Update element content (for contenteditable)
@@ -3084,129 +3047,19 @@ function setValueAtPath(template, path, value) {
3084
3047
 
3085
3048
  // src/core/editor/components/ShadowDomRenderer.tsx
3086
3049
  import { useEffect, useRef, memo } from "react";
3050
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3051
+ var lastSizeLimitToastTime = 0;
3052
+ var cssCache = /* @__PURE__ */ new Map();
3053
+ function getEditorStyles(isDragButtonHovered, textEditingIdx) {
3054
+ const cacheKey = `${isDragButtonHovered}-${textEditingIdx ?? "null"}`;
3055
+ const cached = cssCache.get(cacheKey);
3056
+ if (cached) return cached;
3057
+ const hiddenSelectors = !isDragButtonHovered && HIDDEN_SELECTION_VISUAL_ELEMENTS.length > 0 ? HIDDEN_SELECTION_VISUAL_ELEMENTS.map((type) => `.node-type-${type}`).join(", ") : null;
3058
+ const css = `
3087
3059
 
3088
- // src/core/editor/constant/configuration.ts
3089
- import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, Heading1Icon, Heading2Icon, Heading3Icon, LinkIcon, ListIcon, ListOrderedIcon, MailIcon, PhoneIcon, Pilcrow } from "lucide-react";
3090
- var BUTTON_ALIGNMENTS = ["left", "center", "right"];
3091
- var ALIGNMENT_ICONS = {
3092
- left: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-left.svg",
3093
- center: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-center.svg",
3094
- right: "https://mzyngaqmbvhpgmmipndy.supabase.co/storage/v1/object/public/Maillow/icons/align-vertical-space-around-right.svg"
3095
- };
3096
- var FONTS = [
3097
- "Arial",
3098
- "Helvetica",
3099
- "Times New Roman",
3100
- "Courier New",
3101
- "Verdana",
3102
- "Tahoma",
3103
- "Trebuchet MS",
3104
- "Georgia"
3105
- ];
3106
- var TEXT_ALIGNMENT_ICONS = {
3107
- left: AlignLeftIcon,
3108
- center: AlignCenterIcon,
3109
- right: AlignRightIcon,
3110
- justify: AlignJustifyIcon
3111
- };
3112
- var TEXT_TYPE_OPTIONS = [
3113
- { type: "paragraph", label: "Paragraph", Icon: Pilcrow, disabled: false },
3114
- { type: "h1", label: "Heading 1", Icon: Heading1Icon, disabled: false },
3115
- { type: "h2", label: "Heading 2", Icon: Heading2Icon, disabled: false },
3116
- { type: "h3", label: "Heading 3", Icon: Heading3Icon, disabled: false },
3117
- { type: "list", label: "Bulleted", Icon: ListIcon, disabled: true },
3118
- { type: "ordered", label: "Numbered", Icon: ListOrderedIcon, disabled: true }
3119
- ];
3120
- var DEFAULT_FONT_SIZE = 14;
3121
- var MIN_FONT_SIZE = 6;
3122
- var MAX_FONT_SIZE = 72;
3123
- var FONT_SIZE_STEP = 1;
3124
- var LINK_TYPES = [
3125
- {
3126
- name: "Email",
3127
- placeholder: "email@example.com",
3128
- icon: MailIcon,
3129
- inputType: "email",
3130
- prefix: "mailto:"
3131
- },
3132
- {
3133
- name: "Website",
3134
- placeholder: "https://example.com",
3135
- icon: LinkIcon,
3136
- inputType: "url",
3137
- prefix: ""
3138
- },
3139
- {
3140
- name: "Phone",
3141
- placeholder: "+1234567890",
3142
- icon: PhoneIcon,
3143
- inputType: "tel",
3144
- prefix: "tel:"
3145
- }
3146
- ];
3147
- var LINK_PRESETS = {
3148
- Phone: [
3149
- { label: "Personal Phone", key: "personal_phone_number" },
3150
- { label: "Office Phone", key: "office_phone_number" },
3151
- { label: "Business Phone", key: "business_phone_number" }
3152
- ],
3153
- Website: [
3154
- { label: "Team Website", key: "team_website" },
3155
- { label: "Brokerage Website", key: "brokerage_website" }
3156
- ]
3157
- };
3158
- var detectLinkType = (href) => {
3159
- if (href.startsWith("mailto:")) return LINK_TYPES[0];
3160
- if (href.startsWith("tel:")) return LINK_TYPES[2];
3161
- return LINK_TYPES[1];
3162
- };
3163
- var stripPrefix = (href) => {
3164
- if (href.startsWith("mailto:")) return href.slice(7);
3165
- if (href.startsWith("tel:")) return href.slice(4);
3166
- return href;
3167
- };
3168
- var normalizeWebsiteUrl = (url) => {
3169
- if (!url) return "";
3170
- if (url.match(/^https?:\/\//i)) return url;
3171
- if (url.startsWith("mailto:") || url.startsWith("tel:")) return url;
3172
- return "https://" + url;
3173
- };
3174
- var DEFAULT_LETTER_SPACING = 0;
3175
- var MIN_LETTER_SPACING = -2;
3176
- var MAX_LETTER_SPACING = 10;
3177
- var LETTER_SPACING_STEP = 0.1;
3178
- var DEFAULT_LINE_HEIGHT = 1.4;
3179
- var MIN_LINE_HEIGHT = 0.8;
3180
- var MAX_LINE_HEIGHT = 3;
3181
- var LINE_HEIGHT_STEP = 0.1;
3182
- var HIDDEN_SELECTION_VISUAL_ELEMENTS = ["text", "divider", "column"];
3183
- var NOT_DRAGGABLE_ELEMENTS = ["page", "social-item", "text", "property-card", "property-card-single-two", "property-card-triple", "property-card-triple-item"];
3184
- var EDITOR_COLORS = {
3185
- /** Purple — drag/drop state */
3186
- drag: {
3187
- solid: "rgb(59, 130, 246)",
3188
- half: "rgba(59, 130, 246, 0.5)"
3189
- },
3190
- /** Blue — hover/selection state */
3191
- hover: {
3192
- solid: "rgb(59, 130, 246)",
3193
- half: "rgba(59, 130, 246, 0.5)"
3194
- }
3195
- };
3196
-
3197
- // src/core/editor/components/ShadowDomRenderer.tsx
3198
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3199
- var lastSizeLimitToastTime = 0;
3200
- var cssCache = /* @__PURE__ */ new Map();
3201
- function getEditorStyles(isDragButtonHovered, textEditingIdx) {
3202
- const cacheKey = `${isDragButtonHovered}-${textEditingIdx ?? "null"}`;
3203
- const cached = cssCache.get(cacheKey);
3204
- if (cached) return cached;
3205
- const hiddenSelectors = !isDragButtonHovered && HIDDEN_SELECTION_VISUAL_ELEMENTS.length > 0 ? HIDDEN_SELECTION_VISUAL_ELEMENTS.map((type) => `.node-type-${type}`).join(", ") : null;
3206
- const css = `
3207
- /* Base reset for email content */
3208
- * {
3209
- box-sizing: border-box;
3060
+ /* Base reset for email content */
3061
+ * {
3062
+ box-sizing: border-box;
3210
3063
  }
3211
3064
 
3212
3065
  /* Make all email blocks interactive */
@@ -3528,6 +3381,19 @@ function getEditorStyles(isDragButtonHovered, textEditingIdx) {
3528
3381
  }
3529
3382
  ` : ""}
3530
3383
 
3384
+ /* Merge field tags - dashed underline for {{variable}} patterns */
3385
+ .merge-field-tag {
3386
+
3387
+ background-color: var(--background);
3388
+ border-radius: 4px;
3389
+ padding: 4px;
3390
+ border: 1px solid var(--border);
3391
+ color: #000000;
3392
+ }
3393
+ .merge-field-tag:hover {
3394
+ cursor: pointer;
3395
+ }
3396
+
3531
3397
  /* Company footer - hide selection/hover outlines and make non-interactive */
3532
3398
  .is-company-footer,
3533
3399
  .is-company-footer .${EMAIL_BLOCK_CLASS_NAME} {
@@ -4153,6 +4019,7 @@ function isTextContentEmpty(element) {
4153
4019
  const text2 = element.textContent?.trim() || "";
4154
4020
  return text2.length === 0;
4155
4021
  }
4022
+ var MERGE_FIELD_REGEX_SHADOW = /\{\{[a-zA-Z_][a-zA-Z0-9_]*\}\}/g;
4156
4023
  function isParagraphEmpty(p) {
4157
4024
  const text2 = p.textContent || "";
4158
4025
  return text2.trim() === "" || text2 === "\xA0" || text2 === "&nbsp;";
@@ -4174,6 +4041,40 @@ function injectContentEditable(container) {
4174
4041
  }
4175
4042
  }
4176
4043
  });
4044
+ if (contentDiv.textContent?.includes("{{")) {
4045
+ const walker = document.createTreeWalker(contentDiv, NodeFilter.SHOW_TEXT);
4046
+ const textNodes = [];
4047
+ let tNode;
4048
+ while (tNode = walker.nextNode()) {
4049
+ if (tNode.textContent && MERGE_FIELD_REGEX_SHADOW.test(tNode.textContent)) {
4050
+ textNodes.push(tNode);
4051
+ }
4052
+ MERGE_FIELD_REGEX_SHADOW.lastIndex = 0;
4053
+ }
4054
+ for (const textNode of textNodes) {
4055
+ const text2 = textNode.textContent || "";
4056
+ const fragment = document.createDocumentFragment();
4057
+ let lastIndex = 0;
4058
+ MERGE_FIELD_REGEX_SHADOW.lastIndex = 0;
4059
+ let match;
4060
+ while ((match = MERGE_FIELD_REGEX_SHADOW.exec(text2)) !== null) {
4061
+ if (match.index > lastIndex) {
4062
+ fragment.appendChild(document.createTextNode(text2.slice(lastIndex, match.index)));
4063
+ }
4064
+ const span = document.createElement("span");
4065
+ span.className = "merge-field-tag";
4066
+ const fieldName = match[0].slice(2, -2);
4067
+ span.setAttribute("data-tooltip", fieldName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()));
4068
+ span.textContent = match[0];
4069
+ fragment.appendChild(span);
4070
+ lastIndex = match.index + match[0].length;
4071
+ }
4072
+ if (lastIndex < text2.length) {
4073
+ fragment.appendChild(document.createTextNode(text2.slice(lastIndex)));
4074
+ }
4075
+ textNode.parentNode?.replaceChild(fragment, textNode);
4076
+ }
4077
+ }
4177
4078
  }
4178
4079
  });
4179
4080
  container.querySelectorAll(".node-type-button").forEach((buttonEl) => {
@@ -4995,6 +4896,158 @@ var ElementsSuggestionsContent = () => {
4995
4896
  );
4996
4897
  };
4997
4898
 
4899
+ // src/core/editor/components/merge-field-suggestions.tsx
4900
+ import { useMemo as useMemo3, useEffect as useEffect4, useRef as useRef3, useState, useCallback as useCallback3 } from "react";
4901
+ import { useFloating as useFloating3, offset as offset3, shift as shift3, flip as flip2 } from "@floating-ui/react";
4902
+ import { BracesIcon } from "lucide-react";
4903
+ import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
4904
+ var MergeFieldSuggestions = () => {
4905
+ const isActive = useEditorStore((state) => state.mergeFieldSuggestion?.isActive);
4906
+ if (!isActive) return null;
4907
+ return /* @__PURE__ */ jsx14(MergeFieldSuggestionsContent, {});
4908
+ };
4909
+ var MergeFieldSuggestionsContent = () => {
4910
+ const mergeFieldSuggestion = useEditorStore((state) => state.mergeFieldSuggestion);
4911
+ const clearMergeFieldSuggestion = useEditorStore((state) => state.clearMergeFieldSuggestion);
4912
+ const tiptapEditor = useEditorStore((state) => state.tiptapEditor);
4913
+ const mergeFields = useEditorStore((state) => state.mergeFields);
4914
+ const containerRef = useRef3(null);
4915
+ const [searchQuery, setSearchQuery] = useState("");
4916
+ useEffect4(() => {
4917
+ if (!tiptapEditor || !mergeFieldSuggestion) return;
4918
+ const updateQuery = () => {
4919
+ const { from } = tiptapEditor.state.selection;
4920
+ const triggerEnd = mergeFieldSuggestion.triggerPosition + 2;
4921
+ if (from > triggerEnd) {
4922
+ const typed = tiptapEditor.state.doc.textBetween(triggerEnd, from);
4923
+ setSearchQuery(typed);
4924
+ } else {
4925
+ setSearchQuery("");
4926
+ }
4927
+ };
4928
+ updateQuery();
4929
+ tiptapEditor.on("selectionUpdate", updateQuery);
4930
+ tiptapEditor.on("update", updateQuery);
4931
+ return () => {
4932
+ tiptapEditor.off("selectionUpdate", updateQuery);
4933
+ tiptapEditor.off("update", updateQuery);
4934
+ };
4935
+ }, [tiptapEditor, mergeFieldSuggestion]);
4936
+ const filteredFields = useMemo3(() => {
4937
+ if (!searchQuery) return mergeFields;
4938
+ const q = searchQuery.toLowerCase();
4939
+ return mergeFields.filter(
4940
+ (f) => f.label.toLowerCase().includes(q) || f.value.toLowerCase().includes(q)
4941
+ );
4942
+ }, [searchQuery, mergeFields]);
4943
+ const handleSelect = useCallback3((fieldValue) => {
4944
+ if (!tiptapEditor || !mergeFieldSuggestion) return;
4945
+ const { from } = tiptapEditor.state.selection;
4946
+ const triggerPos = mergeFieldSuggestion.triggerPosition;
4947
+ tiptapEditor.chain().focus().deleteRange({ from: triggerPos, to: from }).insertContent(`{{${fieldValue}}}`).run();
4948
+ clearMergeFieldSuggestion();
4949
+ }, [tiptapEditor, mergeFieldSuggestion, clearMergeFieldSuggestion]);
4950
+ const virtualReference = useMemo3(() => ({
4951
+ getBoundingClientRect: () => {
4952
+ if (!mergeFieldSuggestion?.cursorRect) {
4953
+ return { x: 0, y: 0, top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, toJSON: () => ({}) };
4954
+ }
4955
+ const { top, left, height } = mergeFieldSuggestion.cursorRect;
4956
+ return {
4957
+ x: left,
4958
+ y: top,
4959
+ top,
4960
+ left,
4961
+ bottom: top + height,
4962
+ right: left,
4963
+ width: 0,
4964
+ height,
4965
+ toJSON: () => ({})
4966
+ };
4967
+ }
4968
+ }), [mergeFieldSuggestion?.cursorRect]);
4969
+ const { floatingStyles, refs, update } = useFloating3({
4970
+ placement: "bottom-start",
4971
+ middleware: [
4972
+ offset3(4),
4973
+ flip2({ padding: 8 }),
4974
+ shift3({ padding: 8 })
4975
+ ]
4976
+ });
4977
+ const floatingRefsRef = useRef3(refs);
4978
+ useEffect4(() => {
4979
+ floatingRefsRef.current = refs;
4980
+ }, [refs]);
4981
+ useEffect4(() => {
4982
+ if (mergeFieldSuggestion?.cursorRect) {
4983
+ floatingRefsRef.current.setPositionReference(virtualReference);
4984
+ update();
4985
+ }
4986
+ }, [mergeFieldSuggestion?.cursorRect, virtualReference, update]);
4987
+ const clearRef = useRef3(clearMergeFieldSuggestion);
4988
+ useEffect4(() => {
4989
+ clearRef.current = clearMergeFieldSuggestion;
4990
+ }, [clearMergeFieldSuggestion]);
4991
+ useEffect4(() => {
4992
+ const handleClickOutside = (e) => {
4993
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
4994
+ clearRef.current();
4995
+ }
4996
+ };
4997
+ const timeoutId = setTimeout(() => {
4998
+ document.addEventListener("mousedown", handleClickOutside);
4999
+ }, 0);
5000
+ return () => {
5001
+ clearTimeout(timeoutId);
5002
+ document.removeEventListener("mousedown", handleClickOutside);
5003
+ };
5004
+ }, []);
5005
+ useEffect4(() => {
5006
+ const handleEscape = (e) => {
5007
+ if (e.key === "Escape") {
5008
+ clearRef.current();
5009
+ }
5010
+ };
5011
+ document.addEventListener("keydown", handleEscape);
5012
+ return () => document.removeEventListener("keydown", handleEscape);
5013
+ }, []);
5014
+ return /* @__PURE__ */ jsx14(
5015
+ "div",
5016
+ {
5017
+ ref: (node) => {
5018
+ containerRef.current = node;
5019
+ refs.setFloating(node);
5020
+ },
5021
+ style: {
5022
+ ...floatingStyles,
5023
+ zIndex: 9999
5024
+ },
5025
+ className: "bg-popover border rounded-md shadow-md overflow-hidden",
5026
+ children: /* @__PURE__ */ jsx14(Command, { className: "w-[240px]", children: /* @__PURE__ */ jsxs5(CommandList, { className: "max-h-[300px]", children: [
5027
+ /* @__PURE__ */ jsx14(CommandEmpty, { children: "No matching fields." }),
5028
+ /* @__PURE__ */ jsx14(CommandGroup, { heading: "Merge fields", children: filteredFields.map(({ label, value }) => /* @__PURE__ */ jsxs5(
5029
+ CommandItem,
5030
+ {
5031
+ value,
5032
+ keywords: [label],
5033
+ className: "flex items-center gap-2 cursor-pointer",
5034
+ onSelect: () => handleSelect(value),
5035
+ onMouseDown: (e) => {
5036
+ e.preventDefault();
5037
+ handleSelect(value);
5038
+ },
5039
+ children: [
5040
+ /* @__PURE__ */ jsx14(BracesIcon, { className: "w-4 h-4" }),
5041
+ label
5042
+ ]
5043
+ },
5044
+ value
5045
+ )) })
5046
+ ] }) })
5047
+ }
5048
+ );
5049
+ };
5050
+
4998
5051
  // src/core/editor/components/tiptap-overlay.tsx
4999
5052
  import { useEditor, EditorContent } from "@tiptap/react";
5000
5053
  import { BubbleMenu } from "@tiptap/react/menus";
@@ -5861,7 +5914,7 @@ function normalizeKeyName(name) {
5861
5914
  }
5862
5915
  let alt;
5863
5916
  let ctrl;
5864
- let shift4;
5917
+ let shift5;
5865
5918
  let meta;
5866
5919
  for (let i = 0; i < parts.length - 1; i += 1) {
5867
5920
  const mod = parts[i];
@@ -5872,7 +5925,7 @@ function normalizeKeyName(name) {
5872
5925
  } else if (/^(c|ctrl|control)$/i.test(mod)) {
5873
5926
  ctrl = true;
5874
5927
  } else if (/^s(hift)?$/i.test(mod)) {
5875
- shift4 = true;
5928
+ shift5 = true;
5876
5929
  } else if (/^mod$/i.test(mod)) {
5877
5930
  if (isiOS() || isMacOS()) {
5878
5931
  meta = true;
@@ -5892,7 +5945,7 @@ function normalizeKeyName(name) {
5892
5945
  if (meta) {
5893
5946
  result = `Meta-${result}`;
5894
5947
  }
5895
- if (shift4) {
5948
+ if (shift5) {
5896
5949
  result = `Shift-${result}`;
5897
5950
  }
5898
5951
  return result;
@@ -10744,8 +10797,8 @@ var Link = Mark.create({
10744
10797
  var index_default = Link;
10745
10798
 
10746
10799
  // src/core/editor/components/tiptap-overlay.tsx
10747
- import { useFloating as useFloating3, autoUpdate as autoUpdate2, offset as offset3 } from "@floating-ui/react";
10748
- import { useEffect as useEffect6, useRef as useRef4, useMemo as useMemo3, useState as useState2 } from "react";
10800
+ import { useFloating as useFloating4, autoUpdate as autoUpdate2, offset as offset4 } from "@floating-ui/react";
10801
+ import { useEffect as useEffect7, useRef as useRef5, useMemo as useMemo4, useState as useState3 } from "react";
10749
10802
 
10750
10803
  // src/core/editor/extensions/inverse-placeholder.ts
10751
10804
  import { Plugin as Plugin12, PluginKey as PluginKey10 } from "@tiptap/pm/state";
@@ -10955,25 +11008,69 @@ var HeadingParagraph = Node3.create({
10955
11008
  }
10956
11009
  });
10957
11010
 
11011
+ // src/core/editor/extensions/merge-field-decoration.ts
11012
+ import { Plugin as Plugin13, PluginKey as PluginKey11 } from "@tiptap/pm/state";
11013
+ import { Decoration as Decoration2, DecorationSet as DecorationSet2 } from "@tiptap/pm/view";
11014
+ var MERGE_FIELD_REGEX = /\{\{[a-zA-Z_][a-zA-Z0-9_]*\}\}/g;
11015
+ var MergeFieldDecoration = Extension.create({
11016
+ name: "mergeFieldDecoration",
11017
+ addProseMirrorPlugins() {
11018
+ let cached = null;
11019
+ return [
11020
+ new Plugin13({
11021
+ key: new PluginKey11("mergeFieldDecoration"),
11022
+ props: {
11023
+ decorations: (state) => {
11024
+ const { doc } = state;
11025
+ const docNodeSize = doc.nodeSize;
11026
+ if (cached && cached.docNodeSize === docNodeSize) {
11027
+ return cached.decorations;
11028
+ }
11029
+ const decorations = [];
11030
+ doc.descendants((node, pos) => {
11031
+ if (!node.isText || !node.text) return;
11032
+ MERGE_FIELD_REGEX.lastIndex = 0;
11033
+ let match;
11034
+ while ((match = MERGE_FIELD_REGEX.exec(node.text)) !== null) {
11035
+ const from = pos + match.index;
11036
+ const to = from + match[0].length;
11037
+ decorations.push(
11038
+ Decoration2.inline(from, to, { class: "merge-field-tag" })
11039
+ );
11040
+ }
11041
+ });
11042
+ const decorationSet = DecorationSet2.create(doc, decorations);
11043
+ cached = { docNodeSize, decorations: decorationSet };
11044
+ return decorationSet;
11045
+ }
11046
+ }
11047
+ })
11048
+ ];
11049
+ }
11050
+ });
11051
+
10958
11052
  // src/core/editor/hooks/use-editor-store-refs.ts
10959
- import { useRef as useRef3, useEffect as useEffect4 } from "react";
11053
+ import { useRef as useRef4, useEffect as useEffect5 } from "react";
10960
11054
  function useEditorStoreRefs() {
10961
11055
  const store = useEditorStore();
10962
11056
  const refs = {
10963
- stopTextEditing: useRef3(store.stopTextEditing),
10964
- updateElementContent: useRef3(store.updateElementContent),
10965
- setSlashCommand: useRef3(store.setSlashCommand),
10966
- clearSlashCommand: useRef3(store.clearSlashCommand),
10967
- findAdjacentElement: useRef3(store.findAdjacentElement),
10968
- deleteElement: useRef3(store.deleteElement),
10969
- setFocusIdx: useRef3(store.setFocusIdx),
10970
- requestTextEditingOnElement: useRef3(store.requestTextEditingOnElement),
10971
- clearPendingTextEditRequest: useRef3(store.clearPendingTextEditRequest),
10972
- template: useRef3(store.template),
10973
- slashCommand: useRef3(store.slashCommand),
10974
- pushHistory: useRef3(store.pushHistory)
11057
+ stopTextEditing: useRef4(store.stopTextEditing),
11058
+ updateElementContent: useRef4(store.updateElementContent),
11059
+ setSlashCommand: useRef4(store.setSlashCommand),
11060
+ clearSlashCommand: useRef4(store.clearSlashCommand),
11061
+ findAdjacentElement: useRef4(store.findAdjacentElement),
11062
+ deleteElement: useRef4(store.deleteElement),
11063
+ setFocusIdx: useRef4(store.setFocusIdx),
11064
+ requestTextEditingOnElement: useRef4(store.requestTextEditingOnElement),
11065
+ clearPendingTextEditRequest: useRef4(store.clearPendingTextEditRequest),
11066
+ template: useRef4(store.template),
11067
+ slashCommand: useRef4(store.slashCommand),
11068
+ mergeFieldSuggestion: useRef4(store.mergeFieldSuggestion),
11069
+ setMergeFieldSuggestion: useRef4(store.setMergeFieldSuggestion),
11070
+ clearMergeFieldSuggestion: useRef4(store.clearMergeFieldSuggestion),
11071
+ pushHistory: useRef4(store.pushHistory)
10975
11072
  };
10976
- useEffect4(() => {
11073
+ useEffect5(() => {
10977
11074
  refs.stopTextEditing.current = store.stopTextEditing;
10978
11075
  refs.updateElementContent.current = store.updateElementContent;
10979
11076
  refs.setSlashCommand.current = store.setSlashCommand;
@@ -10985,6 +11082,9 @@ function useEditorStoreRefs() {
10985
11082
  refs.clearPendingTextEditRequest.current = store.clearPendingTextEditRequest;
10986
11083
  refs.template.current = store.template;
10987
11084
  refs.slashCommand.current = store.slashCommand;
11085
+ refs.mergeFieldSuggestion.current = store.mergeFieldSuggestion;
11086
+ refs.setMergeFieldSuggestion.current = store.setMergeFieldSuggestion;
11087
+ refs.clearMergeFieldSuggestion.current = store.clearMergeFieldSuggestion;
10988
11088
  refs.pushHistory.current = store.pushHistory;
10989
11089
  }, [
10990
11090
  store.stopTextEditing,
@@ -10998,6 +11098,9 @@ function useEditorStoreRefs() {
10998
11098
  store.clearPendingTextEditRequest,
10999
11099
  store.template,
11000
11100
  store.slashCommand,
11101
+ store.mergeFieldSuggestion,
11102
+ store.setMergeFieldSuggestion,
11103
+ store.clearMergeFieldSuggestion,
11001
11104
  store.pushHistory
11002
11105
  ]);
11003
11106
  return refs;
@@ -11045,12 +11148,12 @@ function checkElementPosition(template, elementIdx) {
11045
11148
 
11046
11149
  // src/components/ui/tooltip.tsx
11047
11150
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
11048
- import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
11151
+ import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
11049
11152
  function TooltipProvider({
11050
11153
  delayDuration = 0,
11051
11154
  ...props
11052
11155
  }) {
11053
- return /* @__PURE__ */ jsx14(
11156
+ return /* @__PURE__ */ jsx15(
11054
11157
  TooltipPrimitive.Provider,
11055
11158
  {
11056
11159
  "data-slot": "tooltip-provider",
@@ -11062,12 +11165,12 @@ function TooltipProvider({
11062
11165
  function Tooltip({
11063
11166
  ...props
11064
11167
  }) {
11065
- return /* @__PURE__ */ jsx14(TooltipProvider, { children: /* @__PURE__ */ jsx14(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
11168
+ return /* @__PURE__ */ jsx15(TooltipProvider, { children: /* @__PURE__ */ jsx15(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
11066
11169
  }
11067
11170
  function TooltipTrigger({
11068
11171
  ...props
11069
11172
  }) {
11070
- return /* @__PURE__ */ jsx14(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
11173
+ return /* @__PURE__ */ jsx15(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
11071
11174
  }
11072
11175
  function TooltipContent({
11073
11176
  className,
@@ -11075,7 +11178,7 @@ function TooltipContent({
11075
11178
  children,
11076
11179
  ...props
11077
11180
  }) {
11078
- return /* @__PURE__ */ jsx14(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs5(
11181
+ return /* @__PURE__ */ jsx15(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs6(
11079
11182
  TooltipPrimitive.Content,
11080
11183
  {
11081
11184
  "data-slot": "tooltip-content",
@@ -11087,7 +11190,7 @@ function TooltipContent({
11087
11190
  ...props,
11088
11191
  children: [
11089
11192
  children,
11090
- /* @__PURE__ */ jsx14(TooltipPrimitive.Arrow, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
11193
+ /* @__PURE__ */ jsx15(TooltipPrimitive.Arrow, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
11091
11194
  ]
11092
11195
  }
11093
11196
  ) });
@@ -11097,12 +11200,12 @@ function TooltipContent({
11097
11200
  import { BotIcon } from "lucide-react";
11098
11201
 
11099
11202
  // src/core/editor/components/text-link-menu.tsx
11100
- import { useState, useEffect as useEffect5 } from "react";
11203
+ import { useState as useState2, useEffect as useEffect6 } from "react";
11101
11204
 
11102
11205
  // src/components/ui/input.tsx
11103
- import { jsx as jsx15 } from "react/jsx-runtime";
11206
+ import { jsx as jsx16 } from "react/jsx-runtime";
11104
11207
  function Input({ className, type, ...props }) {
11105
- return /* @__PURE__ */ jsx15(
11208
+ return /* @__PURE__ */ jsx16(
11106
11209
  "input",
11107
11210
  {
11108
11211
  type,
@@ -11123,12 +11226,12 @@ import { CheckIcon, CopyIcon, LinkIcon as LinkIcon2, PencilIcon, TrashIcon } fro
11123
11226
 
11124
11227
  // src/components/ui/label.tsx
11125
11228
  import * as LabelPrimitive from "@radix-ui/react-label";
11126
- import { jsx as jsx16 } from "react/jsx-runtime";
11229
+ import { jsx as jsx17 } from "react/jsx-runtime";
11127
11230
  function Label({
11128
11231
  className,
11129
11232
  ...props
11130
11233
  }) {
11131
- return /* @__PURE__ */ jsx16(
11234
+ return /* @__PURE__ */ jsx17(
11132
11235
  LabelPrimitive.Root,
11133
11236
  {
11134
11237
  "data-slot": "label",
@@ -11143,14 +11246,14 @@ function Label({
11143
11246
 
11144
11247
  // src/components/ui/separator.tsx
11145
11248
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
11146
- import { jsx as jsx17 } from "react/jsx-runtime";
11249
+ import { jsx as jsx18 } from "react/jsx-runtime";
11147
11250
  function Separator({
11148
11251
  className,
11149
11252
  orientation = "horizontal",
11150
11253
  decorative = true,
11151
11254
  ...props
11152
11255
  }) {
11153
- return /* @__PURE__ */ jsx17(
11256
+ return /* @__PURE__ */ jsx18(
11154
11257
  SeparatorPrimitive.Root,
11155
11258
  {
11156
11259
  "data-slot": "separator",
@@ -11170,16 +11273,16 @@ var floatButtonVariants = "shadow-none transition-none cursor-pointer rounded-fu
11170
11273
 
11171
11274
  // src/components/ui/popover.tsx
11172
11275
  import * as PopoverPrimitive from "@radix-ui/react-popover";
11173
- import { jsx as jsx18 } from "react/jsx-runtime";
11276
+ import { jsx as jsx19 } from "react/jsx-runtime";
11174
11277
  function Popover({
11175
11278
  ...props
11176
11279
  }) {
11177
- return /* @__PURE__ */ jsx18(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
11280
+ return /* @__PURE__ */ jsx19(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
11178
11281
  }
11179
11282
  function PopoverTrigger({
11180
11283
  ...props
11181
11284
  }) {
11182
- return /* @__PURE__ */ jsx18(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
11285
+ return /* @__PURE__ */ jsx19(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
11183
11286
  }
11184
11287
  function PopoverContent({
11185
11288
  className,
@@ -11187,7 +11290,7 @@ function PopoverContent({
11187
11290
  sideOffset = 4,
11188
11291
  ...props
11189
11292
  }) {
11190
- return /* @__PURE__ */ jsx18(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx18(
11293
+ return /* @__PURE__ */ jsx19(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx19(
11191
11294
  PopoverPrimitive.Content,
11192
11295
  {
11193
11296
  "data-slot": "popover-content",
@@ -11203,16 +11306,16 @@ function PopoverContent({
11203
11306
  }
11204
11307
 
11205
11308
  // src/core/editor/components/text-link-menu.tsx
11206
- import { jsx as jsx19, jsxs as jsxs6 } from "react/jsx-runtime";
11309
+ import { jsx as jsx20, jsxs as jsxs7 } from "react/jsx-runtime";
11207
11310
  var TextLinkMenu = ({ editor }) => {
11208
- const [isOpen, setIsOpen] = useState(false);
11209
- const [inputValue, setInputValue] = useState("");
11210
- const [showCopied, setShowCopied] = useState(false);
11211
- const [linkType, setLinkType] = useState(LINK_TYPES[1]);
11212
- const [isLinkTypeOpen, setIsLinkTypeOpen] = useState(false);
11311
+ const [isOpen, setIsOpen] = useState2(false);
11312
+ const [inputValue, setInputValue] = useState2("");
11313
+ const [showCopied, setShowCopied] = useState2(false);
11314
+ const [linkType, setLinkType] = useState2(LINK_TYPES[1]);
11315
+ const [isLinkTypeOpen, setIsLinkTypeOpen] = useState2(false);
11213
11316
  const currentHref = editor.getAttributes("link").href || "";
11214
11317
  const hasLink = !!currentHref;
11215
- useEffect5(() => {
11318
+ useEffect6(() => {
11216
11319
  if (isOpen) {
11217
11320
  setLinkType(detectLinkType(currentHref));
11218
11321
  setInputValue(stripPrefix(currentHref));
@@ -11254,42 +11357,42 @@ var TextLinkMenu = ({ editor }) => {
11254
11357
  editor.chain().focus().unsetLink().run();
11255
11358
  setInputValue("");
11256
11359
  };
11257
- return /* @__PURE__ */ jsxs6(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
11258
- /* @__PURE__ */ jsxs6(Tooltip, { children: [
11259
- /* @__PURE__ */ jsx19(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(PopoverTrigger, { asChild: true, children: hasLink ? /* @__PURE__ */ jsx19(
11360
+ return /* @__PURE__ */ jsxs7(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
11361
+ /* @__PURE__ */ jsxs7(Tooltip, { children: [
11362
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(PopoverTrigger, { asChild: true, children: hasLink ? /* @__PURE__ */ jsx20(
11260
11363
  Button,
11261
11364
  {
11262
11365
  variant: "ghost",
11263
11366
  size: "icon",
11264
11367
  className: floatButtonVariants,
11265
11368
  onMouseDown: (e) => e.preventDefault(),
11266
- children: /* @__PURE__ */ jsx19(PencilIcon, { className: "size-4" })
11369
+ children: /* @__PURE__ */ jsx20(PencilIcon, { className: "size-4" })
11267
11370
  }
11268
- ) : /* @__PURE__ */ jsxs6(
11371
+ ) : /* @__PURE__ */ jsxs7(
11269
11372
  Button,
11270
11373
  {
11271
11374
  variant: "ghost",
11272
11375
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none h-[34px]",
11273
11376
  onMouseDown: (e) => e.preventDefault(),
11274
11377
  children: [
11275
- /* @__PURE__ */ jsx19(LinkIcon2, { className: "size-4" }),
11276
- /* @__PURE__ */ jsx19("p", { children: "Add link" })
11378
+ /* @__PURE__ */ jsx20(LinkIcon2, { className: "size-4" }),
11379
+ /* @__PURE__ */ jsx20("p", { children: "Add link" })
11277
11380
  ]
11278
11381
  }
11279
11382
  ) }) }),
11280
- /* @__PURE__ */ jsx19(TooltipContent, { side: "bottom", children: hasLink ? "Edit link" : "Add link" })
11383
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", children: hasLink ? "Edit link" : "Add link" })
11281
11384
  ] }),
11282
- /* @__PURE__ */ jsxs6(
11385
+ /* @__PURE__ */ jsxs7(
11283
11386
  PopoverContent,
11284
11387
  {
11285
11388
  side: "bottom",
11286
11389
  className: "w-[250px] p-3 shadow-lg z-50001",
11287
11390
  "data-editor-toolbar": true,
11288
11391
  children: [
11289
- /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-2", children: [
11290
- /* @__PURE__ */ jsx19(Label, { children: "Enter a link" }),
11291
- /* @__PURE__ */ jsxs6("div", { className: "relative", children: [
11292
- /* @__PURE__ */ jsx19(
11392
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2", children: [
11393
+ /* @__PURE__ */ jsx20(Label, { children: "Enter a link" }),
11394
+ /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
11395
+ /* @__PURE__ */ jsx20(
11293
11396
  Input,
11294
11397
  {
11295
11398
  type: linkType.inputType,
@@ -11301,12 +11404,12 @@ var TextLinkMenu = ({ editor }) => {
11301
11404
  autoFocus: true
11302
11405
  }
11303
11406
  ),
11304
- /* @__PURE__ */ jsxs6(Popover, { open: isLinkTypeOpen, onOpenChange: setIsLinkTypeOpen, children: [
11305
- /* @__PURE__ */ jsxs6(Tooltip, { children: [
11306
- /* @__PURE__ */ jsx19(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(Button, { size: "icon", variant: "ghost", className: "absolute shadow-none rounded-[12px] left-1.5 top-1/2 -translate-y-1/2 h-[34px] w-[34px] cursor-pointer", children: /* @__PURE__ */ jsx19(linkType.icon, {}) }) }) }),
11307
- /* @__PURE__ */ jsx19(TooltipContent, { side: "top", className: "z-50001", children: "Link Type" })
11407
+ /* @__PURE__ */ jsxs7(Popover, { open: isLinkTypeOpen, onOpenChange: setIsLinkTypeOpen, children: [
11408
+ /* @__PURE__ */ jsxs7(Tooltip, { children: [
11409
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(Button, { size: "icon", variant: "ghost", className: "absolute shadow-none rounded-[12px] left-1.5 top-1/2 -translate-y-1/2 h-[34px] w-[34px] cursor-pointer", children: /* @__PURE__ */ jsx20(linkType.icon, {}) }) }) }),
11410
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "top", className: "z-50001", children: "Link Type" })
11308
11411
  ] }),
11309
- /* @__PURE__ */ jsx19(
11412
+ /* @__PURE__ */ jsx20(
11310
11413
  PopoverContent,
11311
11414
  {
11312
11415
  side: "bottom",
@@ -11314,7 +11417,7 @@ var TextLinkMenu = ({ editor }) => {
11314
11417
  className: "w-[160px] p-1 z-50001",
11315
11418
  onPointerDownOutside: (e) => e.preventDefault(),
11316
11419
  "data-editor-toolbar": true,
11317
- children: LINK_TYPES.map((type) => /* @__PURE__ */ jsxs6(
11420
+ children: LINK_TYPES.map((type) => /* @__PURE__ */ jsxs7(
11318
11421
  Button,
11319
11422
  {
11320
11423
  variant: "ghost",
@@ -11325,11 +11428,11 @@ var TextLinkMenu = ({ editor }) => {
11325
11428
  setIsLinkTypeOpen(false);
11326
11429
  },
11327
11430
  children: [
11328
- /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-2", children: [
11329
- /* @__PURE__ */ jsx19(type.icon, { className: "size-4" }),
11431
+ /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-2", children: [
11432
+ /* @__PURE__ */ jsx20(type.icon, { className: "size-4" }),
11330
11433
  type.name
11331
11434
  ] }),
11332
- linkType.name === type.name && /* @__PURE__ */ jsx19(CheckIcon, { className: "size-4" })
11435
+ linkType.name === type.name && /* @__PURE__ */ jsx20(CheckIcon, { className: "size-4" })
11333
11436
  ]
11334
11437
  },
11335
11438
  type.name
@@ -11339,11 +11442,11 @@ var TextLinkMenu = ({ editor }) => {
11339
11442
  ] })
11340
11443
  ] })
11341
11444
  ] }),
11342
- /* @__PURE__ */ jsx19(Separator, { className: "my-2" }),
11343
- /* @__PURE__ */ jsxs6("div", { className: "flex flex-row justify-between items-center", children: [
11344
- /* @__PURE__ */ jsxs6("div", { className: "flex flex-row", children: [
11345
- /* @__PURE__ */ jsxs6(Tooltip, { children: [
11346
- /* @__PURE__ */ jsx19(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(
11445
+ /* @__PURE__ */ jsx20(Separator, { className: "my-2" }),
11446
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-row justify-between items-center", children: [
11447
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-row", children: [
11448
+ /* @__PURE__ */ jsxs7(Tooltip, { children: [
11449
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(
11347
11450
  Button,
11348
11451
  {
11349
11452
  variant: "ghost",
@@ -11351,13 +11454,13 @@ var TextLinkMenu = ({ editor }) => {
11351
11454
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
11352
11455
  onClick: handleCopy,
11353
11456
  disabled: !hasLink,
11354
- children: showCopied ? /* @__PURE__ */ jsx19(CheckIcon, { className: "text-green-600" }) : /* @__PURE__ */ jsx19(CopyIcon, {})
11457
+ children: showCopied ? /* @__PURE__ */ jsx20(CheckIcon, { className: "text-green-600" }) : /* @__PURE__ */ jsx20(CopyIcon, {})
11355
11458
  }
11356
11459
  ) }),
11357
- /* @__PURE__ */ jsx19(TooltipContent, { side: "bottom", className: "z-50001", children: showCopied ? "Copied!" : "Copy link" })
11460
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", className: "z-50001", children: showCopied ? "Copied!" : "Copy link" })
11358
11461
  ] }),
11359
- /* @__PURE__ */ jsxs6(Tooltip, { children: [
11360
- /* @__PURE__ */ jsx19(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(
11462
+ /* @__PURE__ */ jsxs7(Tooltip, { children: [
11463
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(
11361
11464
  Button,
11362
11465
  {
11363
11466
  variant: "ghost",
@@ -11365,13 +11468,13 @@ var TextLinkMenu = ({ editor }) => {
11365
11468
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
11366
11469
  onClick: handleRemoveLink,
11367
11470
  disabled: !hasLink,
11368
- children: /* @__PURE__ */ jsx19(TrashIcon, {})
11471
+ children: /* @__PURE__ */ jsx20(TrashIcon, {})
11369
11472
  }
11370
11473
  ) }),
11371
- /* @__PURE__ */ jsx19(TooltipContent, { side: "bottom", className: "z-50001", children: "Remove link" })
11474
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", className: "z-50001", children: "Remove link" })
11372
11475
  ] })
11373
11476
  ] }),
11374
- /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(
11477
+ /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(
11375
11478
  Button,
11376
11479
  {
11377
11480
  variant: "default",
@@ -11388,16 +11491,16 @@ var TextLinkMenu = ({ editor }) => {
11388
11491
  };
11389
11492
 
11390
11493
  // src/core/editor/components/float-link-preview.tsx
11391
- import { jsx as jsx20, jsxs as jsxs7 } from "react/jsx-runtime";
11494
+ import { jsx as jsx21, jsxs as jsxs8 } from "react/jsx-runtime";
11392
11495
  var FloatLinkPreview = ({ href }) => {
11393
- return /* @__PURE__ */ jsxs7(Tooltip, { children: [
11394
- /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20("div", { className: "max-w-[150px] min-w-[25px] h-[34px] px-4 hover:bg-accent rounded-full flex items-center justify-start", children: /* @__PURE__ */ jsx20("a", { href, target: "_blank", className: "shadow-none transition-none cursor-pointer outline-none text-[16px] text-blue-400 truncate", children: href }) }) }),
11395
- /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", children: href })
11496
+ return /* @__PURE__ */ jsxs8(Tooltip, { children: [
11497
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21("div", { className: "max-w-[150px] min-w-[25px] h-[34px] px-4 hover:bg-accent rounded-full flex items-center justify-start", children: /* @__PURE__ */ jsx21("a", { href, target: "_blank", className: "shadow-none transition-none cursor-pointer outline-none text-[16px] text-blue-400 truncate", children: href }) }) }),
11498
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", children: href })
11396
11499
  ] });
11397
11500
  };
11398
11501
 
11399
11502
  // src/core/editor/components/tiptap-overlay.tsx
11400
- import { jsx as jsx21, jsxs as jsxs8 } from "react/jsx-runtime";
11503
+ import { jsx as jsx22, jsxs as jsxs9 } from "react/jsx-runtime";
11401
11504
  var FontFamily = Extension.create({
11402
11505
  name: "fontFamily",
11403
11506
  addGlobalAttributes() {
@@ -11575,7 +11678,8 @@ var TIPTAP_EXTENSIONS = [
11575
11678
  emptyNodeClass: "is-empty-placeholder",
11576
11679
  paragraphPlaceholder: "Start typing...",
11577
11680
  headingPlaceholder: "Heading"
11578
- })
11681
+ }),
11682
+ MergeFieldDecoration
11579
11683
  ];
11580
11684
  function isNodeEmpty2(node) {
11581
11685
  if (!node) return true;
@@ -11706,16 +11810,16 @@ function handleBackspaceOrDelete(view, event, currentElementIdx, storeRefs) {
11706
11810
  var TiptapOverlay = () => {
11707
11811
  const textEditing = useEditorStore((s) => s.textEditing);
11708
11812
  if (!textEditing) return null;
11709
- return /* @__PURE__ */ jsx21(TiptapOverlayContent, { ...textEditing }, textEditing.idx);
11813
+ return /* @__PURE__ */ jsx22(TiptapOverlayContent, { ...textEditing }, textEditing.idx);
11710
11814
  };
11711
11815
  var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWidth, initialHeight, clickX, clickY, content, styles, cursorPosition }) => {
11712
- const containerRef = useRef4(null);
11816
+ const containerRef = useRef5(null);
11713
11817
  const setTiptapEditor = useEditorStore((s) => s.setTiptapEditor);
11714
11818
  const linkColor = useEditorStore((s) => s.template?.content?.[0]?.data?.value?.linkColor) || "#0000ff";
11715
- const lastSizeLimitToastRef = useRef4(0);
11716
- const hasContentChangedRef = useRef4(false);
11819
+ const lastSizeLimitToastRef = useRef5(0);
11820
+ const hasContentChangedRef = useRef5(false);
11717
11821
  const storeRefs = useEditorStoreRefs();
11718
- useEffect6(() => {
11822
+ useEffect7(() => {
11719
11823
  return () => {
11720
11824
  const isUndoRedoAction = useEditorStore.getState().isUndoRedoAction;
11721
11825
  if (hasContentChangedRef.current && !isUndoRedoAction) {
@@ -11723,7 +11827,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11723
11827
  }
11724
11828
  };
11725
11829
  }, []);
11726
- useEffect6(() => {
11830
+ useEffect7(() => {
11727
11831
  const container = containerRef.current;
11728
11832
  if (!container) return;
11729
11833
  const observer = new ResizeObserver(() => {
@@ -11741,10 +11845,10 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11741
11845
  }
11742
11846
  };
11743
11847
  }, [getShadowElement]);
11744
- const cleanedContent = useMemo3(() => {
11848
+ const cleanedContent = useMemo4(() => {
11745
11849
  return content.replace(NBSP_P_CONTENT_REGEX, "<p$1></p>").replace(IS_EMPTY_P_CLASS_REGEX, "").replace(IS_EMPTY_HEADING_CLASS_REGEX, "");
11746
11850
  }, [content]);
11747
- const lineHeightRatio = useMemo3(() => {
11851
+ const lineHeightRatio = useMemo4(() => {
11748
11852
  const lineHeightPx = parseFloat(styles.lineHeight);
11749
11853
  const fontSizePx = parseFloat(styles.fontSize);
11750
11854
  if (isNaN(lineHeightPx) || isNaN(fontSizePx) || fontSizePx === 0) {
@@ -11752,7 +11856,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11752
11856
  }
11753
11857
  return lineHeightPx / fontSizePx;
11754
11858
  }, [styles.lineHeight, styles.fontSize]);
11755
- const virtualReference = useMemo3(() => ({
11859
+ const virtualReference = useMemo4(() => ({
11756
11860
  getBoundingClientRect: () => {
11757
11861
  const rect = getReferenceRect();
11758
11862
  if (!rect) {
@@ -11761,14 +11865,14 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11761
11865
  return rect;
11762
11866
  }
11763
11867
  }), [getReferenceRect]);
11764
- const { floatingStyles, refs, update } = useFloating3({
11868
+ const { floatingStyles, refs, update } = useFloating4({
11765
11869
  placement: "bottom-start",
11766
11870
  middleware: [
11767
- offset3(({ rects }) => -rects.reference.height)
11871
+ offset4(({ rects }) => -rects.reference.height)
11768
11872
  // Move up by reference height to overlay exactly
11769
11873
  ]
11770
11874
  });
11771
- useEffect6(() => {
11875
+ useEffect7(() => {
11772
11876
  const rect = getReferenceRect();
11773
11877
  if (!rect || !refs.floating.current) return;
11774
11878
  refs.setPositionReference(virtualReference);
@@ -11807,17 +11911,36 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11807
11911
  }
11808
11912
  }
11809
11913
  const isSlashCommandActive = storeRefs.slashCommand.current?.isActive;
11810
- if (event.key === "Escape" && isSlashCommandActive) {
11811
- storeRefs.clearSlashCommand.current();
11812
- return true;
11914
+ const isMergeFieldActive = storeRefs.mergeFieldSuggestion.current?.isActive;
11915
+ if (event.key === "Escape") {
11916
+ if (isSlashCommandActive) {
11917
+ storeRefs.clearSlashCommand.current();
11918
+ return true;
11919
+ }
11920
+ if (isMergeFieldActive) {
11921
+ storeRefs.clearMergeFieldSuggestion.current();
11922
+ return true;
11923
+ }
11813
11924
  }
11814
- if (event.key === " " && isSlashCommandActive) {
11815
- storeRefs.clearSlashCommand.current();
11816
- return false;
11925
+ if (event.key === " ") {
11926
+ if (isSlashCommandActive) {
11927
+ storeRefs.clearSlashCommand.current();
11928
+ return false;
11929
+ }
11930
+ if (isMergeFieldActive) {
11931
+ storeRefs.clearMergeFieldSuggestion.current();
11932
+ return false;
11933
+ }
11817
11934
  }
11818
- if ((event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") && isSlashCommandActive) {
11819
- storeRefs.clearSlashCommand.current();
11820
- return false;
11935
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") {
11936
+ if (isSlashCommandActive) {
11937
+ storeRefs.clearSlashCommand.current();
11938
+ return false;
11939
+ }
11940
+ if (isMergeFieldActive) {
11941
+ storeRefs.clearMergeFieldSuggestion.current();
11942
+ return false;
11943
+ }
11821
11944
  }
11822
11945
  if (event.key === "/") {
11823
11946
  const { from } = view.state.selection;
@@ -11839,6 +11962,33 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11839
11962
  });
11840
11963
  }
11841
11964
  }
11965
+ if (event.key === "{") {
11966
+ const { from } = view.state.selection;
11967
+ const textBefore = view.state.doc.textBetween(Math.max(0, from - 1), from);
11968
+ if (textBefore === "{") {
11969
+ const coords = view.coordsAtPos(from);
11970
+ if (coords && coords.left > 0 && coords.top > 0) {
11971
+ const lineHeight = parseInt(styles.lineHeight) || 20;
11972
+ storeRefs.setMergeFieldSuggestion.current({
11973
+ isActive: true,
11974
+ cursorRect: { top: coords.top, left: coords.left, height: lineHeight },
11975
+ triggerPosition: from - 1
11976
+ // Position of first "{"
11977
+ });
11978
+ }
11979
+ }
11980
+ }
11981
+ if (event.key === "}" && isMergeFieldActive) {
11982
+ storeRefs.clearMergeFieldSuggestion.current();
11983
+ return false;
11984
+ }
11985
+ if (event.key === "Backspace" && isMergeFieldActive) {
11986
+ const { from } = view.state.selection;
11987
+ const triggerPos = storeRefs.mergeFieldSuggestion.current?.triggerPosition ?? 0;
11988
+ if (from <= triggerPos + 2) {
11989
+ storeRefs.clearMergeFieldSuggestion.current();
11990
+ }
11991
+ }
11842
11992
  if (event.key === "Backspace" || event.key === "Delete") {
11843
11993
  const handled = handleBackspaceOrDelete(
11844
11994
  view,
@@ -11905,8 +12055,8 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11905
12055
  storeRefs.updateElementContent.current(`${idx}.data.value.content`, html);
11906
12056
  }
11907
12057
  });
11908
- const [currentLinkHref, setCurrentLinkHref] = useState2("");
11909
- useEffect6(() => {
12058
+ const [currentLinkHref, setCurrentLinkHref] = useState3("");
12059
+ useEffect7(() => {
11910
12060
  if (!editor) return;
11911
12061
  setTiptapEditor(editor);
11912
12062
  const updateLinkHref = () => {
@@ -11921,7 +12071,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11921
12071
  editor.off("transaction", updateLinkHref);
11922
12072
  };
11923
12073
  }, [editor, setTiptapEditor]);
11924
- useEffect6(() => {
12074
+ useEffect7(() => {
11925
12075
  if (editor) {
11926
12076
  const timer = setTimeout(() => {
11927
12077
  if (cursorPosition === "end") {
@@ -11950,7 +12100,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11950
12100
  return () => clearTimeout(timer);
11951
12101
  }
11952
12102
  }, [editor, clickX, clickY, cursorPosition]);
11953
- useEffect6(() => {
12103
+ useEffect7(() => {
11954
12104
  const handleClickOutside = (e) => {
11955
12105
  const target = e.target;
11956
12106
  if (containerRef.current && containerRef.current.contains(target)) {
@@ -11972,7 +12122,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
11972
12122
  document.removeEventListener("mousedown", handleClickOutside);
11973
12123
  };
11974
12124
  }, []);
11975
- return /* @__PURE__ */ jsxs8(
12125
+ return /* @__PURE__ */ jsxs9(
11976
12126
  "div",
11977
12127
  {
11978
12128
  ref: (node) => {
@@ -12005,7 +12155,7 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
12005
12155
  boxSizing: "border-box"
12006
12156
  },
12007
12157
  children: [
12008
- /* @__PURE__ */ jsx21("style", { children: `
12158
+ /* @__PURE__ */ jsx22("style", { children: `
12009
12159
  .tiptap-overlay {
12010
12160
  margin: 0;
12011
12161
  padding: 0;
@@ -12071,6 +12221,16 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
12071
12221
  transform: translateY(-50%);
12072
12222
  text-align: inherit;
12073
12223
  }
12224
+ .tiptap-overlay .ProseMirror .merge-field-tag {
12225
+ background-color: var(--background);
12226
+ border-radius: 4px;
12227
+ padding: 4px;
12228
+ border: 1px solid var(--border);
12229
+ color: #000000;
12230
+ }
12231
+ .tiptap-overlay .ProseMirror .merge-field-tag:hover {
12232
+ cursor: pointer;
12233
+ }
12074
12234
  .tiptap-overlay .ProseMirror a {
12075
12235
  color: ${linkColor};
12076
12236
  text-decoration: none;
@@ -12080,36 +12240,36 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
12080
12240
  text-decoration: underline;
12081
12241
  }
12082
12242
  ` }),
12083
- /* @__PURE__ */ jsx21(
12243
+ /* @__PURE__ */ jsx22(
12084
12244
  EditorContent,
12085
12245
  {
12086
12246
  editor,
12087
12247
  className: "tiptap-overlay"
12088
12248
  }
12089
12249
  ),
12090
- editor && /* @__PURE__ */ jsx21(
12250
+ editor && /* @__PURE__ */ jsx22(
12091
12251
  BubbleMenu,
12092
12252
  {
12093
12253
  editor,
12094
12254
  options: { placement: "top", offset: 8, flip: true },
12095
12255
  updateDelay: 0,
12096
- children: /* @__PURE__ */ jsxs8("div", { className: "bg-white flex items-center justify-center border h-[36px] w-fit shadow-md rounded-full text-[16px]", children: [
12097
- /* @__PURE__ */ jsxs8(Tooltip, { children: [
12098
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(
12256
+ children: /* @__PURE__ */ jsxs9("div", { className: "bg-white flex items-center justify-center border h-[36px] w-fit shadow-md rounded-full text-[16px]", children: [
12257
+ /* @__PURE__ */ jsxs9(Tooltip, { children: [
12258
+ /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9(
12099
12259
  Button,
12100
12260
  {
12101
12261
  variant: "ghost",
12102
12262
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none h-[34px]",
12103
12263
  children: [
12104
- /* @__PURE__ */ jsx21(BotIcon, { className: "size-4" }),
12105
- /* @__PURE__ */ jsx21("p", { children: "Magic Write" })
12264
+ /* @__PURE__ */ jsx22(BotIcon, { className: "size-4" }),
12265
+ /* @__PURE__ */ jsx22("p", { children: "Magic Write" })
12106
12266
  ]
12107
12267
  }
12108
12268
  ) }),
12109
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", children: "Ask Maillow" })
12269
+ /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", children: "Ask Maillow" })
12110
12270
  ] }),
12111
- currentLinkHref && /* @__PURE__ */ jsx21(FloatLinkPreview, { href: currentLinkHref }),
12112
- /* @__PURE__ */ jsx21(TextLinkMenu, { editor })
12271
+ currentLinkHref && /* @__PURE__ */ jsx22(FloatLinkPreview, { href: currentLinkHref }),
12272
+ /* @__PURE__ */ jsx22(TextLinkMenu, { editor })
12113
12273
  ] })
12114
12274
  }
12115
12275
  )
@@ -12119,12 +12279,12 @@ var TiptapOverlayContent = ({ idx, getReferenceRect, getShadowElement, initialWi
12119
12279
  };
12120
12280
 
12121
12281
  // src/core/editor/components/element-float.tsx
12122
- import { useEffect as useEffect12, useMemo as useMemo11 } from "react";
12123
- import { useFloating as useFloating4, offset as offset4, shift as shift3, flip as flip2, autoUpdate as autoUpdate3 } from "@floating-ui/react";
12282
+ import { useEffect as useEffect13, useMemo as useMemo12 } from "react";
12283
+ import { useFloating as useFloating5, offset as offset5, shift as shift4, flip as flip3, autoUpdate as autoUpdate3 } from "@floating-ui/react";
12124
12284
 
12125
12285
  // src/core/editor/components/float-ui/actions/delete-button.tsx
12126
12286
  import { TrashIcon as TrashIcon2 } from "lucide-react";
12127
- import { jsx as jsx22, jsxs as jsxs9 } from "react/jsx-runtime";
12287
+ import { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
12128
12288
  var DeleteButton = () => {
12129
12289
  const { focusIdx, deleteElement } = useEditorStore();
12130
12290
  const handleDelete = () => {
@@ -12132,23 +12292,23 @@ var DeleteButton = () => {
12132
12292
  deleteElement(focusIdx);
12133
12293
  }
12134
12294
  };
12135
- return /* @__PURE__ */ jsxs9(Tooltip, { children: [
12136
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
12295
+ return /* @__PURE__ */ jsxs10(Tooltip, { children: [
12296
+ /* @__PURE__ */ jsx23(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx23(
12137
12297
  Button,
12138
12298
  {
12139
12299
  variant: "ghost",
12140
12300
  className: floatButtonVariants,
12141
12301
  onClick: handleDelete,
12142
- children: /* @__PURE__ */ jsx22(TrashIcon2, { className: "size-4" })
12302
+ children: /* @__PURE__ */ jsx23(TrashIcon2, { className: "size-4" })
12143
12303
  }
12144
12304
  ) }),
12145
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", children: "Delete" })
12305
+ /* @__PURE__ */ jsx23(TooltipContent, { side: "bottom", children: "Delete" })
12146
12306
  ] });
12147
12307
  };
12148
12308
 
12149
12309
  // src/core/editor/components/float-ui/actions/dulicate-button.tsx
12150
12310
  import { CopyIcon as CopyIcon2 } from "lucide-react";
12151
- import { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
12311
+ import { jsx as jsx24, jsxs as jsxs11 } from "react/jsx-runtime";
12152
12312
  var DuplicateButton = () => {
12153
12313
  const { focusIdx, duplicateElement } = useEditorStore();
12154
12314
  const isAtSizeLimit = useEditorStore((state) => state.isAtSizeLimit);
@@ -12157,42 +12317,42 @@ var DuplicateButton = () => {
12157
12317
  duplicateElement(focusIdx);
12158
12318
  }
12159
12319
  };
12160
- return /* @__PURE__ */ jsxs10(Tooltip, { children: [
12161
- /* @__PURE__ */ jsx23(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx23(
12320
+ return /* @__PURE__ */ jsxs11(Tooltip, { children: [
12321
+ /* @__PURE__ */ jsx24(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx24(
12162
12322
  Button,
12163
12323
  {
12164
12324
  variant: "ghost",
12165
12325
  className: floatButtonVariants,
12166
12326
  onClick: handleDuplicate,
12167
12327
  disabled: isAtSizeLimit,
12168
- children: /* @__PURE__ */ jsx23(CopyIcon2, { className: "size-4" })
12328
+ children: /* @__PURE__ */ jsx24(CopyIcon2, { className: "size-4" })
12169
12329
  }
12170
12330
  ) }),
12171
- /* @__PURE__ */ jsx23(TooltipContent, { side: "bottom", children: "Duplicate" })
12331
+ /* @__PURE__ */ jsx24(TooltipContent, { side: "bottom", children: "Duplicate" })
12172
12332
  ] });
12173
12333
  };
12174
12334
 
12175
12335
  // src/core/editor/components/href-menu.tsx
12176
- import { useState as useState3, useEffect as useEffect7, useCallback as useCallback4, useMemo as useMemo5 } from "react";
12336
+ import { useState as useState4, useEffect as useEffect8, useCallback as useCallback5, useMemo as useMemo6 } from "react";
12177
12337
 
12178
12338
  // src/components/ui/dropdown-menu.tsx
12179
12339
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
12180
12340
  import { CheckIcon as CheckIcon2, ChevronRightIcon, CircleIcon } from "lucide-react";
12181
- import { jsx as jsx24, jsxs as jsxs11 } from "react/jsx-runtime";
12341
+ import { jsx as jsx25, jsxs as jsxs12 } from "react/jsx-runtime";
12182
12342
  function DropdownMenu({
12183
12343
  ...props
12184
12344
  }) {
12185
- return /* @__PURE__ */ jsx24(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
12345
+ return /* @__PURE__ */ jsx25(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
12186
12346
  }
12187
12347
  function DropdownMenuPortal({
12188
12348
  ...props
12189
12349
  }) {
12190
- return /* @__PURE__ */ jsx24(DropdownMenuPrimitive.Portal, { "data-slot": "dropdown-menu-portal", ...props });
12350
+ return /* @__PURE__ */ jsx25(DropdownMenuPrimitive.Portal, { "data-slot": "dropdown-menu-portal", ...props });
12191
12351
  }
12192
12352
  function DropdownMenuTrigger({
12193
12353
  ...props
12194
12354
  }) {
12195
- return /* @__PURE__ */ jsx24(
12355
+ return /* @__PURE__ */ jsx25(
12196
12356
  DropdownMenuPrimitive.Trigger,
12197
12357
  {
12198
12358
  "data-slot": "dropdown-menu-trigger",
@@ -12205,7 +12365,7 @@ function DropdownMenuContent({
12205
12365
  sideOffset = 4,
12206
12366
  ...props
12207
12367
  }) {
12208
- return /* @__PURE__ */ jsx24(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
12368
+ return /* @__PURE__ */ jsx25(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx25(
12209
12369
  DropdownMenuPrimitive.Content,
12210
12370
  {
12211
12371
  "data-slot": "dropdown-menu-content",
@@ -12224,7 +12384,7 @@ function DropdownMenuItem({
12224
12384
  variant = "default",
12225
12385
  ...props
12226
12386
  }) {
12227
- return /* @__PURE__ */ jsx24(
12387
+ return /* @__PURE__ */ jsx25(
12228
12388
  DropdownMenuPrimitive.Item,
12229
12389
  {
12230
12390
  "data-slot": "dropdown-menu-item",
@@ -12242,7 +12402,7 @@ function DropdownMenuSeparator({
12242
12402
  className,
12243
12403
  ...props
12244
12404
  }) {
12245
- return /* @__PURE__ */ jsx24(
12405
+ return /* @__PURE__ */ jsx25(
12246
12406
  DropdownMenuPrimitive.Separator,
12247
12407
  {
12248
12408
  "data-slot": "dropdown-menu-separator",
@@ -12254,7 +12414,7 @@ function DropdownMenuSeparator({
12254
12414
  function DropdownMenuSub({
12255
12415
  ...props
12256
12416
  }) {
12257
- return /* @__PURE__ */ jsx24(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
12417
+ return /* @__PURE__ */ jsx25(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
12258
12418
  }
12259
12419
  function DropdownMenuSubTrigger({
12260
12420
  className,
@@ -12262,7 +12422,7 @@ function DropdownMenuSubTrigger({
12262
12422
  children,
12263
12423
  ...props
12264
12424
  }) {
12265
- return /* @__PURE__ */ jsxs11(
12425
+ return /* @__PURE__ */ jsxs12(
12266
12426
  DropdownMenuPrimitive.SubTrigger,
12267
12427
  {
12268
12428
  "data-slot": "dropdown-menu-sub-trigger",
@@ -12274,7 +12434,7 @@ function DropdownMenuSubTrigger({
12274
12434
  ...props,
12275
12435
  children: [
12276
12436
  children,
12277
- /* @__PURE__ */ jsx24(ChevronRightIcon, { className: "ml-auto size-4" })
12437
+ /* @__PURE__ */ jsx25(ChevronRightIcon, { className: "ml-auto size-4" })
12278
12438
  ]
12279
12439
  }
12280
12440
  );
@@ -12283,7 +12443,7 @@ function DropdownMenuSubContent({
12283
12443
  className,
12284
12444
  ...props
12285
12445
  }) {
12286
- return /* @__PURE__ */ jsx24(
12446
+ return /* @__PURE__ */ jsx25(
12287
12447
  DropdownMenuPrimitive.SubContent,
12288
12448
  {
12289
12449
  "data-slot": "dropdown-menu-sub-content",
@@ -12300,11 +12460,11 @@ function DropdownMenuSubContent({
12300
12460
  import { CheckIcon as CheckIcon3, CopyIcon as CopyIcon3, LinkIcon as LinkIcon3, PencilIcon as PencilIcon2, TrashIcon as TrashIcon3 } from "lucide-react";
12301
12461
 
12302
12462
  // src/core/editor/hooks/use-href.ts
12303
- import { useMemo as useMemo4, useCallback as useCallback3 } from "react";
12463
+ import { useMemo as useMemo5, useCallback as useCallback4 } from "react";
12304
12464
  import { get as lodashGet2 } from "lodash";
12305
12465
  var useHref = () => {
12306
12466
  const { focusIdx, updateElement, template } = useEditorStore();
12307
- const { element, href } = useMemo4(() => {
12467
+ const { element, href } = useMemo5(() => {
12308
12468
  if (!focusIdx || !template) {
12309
12469
  return { element: null, href: "" };
12310
12470
  }
@@ -12315,19 +12475,19 @@ var useHref = () => {
12315
12475
  href: el?.attributes?.href || ""
12316
12476
  };
12317
12477
  }, [focusIdx, template]);
12318
- const setHref = useCallback3((url) => {
12478
+ const setHref = useCallback4((url) => {
12319
12479
  if (!focusIdx || !element) return;
12320
12480
  updateElement(focusIdx, {
12321
12481
  attributes: { ...element.attributes, href: url }
12322
12482
  });
12323
12483
  }, [focusIdx, element, updateElement]);
12324
- const clearHref = useCallback3(() => {
12484
+ const clearHref = useCallback4(() => {
12325
12485
  if (!focusIdx || !element) return;
12326
12486
  updateElement(focusIdx, {
12327
12487
  attributes: { ...element.attributes, href: "" }
12328
12488
  });
12329
12489
  }, [focusIdx, element, updateElement]);
12330
- const copyHref = useCallback3(async () => {
12490
+ const copyHref = useCallback4(async () => {
12331
12491
  if (href) {
12332
12492
  try {
12333
12493
  await navigator.clipboard.writeText(href);
@@ -12347,18 +12507,18 @@ var useHref = () => {
12347
12507
  };
12348
12508
 
12349
12509
  // src/core/editor/components/href-menu.tsx
12350
- import { jsx as jsx25, jsxs as jsxs12 } from "react/jsx-runtime";
12510
+ import { jsx as jsx26, jsxs as jsxs13 } from "react/jsx-runtime";
12351
12511
  var HrefMenu = () => {
12352
12512
  const { href, setHref, clearHref, copyHref, hasHref } = useHref();
12353
12513
  const userData = useEditorStore((s) => s.userData);
12354
- const [isOpen, setIsOpen] = useState3(false);
12355
- const [inputValue, setInputValue] = useState3("");
12356
- const [showCopied, setShowCopied] = useState3(false);
12357
- const [linkType, setLinkType] = useState3(LINK_TYPES[1]);
12358
- const [isLinkTypeOpen, setIsLinkTypeOpen] = useState3(false);
12359
- const [isPresetOpen, setIsPresetOpen] = useState3(false);
12514
+ const [isOpen, setIsOpen] = useState4(false);
12515
+ const [inputValue, setInputValue] = useState4("");
12516
+ const [showCopied, setShowCopied] = useState4(false);
12517
+ const [linkType, setLinkType] = useState4(LINK_TYPES[1]);
12518
+ const [isLinkTypeOpen, setIsLinkTypeOpen] = useState4(false);
12519
+ const [isPresetOpen, setIsPresetOpen] = useState4(false);
12360
12520
  console.log("userData", userData);
12361
- const availablePresets = useMemo5(() => {
12521
+ const availablePresets = useMemo6(() => {
12362
12522
  const presetDefs = LINK_PRESETS[linkType.name] ?? [];
12363
12523
  if (!userData) return [];
12364
12524
  const all = presetDefs.filter((p) => userData[p.key]).map((p) => ({ ...p, value: String(userData[p.key]) }));
@@ -12366,11 +12526,11 @@ var HrefMenu = () => {
12366
12526
  const query = inputValue.toLowerCase();
12367
12527
  return all.filter((p) => p.value.toLowerCase().includes(query));
12368
12528
  }, [linkType.name, userData, inputValue]);
12369
- const handlePresetSelect = useCallback4((value) => {
12529
+ const handlePresetSelect = useCallback5((value) => {
12370
12530
  setInputValue(value);
12371
12531
  setIsPresetOpen(false);
12372
12532
  }, []);
12373
- useEffect7(() => {
12533
+ useEffect8(() => {
12374
12534
  if (isOpen) {
12375
12535
  setLinkType(detectLinkType(href));
12376
12536
  setInputValue(stripPrefix(href));
@@ -12421,35 +12581,35 @@ var HrefMenu = () => {
12421
12581
  setHref(buildHref(inputValue));
12422
12582
  setIsOpen(false);
12423
12583
  };
12424
- return /* @__PURE__ */ jsxs12(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
12425
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
12426
- /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(DropdownMenuTrigger, { asChild: true, children: hasHref ? /* @__PURE__ */ jsx25(
12584
+ return /* @__PURE__ */ jsxs13(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
12585
+ /* @__PURE__ */ jsxs13(Tooltip, { children: [
12586
+ /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(DropdownMenuTrigger, { asChild: true, children: hasHref ? /* @__PURE__ */ jsx26(
12427
12587
  Button,
12428
12588
  {
12429
12589
  variant: "ghost",
12430
12590
  size: "icon",
12431
12591
  className: floatButtonVariants,
12432
- children: /* @__PURE__ */ jsx25(PencilIcon2, { className: "size-4" })
12592
+ children: /* @__PURE__ */ jsx26(PencilIcon2, { className: "size-4" })
12433
12593
  }
12434
- ) : /* @__PURE__ */ jsxs12(
12594
+ ) : /* @__PURE__ */ jsxs13(
12435
12595
  Button,
12436
12596
  {
12437
12597
  variant: "ghost",
12438
12598
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none h-[34px]",
12439
12599
  children: [
12440
- /* @__PURE__ */ jsx25(LinkIcon3, { className: "size-4" }),
12441
- /* @__PURE__ */ jsx25("p", { children: "Add link" })
12600
+ /* @__PURE__ */ jsx26(LinkIcon3, { className: "size-4" }),
12601
+ /* @__PURE__ */ jsx26("p", { children: "Add link" })
12442
12602
  ]
12443
12603
  }
12444
12604
  ) }) }),
12445
- /* @__PURE__ */ jsx25(TooltipContent, { side: "bottom", children: hasHref ? `Edit link` : "Add link" })
12605
+ /* @__PURE__ */ jsx26(TooltipContent, { side: "bottom", children: hasHref ? `Edit link` : "Add link" })
12446
12606
  ] }),
12447
- /* @__PURE__ */ jsxs12(DropdownMenuContent, { side: "bottom", className: "w-[250px] p-3 shadow-lg z-50001", children: [
12448
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-2", children: [
12449
- /* @__PURE__ */ jsx25(Label, { children: "Enter a link" }),
12450
- /* @__PURE__ */ jsxs12(Popover, { open: isPresetOpen && availablePresets.length > 0, onOpenChange: setIsPresetOpen, children: [
12451
- /* @__PURE__ */ jsx25(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12("div", { className: "relative", children: [
12452
- /* @__PURE__ */ jsx25(
12607
+ /* @__PURE__ */ jsxs13(DropdownMenuContent, { side: "bottom", className: "w-[250px] p-3 shadow-lg z-50001", children: [
12608
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-2", children: [
12609
+ /* @__PURE__ */ jsx26(Label, { children: "Enter a link" }),
12610
+ /* @__PURE__ */ jsxs13(Popover, { open: isPresetOpen && availablePresets.length > 0, onOpenChange: setIsPresetOpen, children: [
12611
+ /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs13("div", { className: "relative", children: [
12612
+ /* @__PURE__ */ jsx26(
12453
12613
  Input,
12454
12614
  {
12455
12615
  type: linkType.inputType,
@@ -12463,19 +12623,19 @@ var HrefMenu = () => {
12463
12623
  autoFocus: true
12464
12624
  }
12465
12625
  ),
12466
- /* @__PURE__ */ jsxs12(Popover, { open: isLinkTypeOpen, onOpenChange: setIsLinkTypeOpen, children: [
12467
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
12468
- /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(Button, { size: "icon", variant: "ghost", className: "absolute shadow-none rounded-[12px] left-1.5 top-1/2 -translate-y-1/2 h-[34px] w-[34px] cursor-pointer", children: /* @__PURE__ */ jsx25(linkType.icon, {}) }) }) }),
12469
- /* @__PURE__ */ jsx25(TooltipContent, { side: "top", className: "z-50001", children: "Link Type" })
12626
+ /* @__PURE__ */ jsxs13(Popover, { open: isLinkTypeOpen, onOpenChange: setIsLinkTypeOpen, children: [
12627
+ /* @__PURE__ */ jsxs13(Tooltip, { children: [
12628
+ /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(Button, { size: "icon", variant: "ghost", className: "absolute shadow-none rounded-[12px] left-1.5 top-1/2 -translate-y-1/2 h-[34px] w-[34px] cursor-pointer", children: /* @__PURE__ */ jsx26(linkType.icon, {}) }) }) }),
12629
+ /* @__PURE__ */ jsx26(TooltipContent, { side: "top", className: "z-50001", children: "Link Type" })
12470
12630
  ] }),
12471
- /* @__PURE__ */ jsx25(
12631
+ /* @__PURE__ */ jsx26(
12472
12632
  PopoverContent,
12473
12633
  {
12474
12634
  side: "bottom",
12475
12635
  align: "start",
12476
12636
  className: "w-[160px] p-1 z-50001",
12477
12637
  onPointerDownOutside: (e) => e.preventDefault(),
12478
- children: LINK_TYPES.map((type) => /* @__PURE__ */ jsxs12(
12638
+ children: LINK_TYPES.map((type) => /* @__PURE__ */ jsxs13(
12479
12639
  Button,
12480
12640
  {
12481
12641
  variant: "ghost",
@@ -12486,11 +12646,11 @@ var HrefMenu = () => {
12486
12646
  setIsLinkTypeOpen(false);
12487
12647
  },
12488
12648
  children: [
12489
- /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-2", children: [
12490
- /* @__PURE__ */ jsx25(type.icon, { className: "size-4" }),
12649
+ /* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-2", children: [
12650
+ /* @__PURE__ */ jsx26(type.icon, { className: "size-4" }),
12491
12651
  type.name
12492
12652
  ] }),
12493
- linkType.name === type.name && /* @__PURE__ */ jsx25(CheckIcon3, { className: "size-4" })
12653
+ linkType.name === type.name && /* @__PURE__ */ jsx26(CheckIcon3, { className: "size-4" })
12494
12654
  ]
12495
12655
  },
12496
12656
  type.name
@@ -12499,14 +12659,14 @@ var HrefMenu = () => {
12499
12659
  )
12500
12660
  ] })
12501
12661
  ] }) }),
12502
- /* @__PURE__ */ jsx25(
12662
+ /* @__PURE__ */ jsx26(
12503
12663
  PopoverContent,
12504
12664
  {
12505
12665
  side: "bottom",
12506
12666
  align: "start",
12507
12667
  className: "w-[var(--radix-popover-trigger-width)] p-0 overflow-hidden z-50001",
12508
12668
  onOpenAutoFocus: (e) => e.preventDefault(),
12509
- children: /* @__PURE__ */ jsx25("div", { className: "flex flex-col max-h-[200px] overflow-y-auto", children: availablePresets.map((preset) => /* @__PURE__ */ jsxs12(
12669
+ children: /* @__PURE__ */ jsx26("div", { className: "flex flex-col max-h-[200px] overflow-y-auto", children: availablePresets.map((preset) => /* @__PURE__ */ jsxs13(
12510
12670
  "button",
12511
12671
  {
12512
12672
  className: `flex items-center justify-between px-3 py-2 text-sm hover:bg-accent cursor-pointer ${inputValue === preset.value ? "bg-accent font-medium" : ""}`,
@@ -12515,11 +12675,11 @@ var HrefMenu = () => {
12515
12675
  handlePresetSelect(preset.value);
12516
12676
  },
12517
12677
  children: [
12518
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-start gap-0.5", children: [
12519
- /* @__PURE__ */ jsx25("span", { className: "text-xs text-muted-foreground", children: preset.label }),
12520
- /* @__PURE__ */ jsx25("span", { className: "text-sm", children: preset.value })
12678
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-start gap-0.5", children: [
12679
+ /* @__PURE__ */ jsx26("span", { className: "text-xs text-muted-foreground", children: preset.label }),
12680
+ /* @__PURE__ */ jsx26("span", { className: "text-sm", children: preset.value })
12521
12681
  ] }),
12522
- inputValue === preset.value && /* @__PURE__ */ jsx25(CheckIcon3, { className: "w-4 h-4 shrink-0" })
12682
+ inputValue === preset.value && /* @__PURE__ */ jsx26(CheckIcon3, { className: "w-4 h-4 shrink-0" })
12523
12683
  ]
12524
12684
  },
12525
12685
  preset.key
@@ -12528,11 +12688,11 @@ var HrefMenu = () => {
12528
12688
  )
12529
12689
  ] })
12530
12690
  ] }),
12531
- /* @__PURE__ */ jsx25(Separator, { className: "my-2" }),
12532
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-row justify-between items-center", children: [
12533
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-row", children: [
12534
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
12535
- /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
12691
+ /* @__PURE__ */ jsx26(Separator, { className: "my-2" }),
12692
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-row justify-between items-center", children: [
12693
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-row", children: [
12694
+ /* @__PURE__ */ jsxs13(Tooltip, { children: [
12695
+ /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(
12536
12696
  Button,
12537
12697
  {
12538
12698
  variant: "ghost",
@@ -12540,13 +12700,13 @@ var HrefMenu = () => {
12540
12700
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
12541
12701
  onClick: handleCopy,
12542
12702
  disabled: !hasHref,
12543
- children: showCopied ? /* @__PURE__ */ jsx25(CheckIcon3, { className: "text-green-600" }) : /* @__PURE__ */ jsx25(CopyIcon3, {})
12703
+ children: showCopied ? /* @__PURE__ */ jsx26(CheckIcon3, { className: "text-green-600" }) : /* @__PURE__ */ jsx26(CopyIcon3, {})
12544
12704
  }
12545
12705
  ) }),
12546
- /* @__PURE__ */ jsx25(TooltipContent, { side: "bottom", className: "z-50001", children: showCopied ? "Copied!" : "Copy link" })
12706
+ /* @__PURE__ */ jsx26(TooltipContent, { side: "bottom", className: "z-50001", children: showCopied ? "Copied!" : "Copy link" })
12547
12707
  ] }),
12548
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
12549
- /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
12708
+ /* @__PURE__ */ jsxs13(Tooltip, { children: [
12709
+ /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(
12550
12710
  Button,
12551
12711
  {
12552
12712
  variant: "ghost",
@@ -12554,13 +12714,13 @@ var HrefMenu = () => {
12554
12714
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
12555
12715
  onClick: handleClear,
12556
12716
  disabled: !href,
12557
- children: /* @__PURE__ */ jsx25(TrashIcon3, {})
12717
+ children: /* @__PURE__ */ jsx26(TrashIcon3, {})
12558
12718
  }
12559
12719
  ) }),
12560
- /* @__PURE__ */ jsx25(TooltipContent, { side: "bottom", className: "z-50001", children: "Remove link" })
12720
+ /* @__PURE__ */ jsx26(TooltipContent, { side: "bottom", className: "z-50001", children: "Remove link" })
12561
12721
  ] })
12562
12722
  ] }),
12563
- /* @__PURE__ */ jsx25("div", { children: /* @__PURE__ */ jsx25(
12723
+ /* @__PURE__ */ jsx26("div", { children: /* @__PURE__ */ jsx26(
12564
12724
  Button,
12565
12725
  {
12566
12726
  variant: "default",
@@ -12575,14 +12735,14 @@ var HrefMenu = () => {
12575
12735
  };
12576
12736
 
12577
12737
  // src/core/editor/components/element-gear/button/float.tsx
12578
- import { Fragment as Fragment6, jsx as jsx26, jsxs as jsxs13 } from "react/jsx-runtime";
12738
+ import { Fragment as Fragment6, jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
12579
12739
  var ButtonFloat = () => {
12580
12740
  const { href, hasHref } = useHref();
12581
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
12582
- hasHref && /* @__PURE__ */ jsx26(FloatLinkPreview, { href }),
12583
- /* @__PURE__ */ jsx26(HrefMenu, {}),
12584
- /* @__PURE__ */ jsx26(DuplicateButton, {}),
12585
- /* @__PURE__ */ jsx26(DeleteButton, {})
12741
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
12742
+ hasHref && /* @__PURE__ */ jsx27(FloatLinkPreview, { href }),
12743
+ /* @__PURE__ */ jsx27(HrefMenu, {}),
12744
+ /* @__PURE__ */ jsx27(DuplicateButton, {}),
12745
+ /* @__PURE__ */ jsx27(DeleteButton, {})
12586
12746
  ] });
12587
12747
  };
12588
12748
 
@@ -12590,11 +12750,11 @@ var ButtonFloat = () => {
12590
12750
  import { ChevronsLeftRightIcon, ChevronsRightLeftIcon, MoreHorizontalIcon } from "lucide-react";
12591
12751
 
12592
12752
  // src/core/editor/hooks/use-full-width-toggle.ts
12593
- import { useCallback as useCallback5, useMemo as useMemo6 } from "react";
12753
+ import { useCallback as useCallback6, useMemo as useMemo7 } from "react";
12594
12754
  import { get as lodashGet3 } from "lodash";
12595
12755
  function useFullWidthToggle() {
12596
12756
  const { focusIdx, template, updateElement } = useEditorStore();
12597
- const { element, isFullWidth } = useMemo6(() => {
12757
+ const { element, isFullWidth } = useMemo7(() => {
12598
12758
  if (!focusIdx || !template) return { element: null, isFullWidth: false };
12599
12759
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.\[(\d+)\]/g, "[$1]") : focusIdx;
12600
12760
  const el = lodashGet3(template, path);
@@ -12603,7 +12763,7 @@ function useFullWidthToggle() {
12603
12763
  isFullWidth: el?.attributes?.["full-width"] === "full-width"
12604
12764
  };
12605
12765
  }, [focusIdx, template]);
12606
- const handleToggleFullWidth = useCallback5(() => {
12766
+ const handleToggleFullWidth = useCallback6(() => {
12607
12767
  if (!focusIdx || !element) return;
12608
12768
  const newAttributes = { ...element.attributes };
12609
12769
  if (isFullWidth) {
@@ -12617,20 +12777,20 @@ function useFullWidthToggle() {
12617
12777
  }
12618
12778
 
12619
12779
  // src/core/editor/components/element-gear/section/float.tsx
12620
- import { Fragment as Fragment7, jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
12780
+ import { Fragment as Fragment7, jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
12621
12781
  var SectionFloat = () => {
12622
12782
  const { isFullWidth, handleToggleFullWidth } = useFullWidthToggle();
12623
- return /* @__PURE__ */ jsxs14(Fragment7, { children: [
12624
- /* @__PURE__ */ jsx27(DuplicateButton, {}),
12625
- /* @__PURE__ */ jsx27(DeleteButton, {}),
12626
- /* @__PURE__ */ jsxs14(DropdownMenu, { children: [
12627
- /* @__PURE__ */ jsxs14(Tooltip, { children: [
12628
- /* @__PURE__ */ jsx27(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx27(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx27(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx27(MoreHorizontalIcon, { className: "w-4 h-4" }) }) }) }),
12629
- /* @__PURE__ */ jsx27(TooltipContent, { side: "bottom", children: "More" })
12783
+ return /* @__PURE__ */ jsxs15(Fragment7, { children: [
12784
+ /* @__PURE__ */ jsx28(DuplicateButton, {}),
12785
+ /* @__PURE__ */ jsx28(DeleteButton, {}),
12786
+ /* @__PURE__ */ jsxs15(DropdownMenu, { children: [
12787
+ /* @__PURE__ */ jsxs15(Tooltip, { children: [
12788
+ /* @__PURE__ */ jsx28(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx28(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx28(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx28(MoreHorizontalIcon, { className: "w-4 h-4" }) }) }) }),
12789
+ /* @__PURE__ */ jsx28(TooltipContent, { side: "bottom", children: "More" })
12630
12790
  ] }),
12631
- /* @__PURE__ */ jsx27(DropdownMenuContent, { side: "bottom", className: "w-[200px]", children: /* @__PURE__ */ jsxs14(DropdownMenuItem, { onClick: handleToggleFullWidth, children: [
12632
- isFullWidth ? /* @__PURE__ */ jsx27(ChevronsRightLeftIcon, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx27(ChevronsLeftRightIcon, { className: "w-4 h-4" }),
12633
- /* @__PURE__ */ jsx27("p", { children: isFullWidth ? "Reset to original width" : "Expand to full width" })
12791
+ /* @__PURE__ */ jsx28(DropdownMenuContent, { side: "bottom", className: "w-[200px]", children: /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: handleToggleFullWidth, children: [
12792
+ isFullWidth ? /* @__PURE__ */ jsx28(ChevronsRightLeftIcon, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx28(ChevronsLeftRightIcon, { className: "w-4 h-4" }),
12793
+ /* @__PURE__ */ jsx28("p", { children: isFullWidth ? "Reset to original width" : "Expand to full width" })
12634
12794
  ] }) })
12635
12795
  ] })
12636
12796
  ] });
@@ -12640,11 +12800,11 @@ var SectionFloat = () => {
12640
12800
  import { CheckIcon as CheckIcon4, ChevronsLeftRightIcon as ChevronsLeftRightIcon2, ChevronsRightLeftIcon as ChevronsRightLeftIcon2, Layers2Icon, MoreHorizontalIcon as MoreHorizontalIcon2 } from "lucide-react";
12641
12801
 
12642
12802
  // src/core/editor/hooks/use-no-wrap.ts
12643
- import { useCallback as useCallback6, useMemo as useMemo7 } from "react";
12803
+ import { useCallback as useCallback7, useMemo as useMemo8 } from "react";
12644
12804
  import { get as lodashGet4 } from "lodash";
12645
12805
  function useNoWrap() {
12646
12806
  const { focusIdx, template, updateElement } = useEditorStore();
12647
- const { element, noWrap } = useMemo7(() => {
12807
+ const { element, noWrap } = useMemo8(() => {
12648
12808
  if (!focusIdx || !template) return { element: null, noWrap: false };
12649
12809
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.\[(\d+)\]/g, "[$1]") : focusIdx;
12650
12810
  const el = lodashGet4(template, path);
@@ -12653,7 +12813,7 @@ function useNoWrap() {
12653
12813
  noWrap: el?.data?.value?.noWrap === true
12654
12814
  };
12655
12815
  }, [focusIdx, template]);
12656
- const handleToggleNoWrap = useCallback6(() => {
12816
+ const handleToggleNoWrap = useCallback7(() => {
12657
12817
  if (!focusIdx || !element) return;
12658
12818
  updateElement(focusIdx, {
12659
12819
  data: {
@@ -12668,30 +12828,30 @@ function useNoWrap() {
12668
12828
  }
12669
12829
 
12670
12830
  // src/core/editor/components/element-gear/section-column/float.tsx
12671
- import { Fragment as Fragment8, jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
12831
+ import { Fragment as Fragment8, jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
12672
12832
  var SectionColumnFloat = () => {
12673
12833
  const { isFullWidth, handleToggleFullWidth } = useFullWidthToggle();
12674
12834
  const { noWrap, handleToggleNoWrap } = useNoWrap();
12675
- return /* @__PURE__ */ jsxs15(Fragment8, { children: [
12676
- /* @__PURE__ */ jsx28(DuplicateButton, {}),
12677
- /* @__PURE__ */ jsx28(DeleteButton, {}),
12678
- /* @__PURE__ */ jsxs15(DropdownMenu, { children: [
12679
- /* @__PURE__ */ jsxs15(Tooltip, { children: [
12680
- /* @__PURE__ */ jsx28(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx28(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx28(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx28(MoreHorizontalIcon2, { className: "w-4 h-4" }) }) }) }),
12681
- /* @__PURE__ */ jsx28(TooltipContent, { side: "bottom", children: "More" })
12835
+ return /* @__PURE__ */ jsxs16(Fragment8, { children: [
12836
+ /* @__PURE__ */ jsx29(DuplicateButton, {}),
12837
+ /* @__PURE__ */ jsx29(DeleteButton, {}),
12838
+ /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
12839
+ /* @__PURE__ */ jsxs16(Tooltip, { children: [
12840
+ /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx29(MoreHorizontalIcon2, { className: "w-4 h-4" }) }) }) }),
12841
+ /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", children: "More" })
12682
12842
  ] }),
12683
- /* @__PURE__ */ jsxs15(DropdownMenuContent, { side: "bottom", className: "w-[250px]", children: [
12684
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: handleToggleNoWrap, children: [
12685
- /* @__PURE__ */ jsx28(Layers2Icon, { className: "w-4 h-4" }),
12686
- /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 w-full", children: [
12687
- /* @__PURE__ */ jsx28("p", { className: "w-full", children: noWrap ? "Columns collapse" : "Columns collapse" }),
12688
- !noWrap && /* @__PURE__ */ jsx28(CheckIcon4, { className: "w-4 h-4" })
12843
+ /* @__PURE__ */ jsxs16(DropdownMenuContent, { side: "bottom", className: "w-[250px]", children: [
12844
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: handleToggleNoWrap, children: [
12845
+ /* @__PURE__ */ jsx29(Layers2Icon, { className: "w-4 h-4" }),
12846
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 w-full", children: [
12847
+ /* @__PURE__ */ jsx29("p", { className: "w-full", children: noWrap ? "Columns collapse" : "Columns collapse" }),
12848
+ !noWrap && /* @__PURE__ */ jsx29(CheckIcon4, { className: "w-4 h-4" })
12689
12849
  ] })
12690
12850
  ] }),
12691
- /* @__PURE__ */ jsx28(DropdownMenuSeparator, {}),
12692
- /* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: handleToggleFullWidth, children: [
12693
- isFullWidth ? /* @__PURE__ */ jsx28(ChevronsRightLeftIcon2, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx28(ChevronsLeftRightIcon2, { className: "w-4 h-4" }),
12694
- /* @__PURE__ */ jsx28("p", { children: isFullWidth ? "Reset to original width" : "Expand to full width" })
12851
+ /* @__PURE__ */ jsx29(DropdownMenuSeparator, {}),
12852
+ /* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: handleToggleFullWidth, children: [
12853
+ isFullWidth ? /* @__PURE__ */ jsx29(ChevronsRightLeftIcon2, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx29(ChevronsLeftRightIcon2, { className: "w-4 h-4" }),
12854
+ /* @__PURE__ */ jsx29("p", { children: isFullWidth ? "Reset to original width" : "Expand to full width" })
12695
12855
  ] })
12696
12856
  ] })
12697
12857
  ] })
@@ -12699,11 +12859,11 @@ var SectionColumnFloat = () => {
12699
12859
  };
12700
12860
 
12701
12861
  // src/core/editor/components/element-gear/spacer/float.tsx
12702
- import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
12862
+ import { Fragment as Fragment9, jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
12703
12863
  var SpacerFloat = () => {
12704
- return /* @__PURE__ */ jsxs16(Fragment9, { children: [
12705
- /* @__PURE__ */ jsx29(DuplicateButton, {}),
12706
- /* @__PURE__ */ jsx29(DeleteButton, {})
12864
+ return /* @__PURE__ */ jsxs17(Fragment9, { children: [
12865
+ /* @__PURE__ */ jsx30(DuplicateButton, {}),
12866
+ /* @__PURE__ */ jsx30(DeleteButton, {})
12707
12867
  ] });
12708
12868
  };
12709
12869
 
@@ -12711,16 +12871,16 @@ var SpacerFloat = () => {
12711
12871
  import { MoreHorizontalIcon as MoreHorizontalIcon3, PlusCircleIcon } from "lucide-react";
12712
12872
 
12713
12873
  // src/core/editor/components/email-template-v2/context/sidebar-context.tsx
12714
- import { createContext, useContext, useState as useState4 } from "react";
12715
- import { jsx as jsx30 } from "react/jsx-runtime";
12874
+ import { createContext, useContext, useState as useState5 } from "react";
12875
+ import { jsx as jsx31 } from "react/jsx-runtime";
12716
12876
  var SidebarContext = createContext(null);
12717
12877
  var PICKER_VIEWS = ["color", "images", "add-social"];
12718
12878
  function SidebarProvider({ children }) {
12719
- const [activeView, setActiveViewState] = useState4("elements");
12720
- const [lastView, setLastView] = useState4("elements");
12721
- const [colorType, setColorType] = useState4("Color");
12722
- const [colorTarget, setColorTarget] = useState4(null);
12723
- const [imageTarget, setImageTarget] = useState4(null);
12879
+ const [activeView, setActiveViewState] = useState5("elements");
12880
+ const [lastView, setLastView] = useState5("elements");
12881
+ const [colorType, setColorType] = useState5("Color");
12882
+ const [colorTarget, setColorTarget] = useState5(null);
12883
+ const [imageTarget, setImageTarget] = useState5(null);
12724
12884
  const setActiveView = (view) => {
12725
12885
  if (view !== activeView) {
12726
12886
  if (!PICKER_VIEWS.includes(activeView)) {
@@ -12729,7 +12889,7 @@ function SidebarProvider({ children }) {
12729
12889
  }
12730
12890
  setActiveViewState(view);
12731
12891
  };
12732
- return /* @__PURE__ */ jsx30(SidebarContext.Provider, { value: { activeView, setActiveView, lastView, colorType, setColorType, colorTarget, setColorTarget, imageTarget, setImageTarget }, children });
12892
+ return /* @__PURE__ */ jsx31(SidebarContext.Provider, { value: { activeView, setActiveView, lastView, colorType, setColorType, colorTarget, setColorTarget, imageTarget, setImageTarget }, children });
12733
12893
  }
12734
12894
  function useSidebarContext() {
12735
12895
  const context = useContext(SidebarContext);
@@ -12740,33 +12900,33 @@ function useSidebarContext() {
12740
12900
  }
12741
12901
 
12742
12902
  // src/core/editor/components/element-gear/social/float.tsx
12743
- import { Fragment as Fragment10, jsx as jsx31, jsxs as jsxs17 } from "react/jsx-runtime";
12903
+ import { Fragment as Fragment10, jsx as jsx32, jsxs as jsxs18 } from "react/jsx-runtime";
12744
12904
  var SocialFloat = () => {
12745
12905
  const { setActiveView } = useSidebarContext();
12746
- return /* @__PURE__ */ jsxs17(Fragment10, { children: [
12747
- /* @__PURE__ */ jsxs17(Tooltip, { children: [
12748
- /* @__PURE__ */ jsx31(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx31(Button, { variant: "ghost", className: floatButtonVariants, onClick: () => setActiveView("add-social"), children: /* @__PURE__ */ jsx31(PlusCircleIcon, {}) }) }),
12749
- /* @__PURE__ */ jsx31(TooltipContent, { side: "bottom", children: "Add Social" })
12906
+ return /* @__PURE__ */ jsxs18(Fragment10, { children: [
12907
+ /* @__PURE__ */ jsxs18(Tooltip, { children: [
12908
+ /* @__PURE__ */ jsx32(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(Button, { variant: "ghost", className: floatButtonVariants, onClick: () => setActiveView("add-social"), children: /* @__PURE__ */ jsx32(PlusCircleIcon, {}) }) }),
12909
+ /* @__PURE__ */ jsx32(TooltipContent, { side: "bottom", children: "Add Social" })
12750
12910
  ] }),
12751
- /* @__PURE__ */ jsx31(DuplicateButton, {}),
12752
- /* @__PURE__ */ jsx31(DeleteButton, {}),
12753
- /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
12754
- /* @__PURE__ */ jsxs17(Tooltip, { children: [
12755
- /* @__PURE__ */ jsx31(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx31(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx31(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx31(MoreHorizontalIcon3, { className: "w-4 h-4" }) }) }) }),
12756
- /* @__PURE__ */ jsx31(TooltipContent, { side: "bottom", children: "More" })
12911
+ /* @__PURE__ */ jsx32(DuplicateButton, {}),
12912
+ /* @__PURE__ */ jsx32(DeleteButton, {}),
12913
+ /* @__PURE__ */ jsxs18(DropdownMenu, { children: [
12914
+ /* @__PURE__ */ jsxs18(Tooltip, { children: [
12915
+ /* @__PURE__ */ jsx32(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx32(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx32(MoreHorizontalIcon3, { className: "w-4 h-4" }) }) }) }),
12916
+ /* @__PURE__ */ jsx32(TooltipContent, { side: "bottom", children: "More" })
12757
12917
  ] }),
12758
- /* @__PURE__ */ jsx31(DropdownMenuContent, { side: "bottom", className: "w-[200px]", children: /* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => setActiveView("add-social"), children: [
12759
- /* @__PURE__ */ jsx31(PlusCircleIcon, { className: "w-4 h-4" }),
12760
- /* @__PURE__ */ jsx31("p", { children: "Add Social" })
12918
+ /* @__PURE__ */ jsx32(DropdownMenuContent, { side: "bottom", className: "w-[200px]", children: /* @__PURE__ */ jsxs18(DropdownMenuItem, { onClick: () => setActiveView("add-social"), children: [
12919
+ /* @__PURE__ */ jsx32(PlusCircleIcon, { className: "w-4 h-4" }),
12920
+ /* @__PURE__ */ jsx32("p", { children: "Add Social" })
12761
12921
  ] }) })
12762
12922
  ] })
12763
12923
  ] });
12764
12924
  };
12765
12925
 
12766
12926
  // src/components/ui/textarea.tsx
12767
- import { jsx as jsx32 } from "react/jsx-runtime";
12927
+ import { jsx as jsx33 } from "react/jsx-runtime";
12768
12928
  function Textarea({ className, ...props }) {
12769
- return /* @__PURE__ */ jsx32(
12929
+ return /* @__PURE__ */ jsx33(
12770
12930
  "textarea",
12771
12931
  {
12772
12932
  "data-slot": "textarea",
@@ -12781,38 +12941,38 @@ function Textarea({ className, ...props }) {
12781
12941
 
12782
12942
  // src/core/editor/components/element-gear/social-item/float.tsx
12783
12943
  import { Accessibility, MoreHorizontalIcon as MoreHorizontalIcon4, TrashIcon as TrashIcon4 } from "lucide-react";
12784
- import { useState as useState6, useEffect as useEffect9 } from "react";
12944
+ import { useState as useState7, useEffect as useEffect10 } from "react";
12785
12945
 
12786
12946
  // src/core/editor/components/social-item-menu.tsx
12787
- import { useState as useState5, useEffect as useEffect8, useMemo as useMemo8, useCallback as useCallback7 } from "react";
12947
+ import { useState as useState6, useEffect as useEffect9, useMemo as useMemo9, useCallback as useCallback8 } from "react";
12788
12948
  import { PencilIcon as PencilIcon3, CheckIcon as CheckIcon5, CopyIcon as CopyIcon4 } from "lucide-react";
12789
12949
  import { get as lodashGet5 } from "lodash";
12790
- import { jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
12950
+ import { jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
12791
12951
  var SocialItemMenu = ({ hasHref }) => {
12792
- const [isOpen, setIsOpen] = useState5(false);
12793
- const [showCopied, setShowCopied] = useState5(false);
12794
- const [hrefInputValue, setHrefInputValue] = useState5("");
12795
- const [contentInputValue, setContentInputValue] = useState5("");
12952
+ const [isOpen, setIsOpen] = useState6(false);
12953
+ const [showCopied, setShowCopied] = useState6(false);
12954
+ const [hrefInputValue, setHrefInputValue] = useState6("");
12955
+ const [contentInputValue, setContentInputValue] = useState6("");
12796
12956
  const { href, setHref, copyHref } = useHref();
12797
12957
  const { focusIdx, template, updateElement } = useEditorStore();
12798
- const element = useMemo8(() => {
12958
+ const element = useMemo9(() => {
12799
12959
  if (!focusIdx || !template) return null;
12800
12960
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.?\[(\d+)\]/g, "[$1]") : focusIdx;
12801
12961
  return lodashGet5(template, path);
12802
12962
  }, [focusIdx, template]);
12803
12963
  const content = element?.data?.value?.content || "";
12804
- useEffect8(() => {
12964
+ useEffect9(() => {
12805
12965
  if (isOpen) {
12806
12966
  setHrefInputValue(href);
12807
12967
  setContentInputValue(content);
12808
12968
  }
12809
12969
  }, [isOpen, href, content]);
12810
- const handleCopy = useCallback7(async () => {
12970
+ const handleCopy = useCallback8(async () => {
12811
12971
  await copyHref();
12812
12972
  setShowCopied(true);
12813
12973
  setTimeout(() => setShowCopied(false), 2e3);
12814
12974
  }, [copyHref]);
12815
- const handleDone = useCallback7(() => {
12975
+ const handleDone = useCallback8(() => {
12816
12976
  setHref(normalizeWebsiteUrl(hrefInputValue));
12817
12977
  if (focusIdx && element) {
12818
12978
  updateElement(focusIdx, {
@@ -12826,33 +12986,33 @@ var SocialItemMenu = ({ hasHref }) => {
12826
12986
  }
12827
12987
  setIsOpen(false);
12828
12988
  }, [hrefInputValue, contentInputValue, setHref, focusIdx, element, updateElement]);
12829
- return /* @__PURE__ */ jsxs18(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
12830
- /* @__PURE__ */ jsxs18(Tooltip, { children: [
12831
- /* @__PURE__ */ jsx33(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx33(DropdownMenuTrigger, { asChild: true, children: hasHref ? /* @__PURE__ */ jsx33(
12989
+ return /* @__PURE__ */ jsxs19(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
12990
+ /* @__PURE__ */ jsxs19(Tooltip, { children: [
12991
+ /* @__PURE__ */ jsx34(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(DropdownMenuTrigger, { asChild: true, children: hasHref ? /* @__PURE__ */ jsx34(
12832
12992
  Button,
12833
12993
  {
12834
12994
  variant: "ghost",
12835
12995
  size: "icon",
12836
12996
  className: floatButtonVariants,
12837
- children: /* @__PURE__ */ jsx33(PencilIcon3, { className: "size-4" })
12997
+ children: /* @__PURE__ */ jsx34(PencilIcon3, { className: "size-4" })
12838
12998
  }
12839
- ) : /* @__PURE__ */ jsxs18(
12999
+ ) : /* @__PURE__ */ jsxs19(
12840
13000
  Button,
12841
13001
  {
12842
13002
  variant: "ghost",
12843
13003
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
12844
13004
  children: [
12845
- /* @__PURE__ */ jsx33(PencilIcon3, { className: "size-4" }),
12846
- /* @__PURE__ */ jsx33("p", { children: "Edit" })
13005
+ /* @__PURE__ */ jsx34(PencilIcon3, { className: "size-4" }),
13006
+ /* @__PURE__ */ jsx34("p", { children: "Edit" })
12847
13007
  ]
12848
13008
  }
12849
13009
  ) }) }),
12850
- /* @__PURE__ */ jsx33(TooltipContent, { side: "bottom", children: "Edit" })
13010
+ /* @__PURE__ */ jsx34(TooltipContent, { side: "bottom", children: "Edit" })
12851
13011
  ] }),
12852
- /* @__PURE__ */ jsxs18(DropdownMenuContent, { side: "bottom", className: "w-[250px] p-3 shadow-lg z-50001", children: [
12853
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-2 mb-2", children: [
12854
- /* @__PURE__ */ jsx33(Label, { className: "text-xs font-medium", children: "Enter a link" }),
12855
- /* @__PURE__ */ jsx33(
13012
+ /* @__PURE__ */ jsxs19(DropdownMenuContent, { side: "bottom", className: "w-[250px] p-3 shadow-lg z-50001", children: [
13013
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2 mb-2", children: [
13014
+ /* @__PURE__ */ jsx34(Label, { className: "text-xs font-medium", children: "Enter a link" }),
13015
+ /* @__PURE__ */ jsx34(
12856
13016
  Input,
12857
13017
  {
12858
13018
  type: "text",
@@ -12864,9 +13024,9 @@ var SocialItemMenu = ({ hasHref }) => {
12864
13024
  }
12865
13025
  )
12866
13026
  ] }),
12867
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-2", children: [
12868
- /* @__PURE__ */ jsx33(Label, { className: "text-xs font-medium", children: "Content" }),
12869
- /* @__PURE__ */ jsx33(
13027
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2", children: [
13028
+ /* @__PURE__ */ jsx34(Label, { className: "text-xs font-medium", children: "Content" }),
13029
+ /* @__PURE__ */ jsx34(
12870
13030
  Input,
12871
13031
  {
12872
13032
  type: "text",
@@ -12877,10 +13037,10 @@ var SocialItemMenu = ({ hasHref }) => {
12877
13037
  }
12878
13038
  )
12879
13039
  ] }),
12880
- /* @__PURE__ */ jsx33(Separator, { className: "my-2" }),
12881
- /* @__PURE__ */ jsxs18("div", { className: "flex flex-row justify-between items-center", children: [
12882
- /* @__PURE__ */ jsx33("div", { className: "flex flex-row", children: /* @__PURE__ */ jsxs18(Tooltip, { children: [
12883
- /* @__PURE__ */ jsx33(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx33(
13040
+ /* @__PURE__ */ jsx34(Separator, { className: "my-2" }),
13041
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-row justify-between items-center", children: [
13042
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-row", children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
13043
+ /* @__PURE__ */ jsx34(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(
12884
13044
  Button,
12885
13045
  {
12886
13046
  variant: "ghost",
@@ -12888,12 +13048,12 @@ var SocialItemMenu = ({ hasHref }) => {
12888
13048
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
12889
13049
  onClick: handleCopy,
12890
13050
  disabled: !hasHref,
12891
- children: showCopied ? /* @__PURE__ */ jsx33(CheckIcon5, { className: "text-green-600" }) : /* @__PURE__ */ jsx33(CopyIcon4, {})
13051
+ children: showCopied ? /* @__PURE__ */ jsx34(CheckIcon5, { className: "text-green-600" }) : /* @__PURE__ */ jsx34(CopyIcon4, {})
12892
13052
  }
12893
13053
  ) }),
12894
- /* @__PURE__ */ jsx33(TooltipContent, { side: "bottom", className: "z-50001", children: showCopied ? "Copied!" : "Copy link" })
13054
+ /* @__PURE__ */ jsx34(TooltipContent, { side: "bottom", className: "z-50001", children: showCopied ? "Copied!" : "Copy link" })
12895
13055
  ] }) }),
12896
- /* @__PURE__ */ jsx33("div", { children: /* @__PURE__ */ jsx33(
13056
+ /* @__PURE__ */ jsx34("div", { children: /* @__PURE__ */ jsx34(
12897
13057
  Button,
12898
13058
  {
12899
13059
  variant: "default",
@@ -12908,11 +13068,11 @@ var SocialItemMenu = ({ hasHref }) => {
12908
13068
  };
12909
13069
 
12910
13070
  // src/core/editor/hooks/use-alt.ts
12911
- import { useMemo as useMemo9, useCallback as useCallback8 } from "react";
13071
+ import { useMemo as useMemo10, useCallback as useCallback9 } from "react";
12912
13072
  import { get as lodashGet6 } from "lodash";
12913
13073
  var useAlt = () => {
12914
13074
  const { focusIdx, updateElement, template } = useEditorStore();
12915
- const { element, alt } = useMemo9(() => {
13075
+ const { element, alt } = useMemo10(() => {
12916
13076
  if (!focusIdx || !template) {
12917
13077
  return { element: null, alt: "" };
12918
13078
  }
@@ -12923,13 +13083,13 @@ var useAlt = () => {
12923
13083
  alt: el?.attributes?.alt || ""
12924
13084
  };
12925
13085
  }, [focusIdx, template]);
12926
- const setAlt = useCallback8((text2) => {
13086
+ const setAlt = useCallback9((text2) => {
12927
13087
  if (!focusIdx || !element) return;
12928
13088
  updateElement(focusIdx, {
12929
13089
  attributes: { ...element.attributes, alt: text2 }
12930
13090
  });
12931
13091
  }, [focusIdx, element, updateElement]);
12932
- const clearAlt = useCallback8(() => {
13092
+ const clearAlt = useCallback9(() => {
12933
13093
  if (!focusIdx || !element) return;
12934
13094
  updateElement(focusIdx, {
12935
13095
  attributes: { ...element.attributes, alt: "" }
@@ -12945,17 +13105,17 @@ var useAlt = () => {
12945
13105
  };
12946
13106
 
12947
13107
  // src/core/editor/components/element-gear/social-item/float.tsx
12948
- import { Fragment as Fragment11, jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
13108
+ import { Fragment as Fragment11, jsx as jsx35, jsxs as jsxs20 } from "react/jsx-runtime";
12949
13109
  var SocialItemFloat = () => {
12950
13110
  const { href, hasHref } = useHref();
12951
13111
  const { alt, setAlt } = useAlt();
12952
13112
  const { focusIdx, template, deleteElement } = useEditorStore();
12953
- const [dropdownOpen, setDropdownOpen] = useState6(false);
12954
- const [altInputValue, setAltInputValue] = useState6("");
13113
+ const [dropdownOpen, setDropdownOpen] = useState7(false);
13114
+ const [altInputValue, setAltInputValue] = useState7("");
12955
13115
  const parentSocial = focusIdx ? getParentByIdx(template, focusIdx) : null;
12956
13116
  const childrenCount = parentSocial?.children?.length || 0;
12957
13117
  const canDelete = childrenCount > 1;
12958
- useEffect9(() => {
13118
+ useEffect10(() => {
12959
13119
  if (dropdownOpen) {
12960
13120
  setAltInputValue(alt);
12961
13121
  }
@@ -12969,37 +13129,37 @@ var SocialItemFloat = () => {
12969
13129
  deleteElement(focusIdx);
12970
13130
  }
12971
13131
  };
12972
- return /* @__PURE__ */ jsxs19(Fragment11, { children: [
12973
- hasHref && /* @__PURE__ */ jsx34(FloatLinkPreview, { href }),
12974
- /* @__PURE__ */ jsx34(SocialItemMenu, { hasHref }),
12975
- /* @__PURE__ */ jsxs19(Tooltip, { children: [
12976
- /* @__PURE__ */ jsx34(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(
13132
+ return /* @__PURE__ */ jsxs20(Fragment11, { children: [
13133
+ hasHref && /* @__PURE__ */ jsx35(FloatLinkPreview, { href }),
13134
+ /* @__PURE__ */ jsx35(SocialItemMenu, { hasHref }),
13135
+ /* @__PURE__ */ jsxs20(Tooltip, { children: [
13136
+ /* @__PURE__ */ jsx35(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx35(
12977
13137
  Button,
12978
13138
  {
12979
13139
  variant: "ghost",
12980
13140
  className: floatButtonVariants,
12981
13141
  onClick: handleDelete,
12982
13142
  disabled: !canDelete,
12983
- children: /* @__PURE__ */ jsx34(TrashIcon4, { className: "size-4" })
13143
+ children: /* @__PURE__ */ jsx35(TrashIcon4, { className: "size-4" })
12984
13144
  }
12985
13145
  ) }),
12986
- /* @__PURE__ */ jsx34(TooltipContent, { side: "bottom", children: canDelete ? "Delete" : "Cannot delete last item" })
13146
+ /* @__PURE__ */ jsx35(TooltipContent, { side: "bottom", children: canDelete ? "Delete" : "Cannot delete last item" })
12987
13147
  ] }),
12988
- /* @__PURE__ */ jsxs19(DropdownMenu, { open: dropdownOpen, onOpenChange: setDropdownOpen, children: [
12989
- /* @__PURE__ */ jsxs19(Tooltip, { children: [
12990
- /* @__PURE__ */ jsx34(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx34(MoreHorizontalIcon4, { className: "w-4 h-4" }) }) }) }),
12991
- /* @__PURE__ */ jsx34(TooltipContent, { side: "bottom", children: "More" })
13148
+ /* @__PURE__ */ jsxs20(DropdownMenu, { open: dropdownOpen, onOpenChange: setDropdownOpen, children: [
13149
+ /* @__PURE__ */ jsxs20(Tooltip, { children: [
13150
+ /* @__PURE__ */ jsx35(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx35(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx35(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx35(MoreHorizontalIcon4, { className: "w-4 h-4" }) }) }) }),
13151
+ /* @__PURE__ */ jsx35(TooltipContent, { side: "bottom", children: "More" })
12992
13152
  ] }),
12993
- /* @__PURE__ */ jsx34(DropdownMenuContent, { side: "bottom", className: "w-[250px] z-50001", children: /* @__PURE__ */ jsxs19(DropdownMenuSub, { children: [
12994
- /* @__PURE__ */ jsxs19(DropdownMenuSubTrigger, { children: [
12995
- /* @__PURE__ */ jsx34(Accessibility, { className: "w-4 h-4" }),
12996
- /* @__PURE__ */ jsx34("p", { children: "Alternative Text" })
13153
+ /* @__PURE__ */ jsx35(DropdownMenuContent, { side: "bottom", className: "w-[250px] z-50001", children: /* @__PURE__ */ jsxs20(DropdownMenuSub, { children: [
13154
+ /* @__PURE__ */ jsxs20(DropdownMenuSubTrigger, { children: [
13155
+ /* @__PURE__ */ jsx35(Accessibility, { className: "w-4 h-4" }),
13156
+ /* @__PURE__ */ jsx35("p", { children: "Alternative Text" })
12997
13157
  ] }),
12998
- /* @__PURE__ */ jsx34(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs19(DropdownMenuSubContent, { className: "p-3 w-[250px] z-50001", children: [
12999
- /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2 mb-2", children: [
13000
- /* @__PURE__ */ jsx34(Label, { children: "Alternative Text" }),
13001
- /* @__PURE__ */ jsxs19("div", { className: "relative", children: [
13002
- /* @__PURE__ */ jsx34(
13158
+ /* @__PURE__ */ jsx35(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs20(DropdownMenuSubContent, { className: "p-3 w-[250px] z-50001", children: [
13159
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-2 mb-2", children: [
13160
+ /* @__PURE__ */ jsx35(Label, { children: "Alternative Text" }),
13161
+ /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
13162
+ /* @__PURE__ */ jsx35(
13003
13163
  Textarea,
13004
13164
  {
13005
13165
  placeholder: "Icon image alt, for example: 'Facebook icon'",
@@ -13009,14 +13169,14 @@ var SocialItemFloat = () => {
13009
13169
  onChange: (e) => setAltInputValue(e.target.value)
13010
13170
  }
13011
13171
  ),
13012
- /* @__PURE__ */ jsxs19("span", { className: "bg-white rounded-[12px] p-1 shadow-sm absolute bottom-2 right-2 text-xs text-muted-foreground", children: [
13172
+ /* @__PURE__ */ jsxs20("span", { className: "bg-white rounded-[12px] p-1 shadow-sm absolute bottom-2 right-2 text-xs text-muted-foreground", children: [
13013
13173
  altInputValue.length,
13014
13174
  "/250"
13015
13175
  ] })
13016
13176
  ] }),
13017
- /* @__PURE__ */ jsx34("p", { className: "text-xs text-muted-foreground mb-4", children: "Be descriptive and add context to keep your alt text clear for clients who use screen readers." })
13177
+ /* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground mb-4", children: "Be descriptive and add context to keep your alt text clear for clients who use screen readers." })
13018
13178
  ] }),
13019
- /* @__PURE__ */ jsx34(
13179
+ /* @__PURE__ */ jsx35(
13020
13180
  Button,
13021
13181
  {
13022
13182
  variant: "default",
@@ -13032,27 +13192,27 @@ var SocialItemFloat = () => {
13032
13192
  };
13033
13193
 
13034
13194
  // src/core/editor/components/element-gear/divider/float.tsx
13035
- import { Fragment as Fragment12, jsx as jsx35, jsxs as jsxs20 } from "react/jsx-runtime";
13195
+ import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
13036
13196
  var DividerFloat = () => {
13037
- return /* @__PURE__ */ jsxs20(Fragment12, { children: [
13038
- /* @__PURE__ */ jsx35(DuplicateButton, {}),
13039
- /* @__PURE__ */ jsx35(DeleteButton, {})
13197
+ return /* @__PURE__ */ jsxs21(Fragment12, { children: [
13198
+ /* @__PURE__ */ jsx36(DuplicateButton, {}),
13199
+ /* @__PURE__ */ jsx36(DeleteButton, {})
13040
13200
  ] });
13041
13201
  };
13042
13202
 
13043
13203
  // src/core/editor/components/element-gear/image/float.tsx
13044
13204
  import { Accessibility as Accessibility2, CheckIcon as CheckIcon6, MoreHorizontalIcon as MoreHorizontalIcon5, Proportions } from "lucide-react";
13045
13205
  import lodashGet7 from "lodash/get";
13046
- import { useState as useState7, useEffect as useEffect10, useMemo as useMemo10, useCallback as useCallback9 } from "react";
13047
- import { Fragment as Fragment13, jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
13206
+ import { useState as useState8, useEffect as useEffect11, useMemo as useMemo11, useCallback as useCallback10 } from "react";
13207
+ import { Fragment as Fragment13, jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
13048
13208
  var ImageFloat = () => {
13049
13209
  const { href, hasHref } = useHref();
13050
13210
  const { alt, setAlt, hasAlt } = useAlt();
13051
13211
  const { focusIdx, updateElement, template } = useEditorStore();
13052
- const [showMoreView, setShowMoreView] = useState7(null);
13053
- const [dropdownOpen, setDropdownOpen] = useState7(false);
13054
- const [altInputValue, setAltInputValue] = useState7("");
13055
- const { element, isFluidOnMobile } = useMemo10(() => {
13212
+ const [showMoreView, setShowMoreView] = useState8(null);
13213
+ const [dropdownOpen, setDropdownOpen] = useState8(false);
13214
+ const [altInputValue, setAltInputValue] = useState8("");
13215
+ const { element, isFluidOnMobile } = useMemo11(() => {
13056
13216
  if (!focusIdx || !template) return { element: null, isFluidOnMobile: false };
13057
13217
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.\[(\d+)\]/g, "[$1]") : focusIdx;
13058
13218
  const el = lodashGet7(template, path);
@@ -13061,7 +13221,7 @@ var ImageFloat = () => {
13061
13221
  isFluidOnMobile: el?.attributes?.["fluid-on-mobile"] === "true"
13062
13222
  };
13063
13223
  }, [focusIdx, template]);
13064
- const toggleFluidOnMobile = useCallback9(() => {
13224
+ const toggleFluidOnMobile = useCallback10(() => {
13065
13225
  if (!focusIdx || !element) return;
13066
13226
  const newAttributes = { ...element.attributes };
13067
13227
  if (isFluidOnMobile) {
@@ -13071,7 +13231,7 @@ var ImageFloat = () => {
13071
13231
  }
13072
13232
  updateElement(focusIdx, { attributes: newAttributes });
13073
13233
  }, [focusIdx, element, isFluidOnMobile, updateElement]);
13074
- useEffect10(() => {
13234
+ useEffect11(() => {
13075
13235
  if (dropdownOpen) {
13076
13236
  setAltInputValue(alt);
13077
13237
  }
@@ -13080,35 +13240,35 @@ var ImageFloat = () => {
13080
13240
  setAlt(altInputValue);
13081
13241
  setDropdownOpen(false);
13082
13242
  };
13083
- return /* @__PURE__ */ jsxs21(Fragment13, { children: [
13084
- hasHref && /* @__PURE__ */ jsx36(FloatLinkPreview, { href }),
13085
- /* @__PURE__ */ jsx36(HrefMenu, {}),
13086
- /* @__PURE__ */ jsx36(DuplicateButton, {}),
13087
- /* @__PURE__ */ jsx36(DeleteButton, {}),
13088
- /* @__PURE__ */ jsxs21(DropdownMenu, { open: dropdownOpen, onOpenChange: setDropdownOpen, children: [
13089
- /* @__PURE__ */ jsxs21(Tooltip, { children: [
13090
- /* @__PURE__ */ jsx36(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx36(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx36(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx36(MoreHorizontalIcon5, { className: "w-4 h-4" }) }) }) }),
13091
- /* @__PURE__ */ jsx36(TooltipContent, { side: "bottom", children: "More" })
13243
+ return /* @__PURE__ */ jsxs22(Fragment13, { children: [
13244
+ hasHref && /* @__PURE__ */ jsx37(FloatLinkPreview, { href }),
13245
+ /* @__PURE__ */ jsx37(HrefMenu, {}),
13246
+ /* @__PURE__ */ jsx37(DuplicateButton, {}),
13247
+ /* @__PURE__ */ jsx37(DeleteButton, {}),
13248
+ /* @__PURE__ */ jsxs22(DropdownMenu, { open: dropdownOpen, onOpenChange: setDropdownOpen, children: [
13249
+ /* @__PURE__ */ jsxs22(Tooltip, { children: [
13250
+ /* @__PURE__ */ jsx37(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(Button, { variant: "ghost", size: "icon", className: floatButtonVariants, children: /* @__PURE__ */ jsx37(MoreHorizontalIcon5, { className: "w-4 h-4" }) }) }) }),
13251
+ /* @__PURE__ */ jsx37(TooltipContent, { side: "bottom", children: "More" })
13092
13252
  ] }),
13093
- /* @__PURE__ */ jsxs21(DropdownMenuContent, { side: "bottom", className: "w-[250px] z-50001", children: [
13094
- /* @__PURE__ */ jsxs21(DropdownMenuItem, { onClick: toggleFluidOnMobile, children: [
13095
- /* @__PURE__ */ jsx36(Proportions, { className: "w-4 h-4" }),
13096
- /* @__PURE__ */ jsxs21("div", { className: "flex flex-row items-center justify-between gap-2 w-full", children: [
13097
- /* @__PURE__ */ jsx36("p", { children: "Full width on mobile" }),
13098
- isFluidOnMobile && /* @__PURE__ */ jsx36(CheckIcon6, { className: "w-4 h-4" })
13253
+ /* @__PURE__ */ jsxs22(DropdownMenuContent, { side: "bottom", className: "w-[250px] z-50001", children: [
13254
+ /* @__PURE__ */ jsxs22(DropdownMenuItem, { onClick: toggleFluidOnMobile, children: [
13255
+ /* @__PURE__ */ jsx37(Proportions, { className: "w-4 h-4" }),
13256
+ /* @__PURE__ */ jsxs22("div", { className: "flex flex-row items-center justify-between gap-2 w-full", children: [
13257
+ /* @__PURE__ */ jsx37("p", { children: "Full width on mobile" }),
13258
+ isFluidOnMobile && /* @__PURE__ */ jsx37(CheckIcon6, { className: "w-4 h-4" })
13099
13259
  ] })
13100
13260
  ] }),
13101
- /* @__PURE__ */ jsx36(DropdownMenuSeparator, {}),
13102
- /* @__PURE__ */ jsxs21(DropdownMenuSub, { children: [
13103
- /* @__PURE__ */ jsxs21(DropdownMenuSubTrigger, { children: [
13104
- /* @__PURE__ */ jsx36(Accessibility2, { className: "w-4 h-4" }),
13105
- /* @__PURE__ */ jsx36("p", { children: "Alternative Text" })
13261
+ /* @__PURE__ */ jsx37(DropdownMenuSeparator, {}),
13262
+ /* @__PURE__ */ jsxs22(DropdownMenuSub, { children: [
13263
+ /* @__PURE__ */ jsxs22(DropdownMenuSubTrigger, { children: [
13264
+ /* @__PURE__ */ jsx37(Accessibility2, { className: "w-4 h-4" }),
13265
+ /* @__PURE__ */ jsx37("p", { children: "Alternative Text" })
13106
13266
  ] }),
13107
- /* @__PURE__ */ jsx36(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs21(DropdownMenuSubContent, { className: "p-3 w-[250px] z-50001", children: [
13108
- /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2 mb-2", children: [
13109
- /* @__PURE__ */ jsx36(Label, { children: "Alternative Text" }),
13110
- /* @__PURE__ */ jsxs21("div", { className: "relative", children: [
13111
- /* @__PURE__ */ jsx36(
13267
+ /* @__PURE__ */ jsx37(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs22(DropdownMenuSubContent, { className: "p-3 w-[250px] z-50001", children: [
13268
+ /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-2 mb-2", children: [
13269
+ /* @__PURE__ */ jsx37(Label, { children: "Alternative Text" }),
13270
+ /* @__PURE__ */ jsxs22("div", { className: "relative", children: [
13271
+ /* @__PURE__ */ jsx37(
13112
13272
  Textarea,
13113
13273
  {
13114
13274
  placeholder: "Spacious living room with hardwood floors, large windows, and a cozy fireplace",
@@ -13118,14 +13278,14 @@ var ImageFloat = () => {
13118
13278
  onChange: (e) => setAltInputValue(e.target.value)
13119
13279
  }
13120
13280
  ),
13121
- /* @__PURE__ */ jsxs21("span", { className: "bg-white rounded-[12px] p-1 shadow-sm absolute bottom-2 right-2 text-xs text-muted-foreground", children: [
13281
+ /* @__PURE__ */ jsxs22("span", { className: "bg-white rounded-[12px] p-1 shadow-sm absolute bottom-2 right-2 text-xs text-muted-foreground", children: [
13122
13282
  altInputValue.length,
13123
13283
  "/250"
13124
13284
  ] })
13125
13285
  ] }),
13126
- /* @__PURE__ */ jsx36("p", { className: "text-xs text-muted-foreground mb-4", children: "Be descriptive and add context to keep your alt text clear for clients who use screen readers." })
13286
+ /* @__PURE__ */ jsx37("p", { className: "text-xs text-muted-foreground mb-4", children: "Be descriptive and add context to keep your alt text clear for clients who use screen readers." })
13127
13287
  ] }),
13128
- /* @__PURE__ */ jsx36(
13288
+ /* @__PURE__ */ jsx37(
13129
13289
  Button,
13130
13290
  {
13131
13291
  variant: "default",
@@ -13142,7 +13302,7 @@ var ImageFloat = () => {
13142
13302
  };
13143
13303
 
13144
13304
  // src/core/editor/components/mlsNumber-menu.tsx
13145
- import { useState as useState8, useEffect as useEffect11 } from "react";
13305
+ import { useState as useState9, useEffect as useEffect12 } from "react";
13146
13306
  import { HousePlusIcon, TrashIcon as TrashIcon5, XIcon as XIcon2, Loader2Icon } from "lucide-react";
13147
13307
 
13148
13308
  // src/services/repliers/commands.ts
@@ -13158,16 +13318,16 @@ async function getListingByMlsNumber(mlsNumber) {
13158
13318
  }
13159
13319
 
13160
13320
  // src/core/editor/components/mlsNumber-menu.tsx
13161
- import { Fragment as Fragment14, jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
13321
+ import { Fragment as Fragment14, jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
13162
13322
  var MlsNumberMenu = () => {
13163
13323
  const { focusIdx, template, updateElement, onToast } = useEditorStore();
13164
- const [isOpen, setIsOpen] = useState8(false);
13165
- const [inputValue, setInputValue] = useState8("");
13166
- const [propertyData, setPropertyData] = useState8(null);
13167
- const [isLoading, setIsLoading] = useState8(false);
13324
+ const [isOpen, setIsOpen] = useState9(false);
13325
+ const [inputValue, setInputValue] = useState9("");
13326
+ const [propertyData, setPropertyData] = useState9(null);
13327
+ const [isLoading, setIsLoading] = useState9(false);
13168
13328
  const propertyElement = focusIdx && template ? getValueByIdx(template, focusIdx) : null;
13169
13329
  const currentMlsNumber = propertyElement?.data?.value?.mlsNumber || "";
13170
- useEffect11(() => {
13330
+ useEffect12(() => {
13171
13331
  setInputValue(currentMlsNumber);
13172
13332
  setPropertyData(null);
13173
13333
  }, [focusIdx, currentMlsNumber]);
@@ -13235,25 +13395,25 @@ var MlsNumberMenu = () => {
13235
13395
  }
13236
13396
  }
13237
13397
  };
13238
- return /* @__PURE__ */ jsxs22(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
13239
- /* @__PURE__ */ jsxs22(Tooltip, { children: [
13240
- /* @__PURE__ */ jsx37(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs22(
13398
+ return /* @__PURE__ */ jsxs23(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
13399
+ /* @__PURE__ */ jsxs23(Tooltip, { children: [
13400
+ /* @__PURE__ */ jsx38(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx38(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs23(
13241
13401
  Button,
13242
13402
  {
13243
13403
  variant: "ghost",
13244
13404
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none h-[34px]",
13245
13405
  children: [
13246
- /* @__PURE__ */ jsx37(HousePlusIcon, { className: "size-4" }),
13247
- /* @__PURE__ */ jsx37("p", { children: "MLS" })
13406
+ /* @__PURE__ */ jsx38(HousePlusIcon, { className: "size-4" }),
13407
+ /* @__PURE__ */ jsx38("p", { children: "MLS" })
13248
13408
  ]
13249
13409
  }
13250
13410
  ) }) }),
13251
- /* @__PURE__ */ jsx37(TooltipContent, { side: "bottom", children: "Enter MLS Number" })
13411
+ /* @__PURE__ */ jsx38(TooltipContent, { side: "bottom", children: "Enter MLS Number" })
13252
13412
  ] }),
13253
- /* @__PURE__ */ jsxs22(DropdownMenuContent, { side: "bottom", className: "w-[250px] p-3 shadow-lg z-50001", children: [
13254
- /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-2", children: [
13255
- /* @__PURE__ */ jsx37(Label, { children: "Enter MLS Number" }),
13256
- /* @__PURE__ */ jsx37(
13413
+ /* @__PURE__ */ jsxs23(DropdownMenuContent, { side: "bottom", className: "w-[250px] p-3 shadow-lg z-50001", children: [
13414
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-2", children: [
13415
+ /* @__PURE__ */ jsx38(Label, { children: "Enter MLS Number" }),
13416
+ /* @__PURE__ */ jsx38(
13257
13417
  Input,
13258
13418
  {
13259
13419
  type: "text",
@@ -13266,10 +13426,10 @@ var MlsNumberMenu = () => {
13266
13426
  }
13267
13427
  )
13268
13428
  ] }),
13269
- /* @__PURE__ */ jsx37(Separator, { className: "my-2" }),
13270
- /* @__PURE__ */ jsxs22("div", { className: "flex flex-row justify-between items-center", children: [
13271
- /* @__PURE__ */ jsx37("div", { className: "flex flex-row", children: /* @__PURE__ */ jsxs22(Tooltip, { children: [
13272
- /* @__PURE__ */ jsx37(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx37(
13429
+ /* @__PURE__ */ jsx38(Separator, { className: "my-2" }),
13430
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-row justify-between items-center", children: [
13431
+ /* @__PURE__ */ jsx38("div", { className: "flex flex-row", children: /* @__PURE__ */ jsxs23(Tooltip, { children: [
13432
+ /* @__PURE__ */ jsx38(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx38(
13273
13433
  Button,
13274
13434
  {
13275
13435
  variant: "ghost",
@@ -13277,27 +13437,27 @@ var MlsNumberMenu = () => {
13277
13437
  className: "shadow-none transition-none cursor-pointer rounded-full outline-none",
13278
13438
  onClick: handleClear,
13279
13439
  disabled: !inputValue,
13280
- children: /* @__PURE__ */ jsx37(TrashIcon5, {})
13440
+ children: /* @__PURE__ */ jsx38(TrashIcon5, {})
13281
13441
  }
13282
13442
  ) }),
13283
- /* @__PURE__ */ jsx37(TooltipContent, { side: "bottom", className: "z-50001", children: "Clear" })
13443
+ /* @__PURE__ */ jsx38(TooltipContent, { side: "bottom", className: "z-50001", children: "Clear" })
13284
13444
  ] }) }),
13285
- /* @__PURE__ */ jsx37("div", { children: /* @__PURE__ */ jsx37(
13445
+ /* @__PURE__ */ jsx38("div", { children: /* @__PURE__ */ jsx38(
13286
13446
  Button,
13287
13447
  {
13288
13448
  variant: "default",
13289
13449
  className: "shadow-none transition-none cursor-pointer rounded-[12px] outline-none",
13290
13450
  onClick: handleDone,
13291
13451
  disabled: isLoading || !inputValue.trim(),
13292
- children: isLoading ? /* @__PURE__ */ jsx37(Loader2Icon, { className: "size-4 animate-spin" }) : "Done"
13452
+ children: isLoading ? /* @__PURE__ */ jsx38(Loader2Icon, { className: "size-4 animate-spin" }) : "Done"
13293
13453
  }
13294
13454
  ) })
13295
13455
  ] }),
13296
- propertyData && /* @__PURE__ */ jsxs22(Fragment14, { children: [
13297
- /* @__PURE__ */ jsx37(Separator, { className: "my-2" }),
13298
- /* @__PURE__ */ jsxs22("div", { className: "rounded-[12px] border overflow-hidden bg-card", children: [
13299
- /* @__PURE__ */ jsxs22("div", { className: "relative", children: [
13300
- /* @__PURE__ */ jsx37(
13456
+ propertyData && /* @__PURE__ */ jsxs23(Fragment14, { children: [
13457
+ /* @__PURE__ */ jsx38(Separator, { className: "my-2" }),
13458
+ /* @__PURE__ */ jsxs23("div", { className: "rounded-[12px] border overflow-hidden bg-card", children: [
13459
+ /* @__PURE__ */ jsxs23("div", { className: "relative", children: [
13460
+ /* @__PURE__ */ jsx38(
13301
13461
  "img",
13302
13462
  {
13303
13463
  src: `https://cdn.repliers.io/${propertyData.images?.[0]}`,
@@ -13305,35 +13465,35 @@ var MlsNumberMenu = () => {
13305
13465
  className: "w-full h-[120px] object-cover"
13306
13466
  }
13307
13467
  ),
13308
- /* @__PURE__ */ jsx37(
13468
+ /* @__PURE__ */ jsx38(
13309
13469
  Button,
13310
13470
  {
13311
13471
  variant: "ghost",
13312
13472
  size: "icon",
13313
13473
  className: "absolute top-1 right-1 h-6 w-6 bg-black/50 hover:bg-black/70 rounded-full",
13314
13474
  onClick: handleClearPreview,
13315
- children: /* @__PURE__ */ jsx37(XIcon2, { className: "size-3 text-white" })
13475
+ children: /* @__PURE__ */ jsx38(XIcon2, { className: "size-3 text-white" })
13316
13476
  }
13317
13477
  )
13318
13478
  ] }),
13319
- /* @__PURE__ */ jsxs22("div", { className: "p-2 flex flex-col gap-1", children: [
13320
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between", children: [
13321
- /* @__PURE__ */ jsx37("span", { className: "font-semibold text-sm", children: formatPrice(String(propertyData.listPrice || 0)) }),
13322
- /* @__PURE__ */ jsx37("span", { className: "text-xs px-2 py-0.5 rounded-full bg-green-100 text-green-700", children: propertyData.standardStatus || propertyData.status })
13479
+ /* @__PURE__ */ jsxs23("div", { className: "p-2 flex flex-col gap-1", children: [
13480
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
13481
+ /* @__PURE__ */ jsx38("span", { className: "font-semibold text-sm", children: formatPrice(String(propertyData.listPrice || 0)) }),
13482
+ /* @__PURE__ */ jsx38("span", { className: "text-xs px-2 py-0.5 rounded-full bg-green-100 text-green-700", children: propertyData.standardStatus || propertyData.status })
13323
13483
  ] }),
13324
- /* @__PURE__ */ jsxs22("div", { className: "text-sm", children: [
13484
+ /* @__PURE__ */ jsxs23("div", { className: "text-sm", children: [
13325
13485
  propertyData.address?.streetNumber,
13326
13486
  " ",
13327
13487
  propertyData.address?.streetName
13328
13488
  ] }),
13329
- /* @__PURE__ */ jsxs22("div", { className: "text-xs text-muted-foreground", children: [
13489
+ /* @__PURE__ */ jsxs23("div", { className: "text-xs text-muted-foreground", children: [
13330
13490
  propertyData.address?.city,
13331
13491
  ", ",
13332
13492
  propertyData.address?.state,
13333
13493
  " ",
13334
13494
  propertyData.address?.zip
13335
13495
  ] }),
13336
- /* @__PURE__ */ jsxs22("div", { className: "text-xs text-muted-foreground", children: [
13496
+ /* @__PURE__ */ jsxs23("div", { className: "text-xs text-muted-foreground", children: [
13337
13497
  propertyData.details?.numBedrooms,
13338
13498
  " bd | ",
13339
13499
  propertyData.details?.numBathrooms,
@@ -13341,8 +13501,8 @@ var MlsNumberMenu = () => {
13341
13501
  formatNumber(String(propertyData.details?.sqft || "--")),
13342
13502
  " sf"
13343
13503
  ] }),
13344
- propertyData.office?.brokerageName && /* @__PURE__ */ jsx37("div", { className: "text-xs text-muted-foreground truncate", children: propertyData.office.brokerageName }),
13345
- /* @__PURE__ */ jsx37(
13504
+ propertyData.office?.brokerageName && /* @__PURE__ */ jsx38("div", { className: "text-xs text-muted-foreground truncate", children: propertyData.office.brokerageName }),
13505
+ /* @__PURE__ */ jsx38(
13346
13506
  Button,
13347
13507
  {
13348
13508
  variant: "default",
@@ -13360,34 +13520,34 @@ var MlsNumberMenu = () => {
13360
13520
  };
13361
13521
 
13362
13522
  // src/core/editor/components/element-gear/property/float.tsx
13363
- import { Fragment as Fragment15, jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
13523
+ import { Fragment as Fragment15, jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
13364
13524
  function PropertyFloat() {
13365
13525
  const { href, hasHref } = useHref();
13366
- return /* @__PURE__ */ jsxs23(Fragment15, { children: [
13367
- hasHref && /* @__PURE__ */ jsx38(FloatLinkPreview, { href }),
13368
- /* @__PURE__ */ jsx38(HrefMenu, {}),
13369
- /* @__PURE__ */ jsx38(MlsNumberMenu, {})
13526
+ return /* @__PURE__ */ jsxs24(Fragment15, { children: [
13527
+ hasHref && /* @__PURE__ */ jsx39(FloatLinkPreview, { href }),
13528
+ /* @__PURE__ */ jsx39(HrefMenu, {}),
13529
+ /* @__PURE__ */ jsx39(MlsNumberMenu, {})
13370
13530
  ] });
13371
13531
  }
13372
13532
 
13373
13533
  // src/core/editor/components/element-gear/property/triple/float.tsx
13374
- import { Fragment as Fragment16, jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
13534
+ import { Fragment as Fragment16, jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
13375
13535
  var PropertyTripleItemFloat = () => {
13376
13536
  const { href, hasHref } = useHref();
13377
- return /* @__PURE__ */ jsxs24(Fragment16, { children: [
13378
- hasHref && /* @__PURE__ */ jsx39(FloatLinkPreview, { href }),
13379
- /* @__PURE__ */ jsx39(HrefMenu, {})
13537
+ return /* @__PURE__ */ jsxs25(Fragment16, { children: [
13538
+ hasHref && /* @__PURE__ */ jsx40(FloatLinkPreview, { href }),
13539
+ /* @__PURE__ */ jsx40(HrefMenu, {})
13380
13540
  ] });
13381
13541
  };
13382
13542
 
13383
13543
  // src/core/editor/components/float-ui/container.tsx
13384
- import { jsx as jsx40 } from "react/jsx-runtime";
13544
+ import { jsx as jsx41 } from "react/jsx-runtime";
13385
13545
  var FloatUIContainer = ({ ref, style, className, children }) => {
13386
- return /* @__PURE__ */ jsx40("div", { ref, style, className, children });
13546
+ return /* @__PURE__ */ jsx41("div", { ref, style, className, children });
13387
13547
  };
13388
13548
 
13389
13549
  // src/core/editor/components/element-float.tsx
13390
- import { jsx as jsx41 } from "react/jsx-runtime";
13550
+ import { jsx as jsx42 } from "react/jsx-runtime";
13391
13551
  var FLOAT_COMPONENTS = {
13392
13552
  "button": ButtonFloat,
13393
13553
  "section": SectionFloat,
@@ -13411,7 +13571,7 @@ var ElementFloat = ({ getReferenceRect, focusIdx, elementType }) => {
13411
13571
  if (!focusIdx || isDragging || textEditing) return null;
13412
13572
  const FloatComponent = FLOAT_COMPONENTS[elementType];
13413
13573
  if (!FloatComponent) return null;
13414
- return /* @__PURE__ */ jsx41(
13574
+ return /* @__PURE__ */ jsx42(
13415
13575
  ElementFloatContent,
13416
13576
  {
13417
13577
  getReferenceRect,
@@ -13420,7 +13580,7 @@ var ElementFloat = ({ getReferenceRect, focusIdx, elementType }) => {
13420
13580
  );
13421
13581
  };
13422
13582
  var ElementFloatContent = ({ getReferenceRect, FloatComponent }) => {
13423
- const virtualReference = useMemo11(() => ({
13583
+ const virtualReference = useMemo12(() => ({
13424
13584
  getBoundingClientRect: () => {
13425
13585
  const rect = getReferenceRect();
13426
13586
  if (!rect) {
@@ -13429,18 +13589,18 @@ var ElementFloatContent = ({ getReferenceRect, FloatComponent }) => {
13429
13589
  return rect;
13430
13590
  }
13431
13591
  }), [getReferenceRect]);
13432
- const { floatingStyles, refs, update } = useFloating4({
13592
+ const { floatingStyles, refs, update } = useFloating5({
13433
13593
  placement: "top",
13434
13594
  middleware: [
13435
- offset4(16),
13595
+ offset5(16),
13436
13596
  // 8px above the element
13437
- flip2({ padding: 8 }),
13597
+ flip3({ padding: 8 }),
13438
13598
  // Flip to bottom if not enough space above
13439
- shift3({ padding: 8 })
13599
+ shift4({ padding: 8 })
13440
13600
  // Keep within viewport
13441
13601
  ]
13442
13602
  });
13443
- useEffect12(() => {
13603
+ useEffect13(() => {
13444
13604
  const rect = getReferenceRect();
13445
13605
  if (!rect || !refs.floating.current) return;
13446
13606
  refs.setPositionReference(virtualReference);
@@ -13455,18 +13615,18 @@ var ElementFloatContent = ({ getReferenceRect, FloatComponent }) => {
13455
13615
  );
13456
13616
  return cleanup;
13457
13617
  }, [getReferenceRect, refs, update, virtualReference]);
13458
- return /* @__PURE__ */ jsx41(FloatUIContainer, { ref: refs.setFloating, style: floatingStyles, className: "bg-white flex items-center justify-center border border-1 h-[36px] w-fit shadow-md rounded-full z-50", children: /* @__PURE__ */ jsx41(FloatComponent, {}) });
13618
+ return /* @__PURE__ */ jsx42(FloatUIContainer, { ref: refs.setFloating, style: floatingStyles, className: "bg-white flex items-center justify-center border border-1 h-[36px] w-fit shadow-md rounded-full z-50", children: /* @__PURE__ */ jsx42(FloatComponent, {}) });
13459
13619
  };
13460
13620
 
13461
13621
  // src/core/editor/components/scaling/divider-scale.tsx
13462
- import { useMemo as useMemo12, useEffect as useEffect13, useState as useState9, useRef as useRef5, useCallback as useCallback11 } from "react";
13463
- import { useFloating as useFloating5, offset as offset5, autoUpdate as autoUpdate4 } from "@floating-ui/react";
13464
- import { jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
13622
+ import { useMemo as useMemo13, useEffect as useEffect14, useState as useState10, useRef as useRef6, useCallback as useCallback12 } from "react";
13623
+ import { useFloating as useFloating6, offset as offset6, autoUpdate as autoUpdate4 } from "@floating-ui/react";
13624
+ import { jsx as jsx43, jsxs as jsxs26 } from "react/jsx-runtime";
13465
13625
  var DividerScale = ({ getReferenceRect }) => {
13466
- const [dimensions, setDimensions] = useState9({ width: 0, height: 0 });
13467
- const [activeSide, setActiveSide] = useState9(null);
13626
+ const [dimensions, setDimensions] = useState10({ width: 0, height: 0 });
13627
+ const [activeSide, setActiveSide] = useState10(null);
13468
13628
  const { focusIdx, template, setIsScaling } = useEditorStore();
13469
- const { currentWidth, currentAlign } = useMemo12(() => {
13629
+ const { currentWidth, currentAlign } = useMemo13(() => {
13470
13630
  if (!focusIdx || !template) return { currentWidth: 100, currentAlign: "center" };
13471
13631
  const element = getValueByIdx(template, focusIdx);
13472
13632
  const rawWidth = element?.attributes?.width;
@@ -13475,13 +13635,13 @@ var DividerScale = ({ getReferenceRect }) => {
13475
13635
  const align = element?.attributes?.align || "center";
13476
13636
  return { currentWidth: width, currentAlign: align };
13477
13637
  }, [focusIdx, template]);
13478
- const dragRef = useRef5(null);
13479
- const getContainerWidth = useCallback11(() => {
13638
+ const dragRef = useRef6(null);
13639
+ const getContainerWidth = useCallback12(() => {
13480
13640
  const rect = getReferenceRect();
13481
13641
  if (!rect || currentWidth <= 0) return null;
13482
13642
  return rect.width / (currentWidth / 100);
13483
13643
  }, [getReferenceRect, currentWidth]);
13484
- const handlePointerDown = useCallback11((e, side) => {
13644
+ const handlePointerDown = useCallback12((e, side) => {
13485
13645
  e.preventDefault();
13486
13646
  e.stopPropagation();
13487
13647
  const containerWidth = getContainerWidth();
@@ -13499,7 +13659,7 @@ var DividerScale = ({ getReferenceRect }) => {
13499
13659
  document.addEventListener("pointermove", handlePointerMove);
13500
13660
  document.addEventListener("pointerup", handlePointerUp);
13501
13661
  }, [getContainerWidth, currentWidth, currentAlign, setIsScaling]);
13502
- const handlePointerMove = useCallback11((e) => {
13662
+ const handlePointerMove = useCallback12((e) => {
13503
13663
  if (!dragRef.current) return;
13504
13664
  const { startX, startWidth, containerWidth, side, align } = dragRef.current;
13505
13665
  const deltaX = e.clientX - startX;
@@ -13519,20 +13679,20 @@ var DividerScale = ({ getReferenceRect }) => {
13519
13679
  }
13520
13680
  });
13521
13681
  }, []);
13522
- const handlePointerUp = useCallback11(() => {
13682
+ const handlePointerUp = useCallback12(() => {
13523
13683
  setActiveSide(null);
13524
13684
  setIsScaling(false);
13525
13685
  dragRef.current = null;
13526
13686
  document.removeEventListener("pointermove", handlePointerMove);
13527
13687
  document.removeEventListener("pointerup", handlePointerUp);
13528
13688
  }, [handlePointerMove, setIsScaling]);
13529
- useEffect13(() => {
13689
+ useEffect14(() => {
13530
13690
  return () => {
13531
13691
  document.removeEventListener("pointermove", handlePointerMove);
13532
13692
  document.removeEventListener("pointerup", handlePointerUp);
13533
13693
  };
13534
13694
  }, [handlePointerMove, handlePointerUp]);
13535
- const virtualReference = useMemo12(() => ({
13695
+ const virtualReference = useMemo13(() => ({
13536
13696
  getBoundingClientRect: () => {
13537
13697
  const rect = getReferenceRect();
13538
13698
  if (!rect) {
@@ -13541,13 +13701,13 @@ var DividerScale = ({ getReferenceRect }) => {
13541
13701
  return rect;
13542
13702
  }
13543
13703
  }), [getReferenceRect]);
13544
- const { floatingStyles, refs, update } = useFloating5({
13704
+ const { floatingStyles, refs, update } = useFloating6({
13545
13705
  placement: "bottom-start",
13546
13706
  middleware: [
13547
- offset5(({ rects }) => -rects.reference.height)
13707
+ offset6(({ rects }) => -rects.reference.height)
13548
13708
  ]
13549
13709
  });
13550
- useEffect13(() => {
13710
+ useEffect14(() => {
13551
13711
  const rect = getReferenceRect();
13552
13712
  if (!rect || !refs.floating.current) return;
13553
13713
  refs.setPositionReference(virtualReference);
@@ -13574,7 +13734,7 @@ var DividerScale = ({ getReferenceRect }) => {
13574
13734
  }, [getReferenceRect, refs, update, virtualReference]);
13575
13735
  const showLeftHandle = currentAlign !== "left";
13576
13736
  const showRightHandle = currentAlign !== "right";
13577
- return /* @__PURE__ */ jsxs25(
13737
+ return /* @__PURE__ */ jsxs26(
13578
13738
  "div",
13579
13739
  {
13580
13740
  ref: refs.setFloating,
@@ -13586,14 +13746,14 @@ var DividerScale = ({ getReferenceRect }) => {
13586
13746
  },
13587
13747
  className: "relative flex flex-row items-center justify-between",
13588
13748
  children: [
13589
- showLeftHandle && (activeSide === null || activeSide === "left") && /* @__PURE__ */ jsx42(
13749
+ showLeftHandle && (activeSide === null || activeSide === "left") && /* @__PURE__ */ jsx43(
13590
13750
  "div",
13591
13751
  {
13592
13752
  onPointerDown: (e) => handlePointerDown(e, "left"),
13593
13753
  className: `w-[18px] h-[18px] cursor-ew-resize bg-background shadow-md border rounded-full absolute -left-[9px] top-1/2 -translate-y-1/2 touch-none select-none ${activeSide === "left" ? "bg-blue-400 border-blue-300" : "hover:bg-blue-400 hover:border-blue-300"}`
13594
13754
  }
13595
13755
  ),
13596
- showRightHandle && (activeSide === null || activeSide === "right") && /* @__PURE__ */ jsx42(
13756
+ showRightHandle && (activeSide === null || activeSide === "right") && /* @__PURE__ */ jsx43(
13597
13757
  "div",
13598
13758
  {
13599
13759
  onPointerDown: (e) => handlePointerDown(e, "right"),
@@ -13606,14 +13766,14 @@ var DividerScale = ({ getReferenceRect }) => {
13606
13766
  };
13607
13767
 
13608
13768
  // src/core/editor/components/scaling/button-scale.tsx
13609
- import { useMemo as useMemo13, useEffect as useEffect14, useState as useState10, useRef as useRef6, useCallback as useCallback12 } from "react";
13610
- import { useFloating as useFloating6, offset as offset6, autoUpdate as autoUpdate5 } from "@floating-ui/react";
13611
- import { jsx as jsx43, jsxs as jsxs26 } from "react/jsx-runtime";
13769
+ import { useMemo as useMemo14, useEffect as useEffect15, useState as useState11, useRef as useRef7, useCallback as useCallback13 } from "react";
13770
+ import { useFloating as useFloating7, offset as offset7, autoUpdate as autoUpdate5 } from "@floating-ui/react";
13771
+ import { jsx as jsx44, jsxs as jsxs27 } from "react/jsx-runtime";
13612
13772
  var ButtonScale = ({ getReferenceRect }) => {
13613
- const [dimensions, setDimensions] = useState10({ width: 0, height: 0 });
13614
- const [activeSide, setActiveSide] = useState10(null);
13773
+ const [dimensions, setDimensions] = useState11({ width: 0, height: 0 });
13774
+ const [activeSide, setActiveSide] = useState11(null);
13615
13775
  const { focusIdx, template, setIsScaling } = useEditorStore();
13616
- const { currentWidth, currentHeight, currentAlign } = useMemo13(() => {
13776
+ const { currentWidth, currentHeight, currentAlign } = useMemo14(() => {
13617
13777
  if (!focusIdx || !template) {
13618
13778
  return { currentWidth: 24, currentHeight: 44, currentAlign: "center" };
13619
13779
  }
@@ -13627,13 +13787,13 @@ var ButtonScale = ({ getReferenceRect }) => {
13627
13787
  const align = element?.attributes?.align || "center";
13628
13788
  return { currentWidth: width, currentHeight: height, currentAlign: align };
13629
13789
  }, [focusIdx, template]);
13630
- const dragRef = useRef6(null);
13631
- const getContainerWidth = useCallback12(() => {
13790
+ const dragRef = useRef7(null);
13791
+ const getContainerWidth = useCallback13(() => {
13632
13792
  const rect = getReferenceRect();
13633
13793
  if (!rect || currentWidth <= 0) return null;
13634
13794
  return rect.width / (currentWidth / 100);
13635
13795
  }, [getReferenceRect, currentWidth]);
13636
- const handlePointerDown = useCallback12((e, side) => {
13796
+ const handlePointerDown = useCallback13((e, side) => {
13637
13797
  e.preventDefault();
13638
13798
  e.stopPropagation();
13639
13799
  if (document.activeElement instanceof HTMLElement) {
@@ -13655,7 +13815,7 @@ var ButtonScale = ({ getReferenceRect }) => {
13655
13815
  document.addEventListener("pointermove", handlePointerMove);
13656
13816
  document.addEventListener("pointerup", handlePointerUp);
13657
13817
  }, [getContainerWidth, currentWidth, currentHeight, currentAlign, setIsScaling]);
13658
- const handlePointerMove = useCallback12((e) => {
13818
+ const handlePointerMove = useCallback13((e) => {
13659
13819
  if (!dragRef.current) return;
13660
13820
  const { startX, startY, startWidth, startHeight, containerWidth, side, align } = dragRef.current;
13661
13821
  const state = useEditorStore.getState();
@@ -13687,20 +13847,20 @@ var ButtonScale = ({ getReferenceRect }) => {
13687
13847
  });
13688
13848
  }
13689
13849
  }, []);
13690
- const handlePointerUp = useCallback12(() => {
13850
+ const handlePointerUp = useCallback13(() => {
13691
13851
  setActiveSide(null);
13692
13852
  setIsScaling(false);
13693
13853
  dragRef.current = null;
13694
13854
  document.removeEventListener("pointermove", handlePointerMove);
13695
13855
  document.removeEventListener("pointerup", handlePointerUp);
13696
13856
  }, [handlePointerMove, setIsScaling]);
13697
- useEffect14(() => {
13857
+ useEffect15(() => {
13698
13858
  return () => {
13699
13859
  document.removeEventListener("pointermove", handlePointerMove);
13700
13860
  document.removeEventListener("pointerup", handlePointerUp);
13701
13861
  };
13702
13862
  }, [handlePointerMove, handlePointerUp]);
13703
- const virtualReference = useMemo13(() => ({
13863
+ const virtualReference = useMemo14(() => ({
13704
13864
  getBoundingClientRect: () => {
13705
13865
  const rect = getReferenceRect();
13706
13866
  if (!rect) {
@@ -13709,13 +13869,13 @@ var ButtonScale = ({ getReferenceRect }) => {
13709
13869
  return rect;
13710
13870
  }
13711
13871
  }), [getReferenceRect]);
13712
- const { floatingStyles, refs, update } = useFloating6({
13872
+ const { floatingStyles, refs, update } = useFloating7({
13713
13873
  placement: "bottom-start",
13714
13874
  middleware: [
13715
- offset6(({ rects }) => -rects.reference.height)
13875
+ offset7(({ rects }) => -rects.reference.height)
13716
13876
  ]
13717
13877
  });
13718
- useEffect14(() => {
13878
+ useEffect15(() => {
13719
13879
  const rect = getReferenceRect();
13720
13880
  if (!rect || !refs.floating.current) return;
13721
13881
  refs.setPositionReference(virtualReference);
@@ -13744,7 +13904,7 @@ var ButtonScale = ({ getReferenceRect }) => {
13744
13904
  const showRightHandle = currentAlign !== "right";
13745
13905
  const handleBaseClass = "bg-background shadow-md border rounded-full absolute touch-none select-none pointer-events-auto";
13746
13906
  const getHandleActiveClass = (side) => activeSide === side ? "bg-blue-400 border-blue-300" : "hover:bg-blue-400 hover:border-blue-300";
13747
- return /* @__PURE__ */ jsxs26(
13907
+ return /* @__PURE__ */ jsxs27(
13748
13908
  "div",
13749
13909
  {
13750
13910
  ref: refs.setFloating,
@@ -13756,28 +13916,28 @@ var ButtonScale = ({ getReferenceRect }) => {
13756
13916
  },
13757
13917
  className: "relative pointer-events-none",
13758
13918
  children: [
13759
- (activeSide === null || activeSide === "top") && /* @__PURE__ */ jsx43(
13919
+ (activeSide === null || activeSide === "top") && /* @__PURE__ */ jsx44(
13760
13920
  "div",
13761
13921
  {
13762
13922
  onPointerDown: (e) => handlePointerDown(e, "top"),
13763
13923
  className: `w-[18px] h-[8px] cursor-ns-resize ${handleBaseClass} left-1/2 -translate-x-1/2 -top-[4px] ${getHandleActiveClass("top")}`
13764
13924
  }
13765
13925
  ),
13766
- showRightHandle && (activeSide === null || activeSide === "right") && /* @__PURE__ */ jsx43(
13926
+ showRightHandle && (activeSide === null || activeSide === "right") && /* @__PURE__ */ jsx44(
13767
13927
  "div",
13768
13928
  {
13769
13929
  onPointerDown: (e) => handlePointerDown(e, "right"),
13770
13930
  className: `w-[8px] h-[18px] cursor-ew-resize ${handleBaseClass} top-1/2 -translate-y-1/2 -right-[4px] ${getHandleActiveClass("right")}`
13771
13931
  }
13772
13932
  ),
13773
- (activeSide === null || activeSide === "bottom") && /* @__PURE__ */ jsx43(
13933
+ (activeSide === null || activeSide === "bottom") && /* @__PURE__ */ jsx44(
13774
13934
  "div",
13775
13935
  {
13776
13936
  onPointerDown: (e) => handlePointerDown(e, "bottom"),
13777
13937
  className: `w-[18px] h-[8px] cursor-ns-resize ${handleBaseClass} left-1/2 -translate-x-1/2 -bottom-[4px] ${getHandleActiveClass("bottom")}`
13778
13938
  }
13779
13939
  ),
13780
- showLeftHandle && (activeSide === null || activeSide === "left") && /* @__PURE__ */ jsx43(
13940
+ showLeftHandle && (activeSide === null || activeSide === "left") && /* @__PURE__ */ jsx44(
13781
13941
  "div",
13782
13942
  {
13783
13943
  onPointerDown: (e) => handlePointerDown(e, "left"),
@@ -13790,14 +13950,15 @@ var ButtonScale = ({ getReferenceRect }) => {
13790
13950
  };
13791
13951
 
13792
13952
  // src/core/editor/components/scaling/image-scale.tsx
13793
- import { useMemo as useMemo14, useEffect as useEffect15, useState as useState11, useRef as useRef7, useCallback as useCallback13 } from "react";
13794
- import { useFloating as useFloating7, offset as offset7, autoUpdate as autoUpdate6 } from "@floating-ui/react";
13795
- import { jsx as jsx44, jsxs as jsxs27 } from "react/jsx-runtime";
13953
+ import { useMemo as useMemo15, useEffect as useEffect16, useState as useState12, useRef as useRef8, useCallback as useCallback14 } from "react";
13954
+ import { useFloating as useFloating8, offset as offset8, autoUpdate as autoUpdate6 } from "@floating-ui/react";
13955
+ import { jsx as jsx45, jsxs as jsxs28 } from "react/jsx-runtime";
13956
+ var isCorner = (side) => side === "top-left" || side === "top-right" || side === "bottom-left" || side === "bottom-right";
13796
13957
  var ImageScale = ({ getReferenceRect }) => {
13797
- const [dimensions, setDimensions] = useState11({ width: 0, height: 0 });
13798
- const [activeSide, setActiveSide] = useState11(null);
13958
+ const [dimensions, setDimensions] = useState12({ width: 0, height: 0 });
13959
+ const [activeSide, setActiveSide] = useState12(null);
13799
13960
  const { focusIdx, template, setIsScaling } = useEditorStore();
13800
- const { currentWidth, currentHeight, currentAlign } = useMemo14(() => {
13961
+ const { currentWidth, currentHeight, currentAlign } = useMemo15(() => {
13801
13962
  if (!focusIdx || !template) {
13802
13963
  return { currentWidth: 0, currentHeight: 0, currentAlign: "center" };
13803
13964
  }
@@ -13811,8 +13972,8 @@ var ImageScale = ({ getReferenceRect }) => {
13811
13972
  const align = element?.attributes?.align || "center";
13812
13973
  return { currentWidth: width, currentHeight: height, currentAlign: align };
13813
13974
  }, [focusIdx, template]);
13814
- const dragRef = useRef7(null);
13815
- const handlePointerDown = useCallback13((e, side) => {
13975
+ const dragRef = useRef8(null);
13976
+ const handlePointerDown = useCallback14((e, side) => {
13816
13977
  e.preventDefault();
13817
13978
  e.stopPropagation();
13818
13979
  if (document.activeElement instanceof HTMLElement) {
@@ -13830,12 +13991,13 @@ var ImageScale = ({ getReferenceRect }) => {
13830
13991
  startWidth: effectiveWidth,
13831
13992
  startHeight: effectiveHeight,
13832
13993
  side,
13833
- align: currentAlign
13994
+ align: currentAlign,
13995
+ aspectRatio: effectiveHeight > 0 ? effectiveWidth / effectiveHeight : 1
13834
13996
  };
13835
13997
  document.addEventListener("pointermove", handlePointerMove);
13836
13998
  document.addEventListener("pointerup", handlePointerUp);
13837
13999
  }, [getReferenceRect, currentWidth, currentHeight, currentAlign, setIsScaling]);
13838
- const handlePointerMove = useCallback13((e) => {
14000
+ const handlePointerMove = useCallback14((e) => {
13839
14001
  if (!dragRef.current) return;
13840
14002
  const { startX, startY, startWidth, startHeight, side, align } = dragRef.current;
13841
14003
  const state = useEditorStore.getState();
@@ -13843,7 +14005,35 @@ var ImageScale = ({ getReferenceRect }) => {
13843
14005
  if (!currentFocusIdx || !currentTemplate) return;
13844
14006
  const element = getValueByIdx(currentTemplate, currentFocusIdx);
13845
14007
  if (!element) return;
13846
- if (side === "left" || side === "right") {
14008
+ if (isCorner(side)) {
14009
+ const { aspectRatio } = dragRef.current;
14010
+ const deltaX = e.clientX - startX;
14011
+ const deltaY = e.clientY - startY;
14012
+ const signX = side.includes("left") ? -1 : 1;
14013
+ const signY = side.includes("top") ? -1 : 1;
14014
+ const alignMultiplier = align === "center" ? 2 : 1;
14015
+ const absDX = Math.abs(deltaX);
14016
+ const absDY = Math.abs(deltaY);
14017
+ let newWidth;
14018
+ let newHeight;
14019
+ if (absDX >= absDY) {
14020
+ newWidth = startWidth + signX * deltaX * alignMultiplier;
14021
+ newHeight = newWidth / aspectRatio;
14022
+ } else {
14023
+ newHeight = startHeight + signY * deltaY;
14024
+ newWidth = newHeight * aspectRatio;
14025
+ }
14026
+ const clampedWidth = Math.max(20, Math.min(600, newWidth));
14027
+ const clampedHeight = Math.max(20, Math.min(600, clampedWidth / aspectRatio));
14028
+ const finalWidth = clampedHeight * aspectRatio;
14029
+ updateElement(currentFocusIdx, {
14030
+ attributes: {
14031
+ ...element.attributes,
14032
+ width: `${Math.round(finalWidth)}px`,
14033
+ height: `${Math.round(clampedHeight)}px`
14034
+ }
14035
+ });
14036
+ } else if (side === "left" || side === "right") {
13847
14037
  const deltaX = e.clientX - startX;
13848
14038
  const alignMultiplier = align === "center" ? 2 : 1;
13849
14039
  const newWidth = side === "left" ? startWidth - deltaX * alignMultiplier : startWidth + deltaX * alignMultiplier;
@@ -13866,20 +14056,20 @@ var ImageScale = ({ getReferenceRect }) => {
13866
14056
  });
13867
14057
  }
13868
14058
  }, []);
13869
- const handlePointerUp = useCallback13(() => {
14059
+ const handlePointerUp = useCallback14(() => {
13870
14060
  setActiveSide(null);
13871
14061
  setIsScaling(false);
13872
14062
  dragRef.current = null;
13873
14063
  document.removeEventListener("pointermove", handlePointerMove);
13874
14064
  document.removeEventListener("pointerup", handlePointerUp);
13875
14065
  }, [handlePointerMove, setIsScaling]);
13876
- useEffect15(() => {
14066
+ useEffect16(() => {
13877
14067
  return () => {
13878
14068
  document.removeEventListener("pointermove", handlePointerMove);
13879
14069
  document.removeEventListener("pointerup", handlePointerUp);
13880
14070
  };
13881
14071
  }, [handlePointerMove, handlePointerUp]);
13882
- const virtualReference = useMemo14(() => ({
14072
+ const virtualReference = useMemo15(() => ({
13883
14073
  getBoundingClientRect: () => {
13884
14074
  const rect = getReferenceRect();
13885
14075
  if (!rect) {
@@ -13888,13 +14078,13 @@ var ImageScale = ({ getReferenceRect }) => {
13888
14078
  return rect;
13889
14079
  }
13890
14080
  }), [getReferenceRect]);
13891
- const { floatingStyles, refs, update } = useFloating7({
14081
+ const { floatingStyles, refs, update } = useFloating8({
13892
14082
  placement: "bottom-start",
13893
14083
  middleware: [
13894
- offset7(({ rects }) => -rects.reference.height)
14084
+ offset8(({ rects }) => -rects.reference.height)
13895
14085
  ]
13896
14086
  });
13897
- useEffect15(() => {
14087
+ useEffect16(() => {
13898
14088
  const rect = getReferenceRect();
13899
14089
  if (!rect || !refs.floating.current) return;
13900
14090
  refs.setPositionReference(virtualReference);
@@ -13921,9 +14111,13 @@ var ImageScale = ({ getReferenceRect }) => {
13921
14111
  }, [getReferenceRect, refs, update, virtualReference]);
13922
14112
  const showLeftHandle = currentAlign !== "left";
13923
14113
  const showRightHandle = currentAlign !== "right";
14114
+ const showTopLeft = currentAlign !== "left";
14115
+ const showTopRight = currentAlign !== "right";
14116
+ const showBottomLeft = currentAlign !== "left";
14117
+ const showBottomRight = currentAlign !== "right";
13924
14118
  const handleBaseClass = "bg-background shadow-md border rounded-full absolute touch-none select-none pointer-events-auto";
13925
14119
  const getHandleActiveClass = (side) => activeSide === side ? "bg-blue-400 border-blue-300" : "hover:bg-blue-400 hover:border-blue-300";
13926
- return /* @__PURE__ */ jsxs27(
14120
+ return /* @__PURE__ */ jsxs28(
13927
14121
  "div",
13928
14122
  {
13929
14123
  ref: refs.setFloating,
@@ -13935,33 +14129,61 @@ var ImageScale = ({ getReferenceRect }) => {
13935
14129
  },
13936
14130
  className: "relative pointer-events-none",
13937
14131
  children: [
13938
- (activeSide === null || activeSide === "top") && /* @__PURE__ */ jsx44(
14132
+ (activeSide === null || activeSide === "top") && /* @__PURE__ */ jsx45(
13939
14133
  "div",
13940
14134
  {
13941
14135
  onPointerDown: (e) => handlePointerDown(e, "top"),
13942
14136
  className: `w-[18px] h-[8px] cursor-ns-resize ${handleBaseClass} left-1/2 -translate-x-1/2 -top-[4px] ${getHandleActiveClass("top")}`
13943
14137
  }
13944
14138
  ),
13945
- showRightHandle && (activeSide === null || activeSide === "right") && /* @__PURE__ */ jsx44(
14139
+ showRightHandle && (activeSide === null || activeSide === "right") && /* @__PURE__ */ jsx45(
13946
14140
  "div",
13947
14141
  {
13948
14142
  onPointerDown: (e) => handlePointerDown(e, "right"),
13949
14143
  className: `w-[8px] h-[18px] cursor-ew-resize ${handleBaseClass} top-1/2 -translate-y-1/2 -right-[4px] ${getHandleActiveClass("right")}`
13950
14144
  }
13951
14145
  ),
13952
- (activeSide === null || activeSide === "bottom") && /* @__PURE__ */ jsx44(
14146
+ (activeSide === null || activeSide === "bottom") && /* @__PURE__ */ jsx45(
13953
14147
  "div",
13954
14148
  {
13955
14149
  onPointerDown: (e) => handlePointerDown(e, "bottom"),
13956
14150
  className: `w-[18px] h-[8px] cursor-ns-resize ${handleBaseClass} left-1/2 -translate-x-1/2 -bottom-[4px] ${getHandleActiveClass("bottom")}`
13957
14151
  }
13958
14152
  ),
13959
- showLeftHandle && (activeSide === null || activeSide === "left") && /* @__PURE__ */ jsx44(
14153
+ showLeftHandle && (activeSide === null || activeSide === "left") && /* @__PURE__ */ jsx45(
13960
14154
  "div",
13961
14155
  {
13962
14156
  onPointerDown: (e) => handlePointerDown(e, "left"),
13963
14157
  className: `w-[8px] h-[18px] cursor-ew-resize ${handleBaseClass} top-1/2 -translate-y-1/2 -left-[4px] ${getHandleActiveClass("left")}`
13964
14158
  }
14159
+ ),
14160
+ showTopLeft && (activeSide === null || activeSide === "top-left") && /* @__PURE__ */ jsx45(
14161
+ "div",
14162
+ {
14163
+ onPointerDown: (e) => handlePointerDown(e, "top-left"),
14164
+ className: `w-[10px] h-[10px] cursor-nwse-resize ${handleBaseClass} -top-[5px] -left-[5px] ${getHandleActiveClass("top-left")}`
14165
+ }
14166
+ ),
14167
+ showTopRight && (activeSide === null || activeSide === "top-right") && /* @__PURE__ */ jsx45(
14168
+ "div",
14169
+ {
14170
+ onPointerDown: (e) => handlePointerDown(e, "top-right"),
14171
+ className: `w-[10px] h-[10px] cursor-nesw-resize ${handleBaseClass} -top-[5px] -right-[5px] ${getHandleActiveClass("top-right")}`
14172
+ }
14173
+ ),
14174
+ showBottomLeft && (activeSide === null || activeSide === "bottom-left") && /* @__PURE__ */ jsx45(
14175
+ "div",
14176
+ {
14177
+ onPointerDown: (e) => handlePointerDown(e, "bottom-left"),
14178
+ className: `w-[10px] h-[10px] cursor-nesw-resize ${handleBaseClass} -bottom-[5px] -left-[5px] ${getHandleActiveClass("bottom-left")}`
14179
+ }
14180
+ ),
14181
+ showBottomRight && (activeSide === null || activeSide === "bottom-right") && /* @__PURE__ */ jsx45(
14182
+ "div",
14183
+ {
14184
+ onPointerDown: (e) => handlePointerDown(e, "bottom-right"),
14185
+ className: `w-[10px] h-[10px] cursor-nwse-resize ${handleBaseClass} -bottom-[5px] -right-[5px] ${getHandleActiveClass("bottom-right")}`
14186
+ }
13965
14187
  )
13966
14188
  ]
13967
14189
  }
@@ -13969,22 +14191,22 @@ var ImageScale = ({ getReferenceRect }) => {
13969
14191
  };
13970
14192
 
13971
14193
  // src/core/editor/components/scaling/spacer-scale.tsx
13972
- import { useMemo as useMemo15, useEffect as useEffect16, useState as useState12, useRef as useRef8, useCallback as useCallback14 } from "react";
13973
- import { useFloating as useFloating8, offset as offset8, autoUpdate as autoUpdate7 } from "@floating-ui/react";
13974
- import { jsx as jsx45, jsxs as jsxs28 } from "react/jsx-runtime";
14194
+ import { useMemo as useMemo16, useEffect as useEffect17, useState as useState13, useRef as useRef9, useCallback as useCallback15 } from "react";
14195
+ import { useFloating as useFloating9, offset as offset9, autoUpdate as autoUpdate7 } from "@floating-ui/react";
14196
+ import { jsx as jsx46, jsxs as jsxs29 } from "react/jsx-runtime";
13975
14197
  var SpacerScale = ({ getReferenceRect }) => {
13976
- const [dimensions, setDimensions] = useState12({ width: 0, height: 0 });
13977
- const [activeSide, setActiveSide] = useState12(null);
14198
+ const [dimensions, setDimensions] = useState13({ width: 0, height: 0 });
14199
+ const [activeSide, setActiveSide] = useState13(null);
13978
14200
  const { focusIdx, template, setIsScaling } = useEditorStore();
13979
- const currentHeight = useMemo15(() => {
14201
+ const currentHeight = useMemo16(() => {
13980
14202
  if (!focusIdx || !template) return 12;
13981
14203
  const element = getValueByIdx(template, focusIdx);
13982
14204
  const rawHeight = element?.attributes?.height;
13983
14205
  const parsedHeight = rawHeight ? parseFloat(rawHeight.replace("px", "")) : 12;
13984
14206
  return isNaN(parsedHeight) ? 12 : Math.max(12, Math.min(200, parsedHeight));
13985
14207
  }, [focusIdx, template]);
13986
- const dragRef = useRef8(null);
13987
- const handlePointerDown = useCallback14((e, side) => {
14208
+ const dragRef = useRef9(null);
14209
+ const handlePointerDown = useCallback15((e, side) => {
13988
14210
  e.preventDefault();
13989
14211
  e.stopPropagation();
13990
14212
  if (document.activeElement instanceof HTMLElement) {
@@ -14000,7 +14222,7 @@ var SpacerScale = ({ getReferenceRect }) => {
14000
14222
  document.addEventListener("pointermove", handlePointerMove);
14001
14223
  document.addEventListener("pointerup", handlePointerUp);
14002
14224
  }, [currentHeight, setIsScaling]);
14003
- const handlePointerMove = useCallback14((e) => {
14225
+ const handlePointerMove = useCallback15((e) => {
14004
14226
  if (!dragRef.current) return;
14005
14227
  const { startY, startHeight, side } = dragRef.current;
14006
14228
  const state = useEditorStore.getState();
@@ -14018,20 +14240,20 @@ var SpacerScale = ({ getReferenceRect }) => {
14018
14240
  }
14019
14241
  });
14020
14242
  }, []);
14021
- const handlePointerUp = useCallback14(() => {
14243
+ const handlePointerUp = useCallback15(() => {
14022
14244
  setActiveSide(null);
14023
14245
  setIsScaling(false);
14024
14246
  dragRef.current = null;
14025
14247
  document.removeEventListener("pointermove", handlePointerMove);
14026
14248
  document.removeEventListener("pointerup", handlePointerUp);
14027
14249
  }, [handlePointerMove, setIsScaling]);
14028
- useEffect16(() => {
14250
+ useEffect17(() => {
14029
14251
  return () => {
14030
14252
  document.removeEventListener("pointermove", handlePointerMove);
14031
14253
  document.removeEventListener("pointerup", handlePointerUp);
14032
14254
  };
14033
14255
  }, [handlePointerMove, handlePointerUp]);
14034
- const virtualReference = useMemo15(() => ({
14256
+ const virtualReference = useMemo16(() => ({
14035
14257
  getBoundingClientRect: () => {
14036
14258
  const rect = getReferenceRect();
14037
14259
  if (!rect) {
@@ -14040,13 +14262,13 @@ var SpacerScale = ({ getReferenceRect }) => {
14040
14262
  return rect;
14041
14263
  }
14042
14264
  }), [getReferenceRect]);
14043
- const { floatingStyles, refs, update } = useFloating8({
14265
+ const { floatingStyles, refs, update } = useFloating9({
14044
14266
  placement: "bottom-start",
14045
14267
  middleware: [
14046
- offset8(({ rects }) => -rects.reference.height)
14268
+ offset9(({ rects }) => -rects.reference.height)
14047
14269
  ]
14048
14270
  });
14049
- useEffect16(() => {
14271
+ useEffect17(() => {
14050
14272
  const rect = getReferenceRect();
14051
14273
  if (!rect || !refs.floating.current) return;
14052
14274
  refs.setPositionReference(virtualReference);
@@ -14073,7 +14295,7 @@ var SpacerScale = ({ getReferenceRect }) => {
14073
14295
  }, [getReferenceRect, refs, update, virtualReference]);
14074
14296
  const handleBaseClass = "bg-background shadow-md border rounded-full absolute touch-none select-none pointer-events-auto";
14075
14297
  const getHandleActiveClass = (side) => activeSide === side ? "bg-blue-400 border-blue-300" : "hover:bg-blue-400 hover:border-blue-300";
14076
- return /* @__PURE__ */ jsxs28(
14298
+ return /* @__PURE__ */ jsxs29(
14077
14299
  "div",
14078
14300
  {
14079
14301
  ref: refs.setFloating,
@@ -14085,14 +14307,14 @@ var SpacerScale = ({ getReferenceRect }) => {
14085
14307
  },
14086
14308
  className: "relative pointer-events-none",
14087
14309
  children: [
14088
- (activeSide === null || activeSide === "top") && /* @__PURE__ */ jsx45(
14310
+ (activeSide === null || activeSide === "top") && /* @__PURE__ */ jsx46(
14089
14311
  "div",
14090
14312
  {
14091
14313
  onPointerDown: (e) => handlePointerDown(e, "top"),
14092
14314
  className: `w-[18px] h-[8px] cursor-ns-resize ${handleBaseClass} left-1/2 -translate-x-1/2 -top-[4px] ${getHandleActiveClass("top")}`
14093
14315
  }
14094
14316
  ),
14095
- (activeSide === null || activeSide === "bottom") && /* @__PURE__ */ jsx45(
14317
+ (activeSide === null || activeSide === "bottom") && /* @__PURE__ */ jsx46(
14096
14318
  "div",
14097
14319
  {
14098
14320
  onPointerDown: (e) => handlePointerDown(e, "bottom"),
@@ -14105,19 +14327,19 @@ var SpacerScale = ({ getReferenceRect }) => {
14105
14327
  };
14106
14328
 
14107
14329
  // src/core/editor/components/scaling/column-scale.tsx
14108
- import { useMemo as useMemo16, useEffect as useEffect17, useState as useState13, useRef as useRef9, useCallback as useCallback15 } from "react";
14109
- import { Fragment as Fragment17, jsx as jsx46 } from "react/jsx-runtime";
14330
+ import { useMemo as useMemo17, useEffect as useEffect18, useState as useState14, useRef as useRef10, useCallback as useCallback16 } from "react";
14331
+ import { Fragment as Fragment17, jsx as jsx47 } from "react/jsx-runtime";
14110
14332
  var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14111
- const [activeDivider, setActiveDivider] = useState13(null);
14112
- const [columnRects, setColumnRects] = useState13([]);
14333
+ const [activeDivider, setActiveDivider] = useState14(null);
14334
+ const [columnRects, setColumnRects] = useState14([]);
14113
14335
  const { template, setIsScaling, setFocusIdx, stopTextEditing } = useEditorStore();
14114
- const columnWidths = useMemo16(() => {
14336
+ const columnWidths = useMemo17(() => {
14115
14337
  if (!template) return [];
14116
14338
  const sectionColumn = getValueByIdx(template, sectionColumnIdx);
14117
14339
  return sectionColumn?.data?.value?.columnWidths || [];
14118
14340
  }, [template, sectionColumnIdx]);
14119
- const dragRef = useRef9(null);
14120
- const updateColumnRects = useCallback15(() => {
14341
+ const dragRef = useRef10(null);
14342
+ const updateColumnRects = useCallback16(() => {
14121
14343
  if (!shadowRoot) return;
14122
14344
  const allColumns = shadowRoot.querySelectorAll(".node-type-column");
14123
14345
  const matchingColumns = [];
@@ -14149,7 +14371,7 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14149
14371
  });
14150
14372
  setColumnRects(rects);
14151
14373
  }, [shadowRoot, sectionColumnIdx]);
14152
- useEffect17(() => {
14374
+ useEffect18(() => {
14153
14375
  updateColumnRects();
14154
14376
  let animationId;
14155
14377
  const updateLoop = () => {
@@ -14162,7 +14384,7 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14162
14384
  const parseWidth = (width) => {
14163
14385
  return parseFloat(width.replace("%", ""));
14164
14386
  };
14165
- const handlePointerDown = useCallback15((e, dividerIndex) => {
14387
+ const handlePointerDown = useCallback16((e, dividerIndex) => {
14166
14388
  e.preventDefault();
14167
14389
  e.stopPropagation();
14168
14390
  stopTextEditing();
@@ -14188,7 +14410,7 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14188
14410
  document.addEventListener("pointermove", handlePointerMove);
14189
14411
  document.addEventListener("pointerup", handlePointerUp);
14190
14412
  }, [columnRects, columnWidths, setIsScaling]);
14191
- const handlePointerMove = useCallback15((e) => {
14413
+ const handlePointerMove = useCallback16((e) => {
14192
14414
  if (!dragRef.current) return;
14193
14415
  const { startX, leftColIndex, rightColIndex, startLeftWidth, startRightWidth, sectionWidth, allWidths } = dragRef.current;
14194
14416
  const deltaX = e.clientX - startX;
@@ -14222,14 +14444,14 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14222
14444
  }
14223
14445
  });
14224
14446
  }, [sectionColumnIdx]);
14225
- const handlePointerUp = useCallback15(() => {
14447
+ const handlePointerUp = useCallback16(() => {
14226
14448
  setActiveDivider(null);
14227
14449
  setIsScaling(false);
14228
14450
  dragRef.current = null;
14229
14451
  document.removeEventListener("pointermove", handlePointerMove);
14230
14452
  document.removeEventListener("pointerup", handlePointerUp);
14231
14453
  }, [handlePointerMove, setIsScaling]);
14232
- useEffect17(() => {
14454
+ useEffect18(() => {
14233
14455
  return () => {
14234
14456
  document.removeEventListener("pointermove", handlePointerMove);
14235
14457
  document.removeEventListener("pointerup", handlePointerUp);
@@ -14240,7 +14462,7 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14240
14462
  }
14241
14463
  const handleBaseClass = "bg-background shadow-md border rounded-full touch-none select-none pointer-events-auto";
14242
14464
  const getHandleActiveClass = (index) => activeDivider === index ? "bg-blue-400 border-blue-300" : "hover:bg-blue-400 hover:border-blue-300";
14243
- return /* @__PURE__ */ jsx46(Fragment17, { children: columnRects.slice(0, -1).map((rect, index) => {
14465
+ return /* @__PURE__ */ jsx47(Fragment17, { children: columnRects.slice(0, -1).map((rect, index) => {
14244
14466
  const nextRect = columnRects[index + 1];
14245
14467
  const handleLeft = rect.right;
14246
14468
  const handleTop = Math.min(rect.top, nextRect.top);
@@ -14248,7 +14470,7 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14248
14470
  if (activeDivider !== null && activeDivider !== index) {
14249
14471
  return null;
14250
14472
  }
14251
- return /* @__PURE__ */ jsx46(
14473
+ return /* @__PURE__ */ jsx47(
14252
14474
  "div",
14253
14475
  {
14254
14476
  onPointerDown: (e) => handlePointerDown(e, index),
@@ -14268,9 +14490,9 @@ var ColumnScale = ({ sectionColumnIdx, shadowRoot }) => {
14268
14490
  };
14269
14491
 
14270
14492
  // src/core/editor/hooks/use-undo-redo-keyboard.ts
14271
- import { useEffect as useEffect18 } from "react";
14493
+ import { useEffect as useEffect19 } from "react";
14272
14494
  function useUndoRedoKeyboard() {
14273
- useEffect18(() => {
14495
+ useEffect19(() => {
14274
14496
  const handler = (e) => {
14275
14497
  const isMeta = e.metaKey || e.ctrlKey;
14276
14498
  if (!isMeta || e.key.toLowerCase() !== "z") return;
@@ -14292,9 +14514,9 @@ function useUndoRedoKeyboard() {
14292
14514
 
14293
14515
  // src/components/ui/spinner.tsx
14294
14516
  import { Loader2Icon as Loader2Icon2 } from "lucide-react";
14295
- import { jsx as jsx47 } from "react/jsx-runtime";
14517
+ import { jsx as jsx48 } from "react/jsx-runtime";
14296
14518
  function Spinner({ className, ...props }) {
14297
- return /* @__PURE__ */ jsx47(
14519
+ return /* @__PURE__ */ jsx48(
14298
14520
  Loader2Icon2,
14299
14521
  {
14300
14522
  role: "status",
@@ -14306,10 +14528,10 @@ function Spinner({ className, ...props }) {
14306
14528
  }
14307
14529
 
14308
14530
  // src/core/editor/components/preview.tsx
14309
- import { EyeIcon } from "lucide-react";
14531
+ import { EyeIcon, SendIcon, Monitor, Smartphone } from "lucide-react";
14310
14532
 
14311
14533
  // src/render/useMjmlCompiler.ts
14312
- import { useState as useState14, useCallback as useCallback16 } from "react";
14534
+ import { useState as useState15, useCallback as useCallback17 } from "react";
14313
14535
  async function compileMjml(mjml) {
14314
14536
  console.log("Compiling MJML", mjml);
14315
14537
  const response = await fetch("/api/mrender", {
@@ -14326,14 +14548,101 @@ async function compileMjml(mjml) {
14326
14548
  }
14327
14549
 
14328
14550
  // src/core/editor/components/preview.tsx
14329
- import { useEffect as useEffect19, useState as useState15, useRef as useRef10 } from "react";
14330
- import { jsx as jsx48, jsxs as jsxs29 } from "react/jsx-runtime";
14551
+ import { useEffect as useEffect20, useState as useState16, useRef as useRef11 } from "react";
14552
+
14553
+ // src/validate/helpers.ts
14554
+ var MERGE_FIELD_REGEX2 = /\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g;
14555
+ function extractMergeFields(node) {
14556
+ const fields = [];
14557
+ if (!node || typeof node !== "object") return fields;
14558
+ const content = node?.data?.value?.content;
14559
+ if (typeof content === "string") {
14560
+ let match;
14561
+ MERGE_FIELD_REGEX2.lastIndex = 0;
14562
+ while ((match = MERGE_FIELD_REGEX2.exec(content)) !== null) {
14563
+ fields.push(match[1]);
14564
+ }
14565
+ }
14566
+ if (Array.isArray(node.children)) {
14567
+ for (const child of node.children) {
14568
+ fields.push(...extractMergeFields(child));
14569
+ }
14570
+ }
14571
+ if (Array.isArray(node.content)) {
14572
+ for (const page of node.content) {
14573
+ fields.push(...extractMergeFields(page));
14574
+ }
14575
+ }
14576
+ return fields;
14577
+ }
14578
+ function extractEmptyLinks(node) {
14579
+ const results = [];
14580
+ if (!node || typeof node !== "object") return results;
14581
+ if (node.type === "button" || node.type === "social-item") {
14582
+ const href = node.attributes?.href;
14583
+ if (!href || href.trim() === "") {
14584
+ const label = node.type === "button" ? node.data?.value?.content || "Untitled Button" : node.attributes?.alt || node.data?.value?.socialType || "Social Link";
14585
+ results.push({ type: node.type, label });
14586
+ }
14587
+ }
14588
+ if (Array.isArray(node.children)) {
14589
+ for (const child of node.children) {
14590
+ results.push(...extractEmptyLinks(child));
14591
+ }
14592
+ }
14593
+ if (Array.isArray(node.content)) {
14594
+ for (const page of node.content) {
14595
+ results.push(...extractEmptyLinks(page));
14596
+ }
14597
+ }
14598
+ return results;
14599
+ }
14600
+
14601
+ // src/validate/index.ts
14602
+ var PROPERTY_CARD_TYPES = /* @__PURE__ */ new Set(["property-card", "property-card-single-two", "property-card-triple-item"]);
14603
+ function countPlaceholderPropertyImages(node) {
14604
+ let count = 0;
14605
+ if (!node || typeof node !== "object") return count;
14606
+ if (PROPERTY_CARD_TYPES.has(node.type)) {
14607
+ const imageSrc = node.attributes?.["image-src"];
14608
+ if (!imageSrc || imageSrc === DEFAULT_PROPERTY_PLACEHOLDER_IMAGE) {
14609
+ count++;
14610
+ }
14611
+ }
14612
+ if (Array.isArray(node.children)) {
14613
+ for (const child of node.children) {
14614
+ count += countPlaceholderPropertyImages(child);
14615
+ }
14616
+ }
14617
+ if (Array.isArray(node.content)) {
14618
+ for (const page of node.content) {
14619
+ count += countPlaceholderPropertyImages(page);
14620
+ }
14621
+ }
14622
+ return count;
14623
+ }
14624
+ function validate_editor_onPreview(template, mergeFields) {
14625
+ const usedFields = [...new Set(extractMergeFields(template))];
14626
+ const validValues = new Set(mergeFields.map((f) => f.value));
14627
+ const invalid_merge_fields = usedFields.filter((field) => !validValues.has(field));
14628
+ const missing_links = extractEmptyLinks(template);
14629
+ const placeholder_property_images = countPlaceholderPropertyImages(template);
14630
+ const templateSize = new Blob([JSON.stringify(template)]).size;
14631
+ const is_over_size_limit = templateSize > 50 * 1024;
14632
+ return { invalid_merge_fields, missing_links, is_over_size_limit, placeholder_property_images };
14633
+ }
14634
+
14635
+ // src/core/editor/components/preview.tsx
14636
+ import { jsx as jsx49, jsxs as jsxs30 } from "react/jsx-runtime";
14331
14637
  function Preview() {
14332
- const { template, setPreviewMode, previewMode, isPaidLevel } = useEditorStore();
14333
- const [html, setHtml] = useState15("");
14334
- const [isLoading, setIsLoading] = useState15(false);
14335
- const lastTemplateRef = useRef10("");
14336
- useEffect19(() => {
14638
+ const { template, setPreviewMode, previewMode, isPaidLevel, mergeFields } = useEditorStore();
14639
+ const [html, setHtml] = useState16("");
14640
+ const [isLoading, setIsLoading] = useState16(false);
14641
+ const lastTemplateRef = useRef11("");
14642
+ const [deviceMode, setDeviceMode] = useState16("desktop");
14643
+ const [preview_validations, setPreviewValidations] = useState16({ invalid_merge_fields: [], missing_links: [], is_over_size_limit: false, placeholder_property_images: 0 });
14644
+ const [mjmlErrors, setMjmlErrors] = useState16([]);
14645
+ useEffect20(() => {
14337
14646
  if (typeof window === "undefined" || !previewMode) {
14338
14647
  if (!previewMode) {
14339
14648
  setHtml("");
@@ -14347,56 +14656,165 @@ function Preview() {
14347
14656
  }
14348
14657
  lastTemplateRef.current = templateString;
14349
14658
  setIsLoading(true);
14659
+ const validatePreview = () => {
14660
+ const validations = validate_editor_onPreview(template, mergeFields);
14661
+ setPreviewValidations(validations);
14662
+ };
14350
14663
  const convertMjml = async () => {
14351
14664
  try {
14352
14665
  const mjmlString = json2mjml(template, "production", { isPaidLevel });
14353
14666
  console.log("MJML string:", mjmlString);
14354
14667
  const result = await compileMjml(mjmlString);
14668
+ console.log("MJML errors:", result);
14669
+ setMjmlErrors(result.errors ?? []);
14355
14670
  if (result.errors?.length > 0) {
14356
- console.warn("MJML warnings:", result.errors);
14671
+ console.warn("MJML warnings 1:", result.errors);
14357
14672
  }
14358
14673
  console.log(result.html);
14359
14674
  setHtml(result.html);
14360
14675
  } catch (error) {
14361
14676
  console.error("MJML compilation error:", error);
14677
+ setMjmlErrors([]);
14362
14678
  setHtml('<p style="color: red; padding: 20px;">Error generating preview</p>');
14363
14679
  } finally {
14364
14680
  setIsLoading(false);
14365
14681
  }
14366
14682
  };
14683
+ validatePreview();
14367
14684
  convertMjml();
14368
14685
  }, [template, previewMode]);
14369
- return /* @__PURE__ */ jsxs29(Dialog, { open: previewMode, onOpenChange: setPreviewMode, children: [
14370
- /* @__PURE__ */ jsxs29(Tooltip, { children: [
14371
- /* @__PURE__ */ jsx48(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx48(
14686
+ const hasValidations = preview_validations.invalid_merge_fields.length > 0 || preview_validations.missing_links.length > 0 || preview_validations.is_over_size_limit || preview_validations.placeholder_property_images > 0 || mjmlErrors.length > 0;
14687
+ return /* @__PURE__ */ jsxs30(Dialog, { open: previewMode, onOpenChange: setPreviewMode, children: [
14688
+ /* @__PURE__ */ jsxs30(Tooltip, { children: [
14689
+ /* @__PURE__ */ jsx49(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx49(
14372
14690
  Button,
14373
14691
  {
14374
14692
  variant: "ghost",
14375
14693
  className: "shadow-none transition-none cursor-pointer",
14376
14694
  size: "icon",
14377
14695
  onClick: () => setPreviewMode(true),
14378
- children: /* @__PURE__ */ jsx48(EyeIcon, {})
14696
+ children: /* @__PURE__ */ jsx49(EyeIcon, {})
14379
14697
  }
14380
14698
  ) }),
14381
- /* @__PURE__ */ jsx48(TooltipContent, { side: "bottom", className: "z-51", children: "Preview" })
14699
+ /* @__PURE__ */ jsx49(TooltipContent, { side: "bottom", className: "z-51", children: "Preview" })
14382
14700
  ] }),
14383
- /* @__PURE__ */ jsxs29(DialogContent, { className: "max-w-[1200px] sm:max-w-[1200px]", children: [
14384
- /* @__PURE__ */ jsx48(DialogTitle, { children: "Preview" }),
14385
- /* @__PURE__ */ jsx48("div", { className: "w-full h-full max-h-[600px]", children: isLoading ? /* @__PURE__ */ jsx48("div", { className: "flex items-center justify-center h-[600px]", children: /* @__PURE__ */ jsx48("p", { children: "Generating preview..." }) }) : /* @__PURE__ */ jsx48("iframe", { srcDoc: html, className: "w-full h-[600px]" }) })
14386
- ] })
14701
+ /* @__PURE__ */ jsxs30(
14702
+ DialogContent,
14703
+ {
14704
+ showCloseButton: true,
14705
+ className: "flex flex-col !fixed !top-14 !left-12 !right-12 !bottom-0 !transform-none !translate-x-0 !translate-y-0 !w-auto !h-auto !max-w-none !max-h-none rounded-b-none p-0 gap-0",
14706
+ children: [
14707
+ /* @__PURE__ */ jsx49(DialogHeader, { className: "border-b p-4", children: /* @__PURE__ */ jsx49(DialogTitle, { children: "Preview" }) }),
14708
+ /* @__PURE__ */ jsxs30("div", { className: "flex gap-2 justify-between border-b p-4", children: [
14709
+ /* @__PURE__ */ jsx49("div", { className: "flex gap-2", children: /* @__PURE__ */ jsxs30(Button, { variant: "ghost", onClick: () => {
14710
+ }, children: [
14711
+ /* @__PURE__ */ jsx49(SendIcon, { className: "w-4 h-4" }),
14712
+ "Send a Test Email"
14713
+ ] }) }),
14714
+ /* @__PURE__ */ jsxs30("div", { className: "flex gap-2", children: [
14715
+ /* @__PURE__ */ jsxs30(
14716
+ Button,
14717
+ {
14718
+ variant: deviceMode === "desktop" ? "default" : "ghost",
14719
+ onClick: () => setDeviceMode("desktop"),
14720
+ className: "gap-2 cursor-pointer",
14721
+ children: [
14722
+ /* @__PURE__ */ jsx49(Monitor, { className: "w-4 h-4" }),
14723
+ "Desktop"
14724
+ ]
14725
+ }
14726
+ ),
14727
+ /* @__PURE__ */ jsxs30(
14728
+ Button,
14729
+ {
14730
+ variant: deviceMode === "mobile" ? "default" : "ghost",
14731
+ onClick: () => setDeviceMode("mobile"),
14732
+ className: "gap-2 cursor-pointer",
14733
+ children: [
14734
+ /* @__PURE__ */ jsx49(Smartphone, { className: "w-4 h-4" }),
14735
+ "Mobile"
14736
+ ]
14737
+ }
14738
+ )
14739
+ ] })
14740
+ ] }),
14741
+ /* @__PURE__ */ jsxs30("div", { className: "flex flex-1 overflow-hidden", children: [
14742
+ /* @__PURE__ */ jsx49(
14743
+ "div",
14744
+ {
14745
+ className: "flex-1 flex items-start justify-center overflow-auto w-full",
14746
+ style: { backgroundColor: template?.content?.[0]?.attributes?.["background-color"] || "#965D5D" },
14747
+ children: isLoading ? /* @__PURE__ */ jsx49("div", { className: "flex items-center justify-center h-full w-full", children: /* @__PURE__ */ jsx49("p", { children: "Generating preview..." }) }) : /* @__PURE__ */ jsx49(
14748
+ "div",
14749
+ {
14750
+ className: "flex items-center justify-center bg-white transition-all duration-300 h-full w-full",
14751
+ children: /* @__PURE__ */ jsx49(
14752
+ "iframe",
14753
+ {
14754
+ srcDoc: html,
14755
+ className: "w-full border-0 transition-all duration-200",
14756
+ style: { height: "100%", minHeight: "600px", width: deviceMode === "desktop" ? "100%" : "360px", maxWidth: deviceMode === "desktop" ? "100%" : "360px" },
14757
+ title: "Email Preview",
14758
+ sandbox: "allow-same-origin"
14759
+ }
14760
+ )
14761
+ }
14762
+ )
14763
+ }
14764
+ ),
14765
+ hasValidations && /* @__PURE__ */ jsxs30("div", { className: "w-[300px] border-l p-4 overflow-y-auto flex flex-col gap-4", children: [
14766
+ mjmlErrors.length > 0 && /* @__PURE__ */ jsxs30("div", { className: "w-full rounded-md border border-red-600 p-2", children: [
14767
+ /* @__PURE__ */ jsx49("h3", { className: "text-sm font-semibold text-red-600", children: "MJML Errors" }),
14768
+ /* @__PURE__ */ jsx49("p", { className: "text-sm mt-1 text-red-600", children: "The following errors occurred during email compilation:" }),
14769
+ /* @__PURE__ */ jsx49("ul", { className: "flex flex-col gap-2 my-2", children: mjmlErrors.map((err, i) => /* @__PURE__ */ jsxs30("li", { className: "text-sm font-mono bg-red-100 rounded border border-red-200 text-red-700 p-2", children: [
14770
+ /* @__PURE__ */ jsx49("span", { className: "font-semibold", children: err.tagName }),
14771
+ " (line ",
14772
+ err.line,
14773
+ "): ",
14774
+ err.message
14775
+ ] }, i)) }),
14776
+ /* @__PURE__ */ jsx49("p", { className: "text-xs text-red-500 italic", children: "You may need to contact support to fix these errors. You'll still be able to send the email, but it may not look as expected." })
14777
+ ] }),
14778
+ preview_validations.is_over_size_limit && /* @__PURE__ */ jsxs30("div", { className: "w-full rounded-md border border-red-300 p-2", children: [
14779
+ /* @__PURE__ */ jsx49("h3", { className: "text-sm font-semibold text-red-600", children: "Template Too Large" }),
14780
+ /* @__PURE__ */ jsx49("p", { className: "text-sm mt-1 text-red-600", children: "This template exceeds the size limit. Reduce your content to use this template, otherwise it will be auto-trimmed." })
14781
+ ] }),
14782
+ preview_validations.placeholder_property_images > 0 && /* @__PURE__ */ jsxs30("div", { className: "w-full rounded-md border p-2", children: [
14783
+ /* @__PURE__ */ jsx49("h3", { className: "text-sm font-semibold", children: "Placeholder Property Image" }),
14784
+ /* @__PURE__ */ jsx49("p", { className: "text-sm mt-1", children: preview_validations.placeholder_property_images === 1 ? "1 property card is still using the default placeholder image. Upload an image of the property." : `${preview_validations.placeholder_property_images} property cards are still using the default placeholder image. Upload images for each property.` })
14785
+ ] }),
14786
+ preview_validations.invalid_merge_fields.length > 0 && /* @__PURE__ */ jsxs30("div", { className: "w-full rounded-md border p-2", children: [
14787
+ /* @__PURE__ */ jsx49("h3", { className: "text-sm font-semibold", children: "Invalid Merge Fields" }),
14788
+ /* @__PURE__ */ jsx49("p", { className: "text-sm mt-1", children: "The following merge fields are used in the template but don't exist in your merge field data:" }),
14789
+ /* @__PURE__ */ jsx49("ul", { className: "flex flex-wrap gap-2 mt-2 space-y-1", children: preview_validations.invalid_merge_fields.map((field) => /* @__PURE__ */ jsx49("li", { className: "text-sm font-mono flex items-center justify-center no-wrap whitespace-nowrap bg-background text-nowrap text-ellipsis overflow-hidden rounded border border-border text-black p-2 h-[30px]", children: `{{${field}}}` }, field)) })
14790
+ ] }),
14791
+ preview_validations.missing_links.length > 0 && /* @__PURE__ */ jsxs30("div", { className: "w-full rounded-md border p-2", children: [
14792
+ /* @__PURE__ */ jsx49("h3", { className: "text-sm font-semibold", children: "Missing Links" }),
14793
+ /* @__PURE__ */ jsx49("p", { className: "text-sm mt-1", children: "The following elements have no link set:" }),
14794
+ /* @__PURE__ */ jsx49("ul", { className: "flex flex-wrap gap-2 mt-2", children: preview_validations.missing_links.map((item, i) => /* @__PURE__ */ jsxs30("li", { className: "text-sm w-full font-mono flex items-center justify-start no-wrap whitespace-nowrap bg-background text-nowrap text-ellipsis overflow-hidden rounded border border-border text-black p-2 h-[30px]", children: [
14795
+ item.type === "button" ? "Button" : "Social",
14796
+ ": ",
14797
+ item.label
14798
+ ] }, i)) })
14799
+ ] })
14800
+ ] })
14801
+ ] })
14802
+ ]
14803
+ }
14804
+ )
14387
14805
  ] });
14388
14806
  }
14389
14807
 
14390
14808
  // src/core/editor/components/history.tsx
14391
14809
  import { Redo2Icon, Undo2Icon } from "lucide-react";
14392
- import { Fragment as Fragment18, jsx as jsx49, jsxs as jsxs30 } from "react/jsx-runtime";
14810
+ import { Fragment as Fragment18, jsx as jsx50, jsxs as jsxs31 } from "react/jsx-runtime";
14393
14811
  var History = () => {
14394
14812
  const { undo, redo } = useEditorStore();
14395
14813
  const canUndo = useEditorStore((s) => s.historyIndex > 0);
14396
14814
  const canRedo = useEditorStore((s) => s.historyIndex < s.history.length - 1);
14397
- return /* @__PURE__ */ jsxs30(Fragment18, { children: [
14398
- /* @__PURE__ */ jsxs30(Tooltip, { children: [
14399
- /* @__PURE__ */ jsx49(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx49(
14815
+ return /* @__PURE__ */ jsxs31(Fragment18, { children: [
14816
+ /* @__PURE__ */ jsxs31(Tooltip, { children: [
14817
+ /* @__PURE__ */ jsx50(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx50(
14400
14818
  Button,
14401
14819
  {
14402
14820
  variant: "ghost",
@@ -14404,13 +14822,13 @@ var History = () => {
14404
14822
  size: "icon",
14405
14823
  disabled: !canUndo,
14406
14824
  onClick: undo,
14407
- children: /* @__PURE__ */ jsx49(Undo2Icon, {})
14825
+ children: /* @__PURE__ */ jsx50(Undo2Icon, {})
14408
14826
  }
14409
14827
  ) }),
14410
- /* @__PURE__ */ jsx49(TooltipContent, { side: "bottom", children: "Undo (Ctrl+Z)" })
14828
+ /* @__PURE__ */ jsx50(TooltipContent, { side: "bottom", children: "Undo (Ctrl+Z)" })
14411
14829
  ] }),
14412
- /* @__PURE__ */ jsxs30(Tooltip, { children: [
14413
- /* @__PURE__ */ jsx49(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx49(
14830
+ /* @__PURE__ */ jsxs31(Tooltip, { children: [
14831
+ /* @__PURE__ */ jsx50(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx50(
14414
14832
  Button,
14415
14833
  {
14416
14834
  variant: "ghost",
@@ -14418,16 +14836,16 @@ var History = () => {
14418
14836
  size: "icon",
14419
14837
  disabled: !canRedo,
14420
14838
  onClick: redo,
14421
- children: /* @__PURE__ */ jsx49(Redo2Icon, {})
14839
+ children: /* @__PURE__ */ jsx50(Redo2Icon, {})
14422
14840
  }
14423
14841
  ) }),
14424
- /* @__PURE__ */ jsx49(TooltipContent, { side: "bottom", children: "Redo (Ctrl+Shift+Z)" })
14842
+ /* @__PURE__ */ jsx50(TooltipContent, { side: "bottom", children: "Redo (Ctrl+Shift+Z)" })
14425
14843
  ] })
14426
14844
  ] });
14427
14845
  };
14428
14846
 
14429
14847
  // src/core/index.tsx
14430
- import { jsx as jsx50, jsxs as jsxs31 } from "react/jsx-runtime";
14848
+ import { jsx as jsx51, jsxs as jsxs32 } from "react/jsx-runtime";
14431
14849
  var MAILLOW_EMAIL_EDITOR_VERSION = "0.0.1";
14432
14850
  function getSectionColumnIdx(idx, template) {
14433
14851
  let current = idx;
@@ -14463,6 +14881,20 @@ function getCompanyFooterSection(template) {
14463
14881
  }
14464
14882
  return null;
14465
14883
  }
14884
+ function restoreImagePreview(shadowRoot, targetIdx, originalSrc) {
14885
+ const targetEl = shadowRoot.querySelector(`.node-idx-${CSS.escape(targetIdx)}`);
14886
+ if (!targetEl) return;
14887
+ const bgEl = targetEl.querySelector("td[background], th[background]");
14888
+ if (bgEl) {
14889
+ bgEl.setAttribute("background", originalSrc);
14890
+ bgEl.style.backgroundImage = `url(${originalSrc})`;
14891
+ return;
14892
+ }
14893
+ const img = targetEl.querySelector("img");
14894
+ if (img) {
14895
+ img.src = originalSrc;
14896
+ }
14897
+ }
14466
14898
  function Editor({ setEditorLoading }) {
14467
14899
  useUndoRedoKeyboard();
14468
14900
  const template = useEditorStore((state) => state.template);
@@ -14474,6 +14906,8 @@ function Editor({ setEditorLoading }) {
14474
14906
  const dataTransfer = useEditorStore((state) => state.dataTransfer);
14475
14907
  const textEditing = useEditorStore((state) => state.textEditing);
14476
14908
  const isScaling = useEditorStore((state) => state.isScaling);
14909
+ const canvasBackgroundColor = useEditorStore((s) => s.template?.content?.[0]?.attributes?.["background-color"]) || "#f5f5f5";
14910
+ const renderSyncNeeded = useEditorStore((state) => state.renderSyncNeeded);
14477
14911
  const setFocusIdx = useEditorStore((state) => state.setFocusIdx);
14478
14912
  const setHoverIdx = useEditorStore((state) => state.setHoverIdx);
14479
14913
  const updateElementContent = useEditorStore((state) => state.updateElementContent);
@@ -14491,33 +14925,40 @@ function Editor({ setEditorLoading }) {
14491
14925
  const startTextEditing = useEditorStore((state) => state.startTextEditing);
14492
14926
  const pendingTextEditRequest = useEditorStore((state) => state.pendingTextEditRequest);
14493
14927
  const clearPendingTextEditRequest = useEditorStore((state) => state.clearPendingTextEditRequest);
14494
- const [renderData, setRenderData] = useState16(null);
14495
- const [isEditing, setIsEditing] = useState16(false);
14496
- const [dropIndicator, setDropIndicator] = useState16(null);
14497
- const [dropTargetIdx, setDropTargetIdx] = useState16(null);
14498
- const shadowRootRef = useRef11(null);
14499
- const [hasSelectedElement, setHasSelectedElement] = useState16(false);
14500
- const dragParentIdxRef = useRef11(null);
14501
- const dragPositionIndexRef = useRef11(0);
14502
- const createNewSectionRef = useRef11(false);
14503
- const splitAtParagraphRef = useRef11(null);
14504
- const isHorizontalDropRef = useRef11(false);
14505
- const horizontalDropPositionRef = useRef11(null);
14506
- const isSplitSectionDropRef = useRef11(false);
14507
- const splitSectionAtElementRef = useRef11(null);
14508
- const templateCacheRef = useRef11(null);
14509
- const parentSectionCacheRef = useRef11(/* @__PURE__ */ new Map());
14510
- const sectionElementCacheRef = useRef11(/* @__PURE__ */ new Map());
14511
- const sectionRectCacheRef = useRef11(/* @__PURE__ */ new Map());
14512
- const companyFooterCacheRef = useRef11(void 0);
14513
- const lastSyncedTemplateRef = useRef11(null);
14514
- const prevTextEditingIdxRef = useRef11(null);
14515
- useEffect20(() => {
14928
+ const [renderData, setRenderData] = useState17(null);
14929
+ const [isEditing, setIsEditing] = useState17(false);
14930
+ const [dropIndicator, setDropIndicator] = useState17(null);
14931
+ const [dropTargetIdx, setDropTargetIdx] = useState17(null);
14932
+ const shadowRootRef = useRef12(null);
14933
+ const [hasSelectedElement, setHasSelectedElement] = useState17(false);
14934
+ const dragParentIdxRef = useRef12(null);
14935
+ const dragPositionIndexRef = useRef12(0);
14936
+ const createNewSectionRef = useRef12(false);
14937
+ const splitAtParagraphRef = useRef12(null);
14938
+ const isHorizontalDropRef = useRef12(false);
14939
+ const horizontalDropPositionRef = useRef12(null);
14940
+ const isSplitSectionDropRef = useRef12(false);
14941
+ const splitSectionAtElementRef = useRef12(null);
14942
+ const templateCacheRef = useRef12(null);
14943
+ const parentSectionCacheRef = useRef12(/* @__PURE__ */ new Map());
14944
+ const sectionElementCacheRef = useRef12(/* @__PURE__ */ new Map());
14945
+ const sectionRectCacheRef = useRef12(/* @__PURE__ */ new Map());
14946
+ const companyFooterCacheRef = useRef12(void 0);
14947
+ const lastSyncedTemplateRef = useRef12(null);
14948
+ const prevTextEditingIdxRef = useRef12(null);
14949
+ const lastRenderSyncNeededRef = useRef12(0);
14950
+ const imageReplaceTargetRef = useRef12(null);
14951
+ const imagePreviewOriginalSrcRef = useRef12(null);
14952
+ useEffect21(() => {
14516
14953
  const currentIdx = textEditing?.idx ?? null;
14517
14954
  const prevIdx = prevTextEditingIdxRef.current;
14518
14955
  const switchedTarget = currentIdx !== null && prevIdx !== null && currentIdx !== prevIdx;
14519
14956
  prevTextEditingIdxRef.current = currentIdx;
14520
- if (!isEditing && (!textEditing || switchedTarget)) {
14957
+ const forceSync = renderSyncNeeded > lastRenderSyncNeededRef.current;
14958
+ if (forceSync) {
14959
+ lastRenderSyncNeededRef.current = renderSyncNeeded;
14960
+ }
14961
+ if (forceSync || !isEditing && (!textEditing || switchedTarget)) {
14521
14962
  if (template === lastSyncedTemplateRef.current) {
14522
14963
  return;
14523
14964
  }
@@ -14526,13 +14967,13 @@ function Editor({ setEditorLoading }) {
14526
14967
  }
14527
14968
  lastSyncedTemplateRef.current = template;
14528
14969
  }
14529
- }, [template, renderData, isEditing, textEditing]);
14530
- useEffect20(() => {
14970
+ }, [template, renderData, isEditing, textEditing, renderSyncNeeded]);
14971
+ useEffect21(() => {
14531
14972
  if (renderData && setEditorLoading) {
14532
14973
  setEditorLoading(false);
14533
14974
  }
14534
14975
  }, [renderData, setEditorLoading]);
14535
- useEffect20(() => {
14976
+ useEffect21(() => {
14536
14977
  if (!pendingTextEditRequest || !shadowRootRef.current) return;
14537
14978
  const { idx, cursorPosition } = pendingTextEditRequest;
14538
14979
  const blockNode = shadowRootRef.current.querySelector(`.node-idx-${CSS.escape(idx)}`);
@@ -14581,7 +15022,7 @@ function Editor({ setEditorLoading }) {
14581
15022
  startTextEditing({ idx, getReferenceRect: getReferenceRect2, getShadowElement, initialWidth: blockRect.width, initialHeight: blockRect.height, clickX, clickY, content, styles, cursorPosition });
14582
15023
  clearPendingTextEditRequest();
14583
15024
  }, [pendingTextEditRequest, clearPendingTextEditRequest, startTextEditing]);
14584
- useEffect20(() => {
15025
+ useEffect21(() => {
14585
15026
  if (isDragging && dataTransfer) {
14586
15027
  const currentTemplate = useEditorStore.getState().template;
14587
15028
  templateCacheRef.current = currentTemplate;
@@ -14597,9 +15038,9 @@ function Editor({ setEditorLoading }) {
14597
15038
  sectionRectCacheRef.current.clear();
14598
15039
  }
14599
15040
  }, [isDragging, dataTransfer]);
14600
- const [html, setHtml] = useState16("");
14601
- const lastRenderDataRef = useRef11("");
14602
- useEffect20(() => {
15041
+ const [html, setHtml] = useState17("");
15042
+ const lastRenderDataRef = useRef12("");
15043
+ useEffect21(() => {
14603
15044
  if (typeof window === "undefined" || !renderData) {
14604
15045
  setHtml("");
14605
15046
  lastRenderDataRef.current = "";
@@ -14626,13 +15067,13 @@ function Editor({ setEditorLoading }) {
14626
15067
  };
14627
15068
  convertMjml();
14628
15069
  }, [renderData]);
14629
- const debouncedUpdateContent = useMemo17(
15070
+ const debouncedUpdateContent = useMemo18(
14630
15071
  () => debounce((contentIdx, content) => {
14631
15072
  updateElementContent(contentIdx, content);
14632
15073
  }, 200),
14633
15074
  [updateElementContent]
14634
15075
  );
14635
- const handleElementClick = useCallback17(
15076
+ const handleElementClick = useCallback18(
14636
15077
  (idx) => {
14637
15078
  if (isInsideCompanyFooter(idx, template)) {
14638
15079
  return;
@@ -14645,7 +15086,7 @@ function Editor({ setEditorLoading }) {
14645
15086
  },
14646
15087
  [setFocusIdx, template]
14647
15088
  );
14648
- const handleElementHover = useCallback17(
15089
+ const handleElementHover = useCallback18(
14649
15090
  (idx) => {
14650
15091
  if (!isDragging) {
14651
15092
  if (idx) {
@@ -14659,19 +15100,19 @@ function Editor({ setEditorLoading }) {
14659
15100
  },
14660
15101
  [isDragging, setHoverIdx, template]
14661
15102
  );
14662
- const handleContentInput = useCallback17(
15103
+ const handleContentInput = useCallback18(
14663
15104
  (contentIdx, content) => {
14664
15105
  debouncedUpdateContent(contentIdx, content);
14665
15106
  },
14666
15107
  [debouncedUpdateContent]
14667
15108
  );
14668
- const handleEditingStart = useCallback17(() => {
15109
+ const handleEditingStart = useCallback18(() => {
14669
15110
  setIsEditing(true);
14670
15111
  }, []);
14671
- const handleEditingEnd = useCallback17(() => {
15112
+ const handleEditingEnd = useCallback18(() => {
14672
15113
  setIsEditing(false);
14673
15114
  }, []);
14674
- const handleSlashCommand = useCallback17(
15115
+ const handleSlashCommand = useCallback18(
14675
15116
  (cursorRect) => {
14676
15117
  setSlashCommand({
14677
15118
  isActive: true,
@@ -14686,10 +15127,10 @@ function Editor({ setEditorLoading }) {
14686
15127
  },
14687
15128
  [setSlashCommand]
14688
15129
  );
14689
- const handleSlashCommandClose = useCallback17(() => {
15130
+ const handleSlashCommandClose = useCallback18(() => {
14690
15131
  clearSlashCommand();
14691
15132
  }, [clearSlashCommand]);
14692
- const handleTextEditStart = useCallback17(
15133
+ const handleTextEditStart = useCallback18(
14693
15134
  (idx, initialWidth, initialHeight, clickX, clickY, content, styles) => {
14694
15135
  const getReferenceRect2 = () => {
14695
15136
  if (!shadowRootRef.current) return null;
@@ -14704,11 +15145,11 @@ function Editor({ setEditorLoading }) {
14704
15145
  },
14705
15146
  [startTextEditing]
14706
15147
  );
14707
- const findParentSectionIdx = useCallback17((idx) => {
15148
+ const findParentSectionIdx = useCallback18((idx) => {
14708
15149
  const match = /^(content\.children\.\[\d+\])/.exec(idx);
14709
15150
  return match ? match[1] : null;
14710
15151
  }, []);
14711
- const handleDragOver = useCallback17(
15152
+ const handleDragOver = useCallback18(
14712
15153
  (_e, dragInfo) => {
14713
15154
  const currentDataTransfer = useEditorStore.getState().dataTransfer;
14714
15155
  if (!currentDataTransfer) return;
@@ -14717,6 +15158,11 @@ function Editor({ setEditorLoading }) {
14717
15158
  setDropIndicator(null);
14718
15159
  setDropTargetIdx(null);
14719
15160
  splitAtParagraphRef.current = null;
15161
+ if (imageReplaceTargetRef.current && shadowRootRef.current && imagePreviewOriginalSrcRef.current !== null) {
15162
+ restoreImagePreview(shadowRootRef.current, imageReplaceTargetRef.current, imagePreviewOriginalSrcRef.current);
15163
+ }
15164
+ imageReplaceTargetRef.current = null;
15165
+ imagePreviewOriginalSrcRef.current = null;
14720
15166
  return;
14721
15167
  }
14722
15168
  const template2 = templateCacheRef.current || useEditorStore.getState().template;
@@ -14748,21 +15194,64 @@ function Editor({ setEditorLoading }) {
14748
15194
  }
14749
15195
  }
14750
15196
  if (hoveredType === "column" || hoveredType === "property-card" || hoveredType === "property-card-single-two" || hoveredType === "property-card-triple") {
14751
- const columnIdx = hoveredType === "column" ? idx : getParentIdx(idx);
14752
- if (columnIdx) {
14753
- const columnParentIdx = getParentIdx(columnIdx);
14754
- if (columnParentIdx) {
14755
- const columnParent = getValueByIdx(template2, columnParentIdx);
14756
- if (columnParent?.type === "section-property-km" || columnParent?.type === "section-property-single-two" || columnParent?.type === "section-property-triple") {
14757
- setDropIndicator(null);
14758
- setDropTargetIdx(null);
14759
- splitAtParagraphRef.current = null;
14760
- return;
15197
+ const isImageReplaceDrop = currentDataTransfer.type === "image" && currentDataTransfer.payload?.attributes?.src && (hoveredType === "property-card" || hoveredType === "property-card-single-two");
15198
+ if (!isImageReplaceDrop) {
15199
+ const columnIdx = hoveredType === "column" ? idx : getParentIdx(idx);
15200
+ if (columnIdx) {
15201
+ const columnParentIdx = getParentIdx(columnIdx);
15202
+ if (columnParentIdx) {
15203
+ const columnParent = getValueByIdx(template2, columnParentIdx);
15204
+ if (columnParent?.type === "section-property-km" || columnParent?.type === "section-property-single-two" || columnParent?.type === "section-property-triple") {
15205
+ setDropIndicator(null);
15206
+ setDropTargetIdx(null);
15207
+ splitAtParagraphRef.current = null;
15208
+ return;
15209
+ }
14761
15210
  }
14762
15211
  }
14763
15212
  }
14764
15213
  }
14765
15214
  const dragType = currentDataTransfer.type;
15215
+ const hasImagePayload = currentDataTransfer.payload?.attributes?.src;
15216
+ const PROPERTY_CARD_IMAGE_TYPES = ["property-card", "property-card-single-two", "property-card-triple-item"];
15217
+ const isImageReplaceTarget = hoveredType === "image" || PROPERTY_CARD_IMAGE_TYPES.includes(hoveredType);
15218
+ if (dragType === "image" && hasImagePayload && isImageReplaceTarget) {
15219
+ const newSrc = currentDataTransfer.payload.attributes.src;
15220
+ const prevTarget = imageReplaceTargetRef.current;
15221
+ if (prevTarget !== idx) {
15222
+ if (prevTarget && imagePreviewOriginalSrcRef.current !== null && shadowRootRef.current) {
15223
+ restoreImagePreview(shadowRootRef.current, prevTarget, imagePreviewOriginalSrcRef.current);
15224
+ }
15225
+ if (shadowRootRef.current) {
15226
+ const targetEl = shadowRootRef.current.querySelector(`.node-idx-${CSS.escape(idx)}`);
15227
+ if (targetEl) {
15228
+ const img = targetEl.querySelector("img");
15229
+ if (img && hoveredType === "image") {
15230
+ imagePreviewOriginalSrcRef.current = img.src;
15231
+ img.src = newSrc;
15232
+ } else {
15233
+ const bgEl = targetEl.querySelector("td[background], th[background]");
15234
+ if (bgEl) {
15235
+ imagePreviewOriginalSrcRef.current = bgEl.getAttribute("background") || "";
15236
+ bgEl.setAttribute("background", newSrc);
15237
+ bgEl.style.backgroundImage = `url(${newSrc})`;
15238
+ }
15239
+ }
15240
+ }
15241
+ }
15242
+ imageReplaceTargetRef.current = idx;
15243
+ }
15244
+ setDropIndicator(null);
15245
+ setDropTargetIdx(idx);
15246
+ return;
15247
+ }
15248
+ if (imageReplaceTargetRef.current) {
15249
+ if (shadowRootRef.current && imagePreviewOriginalSrcRef.current !== null) {
15250
+ restoreImagePreview(shadowRootRef.current, imageReplaceTargetRef.current, imagePreviewOriginalSrcRef.current);
15251
+ }
15252
+ imageReplaceTargetRef.current = null;
15253
+ imagePreviewOriginalSrcRef.current = null;
15254
+ }
14766
15255
  const validParents = VALID_PARENT_TYPES[dragType] || [];
14767
15256
  let parentIdx;
14768
15257
  let positionIndex;
@@ -15119,10 +15608,51 @@ function Editor({ setEditorLoading }) {
15119
15608
  [findParentSectionIdx]
15120
15609
  // Only dependency is the helper function
15121
15610
  );
15122
- const handleDrop = useCallback17(
15611
+ const handleDrop = useCallback18(
15123
15612
  (_e, _dragInfo) => {
15124
15613
  const currentDataTransfer = useEditorStore.getState().dataTransfer;
15125
15614
  if (!currentDataTransfer) return;
15615
+ if (imageReplaceTargetRef.current && currentDataTransfer.payload?.attributes?.src) {
15616
+ const targetIdx = imageReplaceTargetRef.current;
15617
+ const newSrc = currentDataTransfer.payload.attributes.src;
15618
+ const template2 = useEditorStore.getState().template;
15619
+ const PROPERTY_CARD_IMAGE_TYPES = ["property-card", "property-card-single-two", "property-card-triple-item"];
15620
+ if (template2) {
15621
+ const targetElement = getValueByIdx(template2, targetIdx);
15622
+ if (targetElement?.type === "image") {
15623
+ useEditorStore.getState().updateElement(targetIdx, {
15624
+ attributes: { ...targetElement.attributes, src: newSrc }
15625
+ });
15626
+ useEditorStore.getState().setFocusIdx(targetIdx);
15627
+ } else if (targetElement && PROPERTY_CARD_IMAGE_TYPES.includes(targetElement.type)) {
15628
+ useEditorStore.getState().updateElement(targetIdx, {
15629
+ attributes: { ...targetElement.attributes, "image-src": newSrc }
15630
+ });
15631
+ useEditorStore.getState().setFocusIdx(targetIdx);
15632
+ }
15633
+ }
15634
+ setDropIndicator(null);
15635
+ setDropTargetIdx(null);
15636
+ setIsDragging(false);
15637
+ setIsDragButtonHovered(false);
15638
+ setDataTransfer(null);
15639
+ setHoverIdx(null);
15640
+ dragParentIdxRef.current = null;
15641
+ dragPositionIndexRef.current = 0;
15642
+ createNewSectionRef.current = false;
15643
+ splitAtParagraphRef.current = null;
15644
+ isHorizontalDropRef.current = false;
15645
+ horizontalDropPositionRef.current = null;
15646
+ isSplitSectionDropRef.current = false;
15647
+ splitSectionAtElementRef.current = null;
15648
+ imageReplaceTargetRef.current = null;
15649
+ imagePreviewOriginalSrcRef.current = null;
15650
+ templateCacheRef.current = null;
15651
+ parentSectionCacheRef.current.clear();
15652
+ sectionElementCacheRef.current.clear();
15653
+ sectionRectCacheRef.current.clear();
15654
+ return;
15655
+ }
15126
15656
  if (isHorizontalDropRef.current && horizontalDropPositionRef.current) {
15127
15657
  const parentIdx2 = dragParentIdxRef.current;
15128
15658
  const dropPosition = horizontalDropPositionRef.current;
@@ -15143,6 +15673,8 @@ function Editor({ setEditorLoading }) {
15143
15673
  horizontalDropPositionRef.current = null;
15144
15674
  isSplitSectionDropRef.current = false;
15145
15675
  splitSectionAtElementRef.current = null;
15676
+ imageReplaceTargetRef.current = null;
15677
+ imagePreviewOriginalSrcRef.current = null;
15146
15678
  templateCacheRef.current = null;
15147
15679
  parentSectionCacheRef.current.clear();
15148
15680
  sectionElementCacheRef.current.clear();
@@ -15203,6 +15735,8 @@ function Editor({ setEditorLoading }) {
15203
15735
  splitAtParagraphRef.current = null;
15204
15736
  isSplitSectionDropRef.current = false;
15205
15737
  splitSectionAtElementRef.current = null;
15738
+ imageReplaceTargetRef.current = null;
15739
+ imagePreviewOriginalSrcRef.current = null;
15206
15740
  templateCacheRef.current = null;
15207
15741
  parentSectionCacheRef.current.clear();
15208
15742
  sectionElementCacheRef.current.clear();
@@ -15258,7 +15792,7 @@ function Editor({ setEditorLoading }) {
15258
15792
  },
15259
15793
  [addElement, addElementInNewSection, moveElement, moveElementToNewSection, splitTextAndInsertElement, splitSectionAndInsertElement, setIsDragging, setIsDragButtonHovered, setDataTransfer, setHoverIdx]
15260
15794
  );
15261
- const handleDragLeave = useCallback17(() => {
15795
+ const handleDragLeave = useCallback18(() => {
15262
15796
  setDropIndicator(null);
15263
15797
  setDropTargetIdx(null);
15264
15798
  dragParentIdxRef.current = null;
@@ -15269,18 +15803,23 @@ function Editor({ setEditorLoading }) {
15269
15803
  horizontalDropPositionRef.current = null;
15270
15804
  isSplitSectionDropRef.current = false;
15271
15805
  splitSectionAtElementRef.current = null;
15806
+ if (imageReplaceTargetRef.current && shadowRootRef.current && imagePreviewOriginalSrcRef.current !== null) {
15807
+ restoreImagePreview(shadowRootRef.current, imageReplaceTargetRef.current, imagePreviewOriginalSrcRef.current);
15808
+ }
15809
+ imageReplaceTargetRef.current = null;
15810
+ imagePreviewOriginalSrcRef.current = null;
15272
15811
  templateCacheRef.current = null;
15273
15812
  parentSectionCacheRef.current.clear();
15274
15813
  sectionElementCacheRef.current.clear();
15275
15814
  sectionRectCacheRef.current.clear();
15276
15815
  }, []);
15277
- const handleShadowRootRef = useCallback17((shadowRoot) => {
15816
+ const handleShadowRootRef = useCallback18((shadowRoot) => {
15278
15817
  shadowRootRef.current = shadowRoot;
15279
15818
  }, []);
15280
- const handleSelectionRectChange = useCallback17((rect) => {
15819
+ const handleSelectionRectChange = useCallback18((rect) => {
15281
15820
  setHasSelectedElement(rect !== null);
15282
15821
  }, []);
15283
- const getReferenceRect = useCallback17(() => {
15822
+ const getReferenceRect = useCallback18(() => {
15284
15823
  if (!shadowRootRef.current || !focusIdx) return null;
15285
15824
  const selectedEl = shadowRootRef.current.querySelector(
15286
15825
  `.node-idx-${CSS.escape(focusIdx)}`
@@ -15308,14 +15847,14 @@ function Editor({ setEditorLoading }) {
15308
15847
  }, [focusIdx]);
15309
15848
  const selectedElement = focusIdx && renderData ? getValueByIdx(renderData, focusIdx) : null;
15310
15849
  const canDragSelectedElement = selectedElement && selectedElement.type !== "column" && !(focusIdx && renderData && isInsideCompanyFooter(focusIdx, renderData));
15311
- const showCompanyFooter = useMemo17(
15850
+ const showCompanyFooter = useMemo18(
15312
15851
  () => template.content[0]?.data?.value?.showCompanyFooter ?? true,
15313
15852
  [template.content[0]?.data?.value?.showCompanyFooter]
15314
15853
  );
15315
15854
  if (!html) {
15316
- return /* @__PURE__ */ jsx50("div", { className: "maillow-editor flex items-center justify-center h-[500px]", children: /* @__PURE__ */ jsx50(Spinner, {}) });
15855
+ return /* @__PURE__ */ jsx51("div", { className: "maillow-editor flex items-center justify-center h-[500px]", children: /* @__PURE__ */ jsx51(Spinner, {}) });
15317
15856
  }
15318
- return /* @__PURE__ */ jsxs31(
15857
+ return /* @__PURE__ */ jsxs32(
15319
15858
  "div",
15320
15859
  {
15321
15860
  className: "maillow-editor relative ",
@@ -15326,48 +15865,51 @@ function Editor({ setEditorLoading }) {
15326
15865
  justifyContent: "center"
15327
15866
  },
15328
15867
  children: [
15329
- /* @__PURE__ */ jsx50(
15868
+ /* @__PURE__ */ jsxs32(
15330
15869
  "div",
15331
15870
  {
15332
- className: `editor-container rounded-b-[12px] border-t-1 border-t-accent max-w-[626px]`,
15871
+ className: `editor-container rounded-b-[12px] max-w-[626px] w-[626px] [@media(max-width:950px)]:max-w-[100%] [@media(max-width:950px)]:w-[100%] `,
15333
15872
  style: {
15334
- width: "626px",
15335
15873
  height: "100%",
15336
- backgroundColor: "#f5f5f5",
15874
+ backgroundColor: canvasBackgroundColor,
15337
15875
  overflow: "auto"
15338
15876
  },
15339
- children: /* @__PURE__ */ jsx50(
15340
- ShadowDomRenderer,
15341
- {
15342
- html,
15343
- focusIdx,
15344
- hoverIdx,
15345
- dropIndicator,
15346
- dropTargetIdx,
15347
- isDragging,
15348
- isDragButtonHovered,
15349
- textEditingIdx: textEditing?.idx || null,
15350
- showCompanyFooter,
15351
- onElementClick: handleElementClick,
15352
- onElementHover: handleElementHover,
15353
- onContentInput: handleContentInput,
15354
- onEditingStart: handleEditingStart,
15355
- onEditingEnd: handleEditingEnd,
15356
- onDragOver: handleDragOver,
15357
- onDrop: handleDrop,
15358
- onDragLeave: handleDragLeave,
15359
- onSelectionRectChange: handleSelectionRectChange,
15360
- onShadowRootRef: handleShadowRootRef,
15361
- onSlashCommand: handleSlashCommand,
15362
- onSlashCommandClose: handleSlashCommandClose,
15363
- onTextEditStart: handleTextEditStart
15364
- }
15365
- )
15877
+ children: [
15878
+ /* @__PURE__ */ jsx51("div", { className: "w-full h-[2px] bg-black opacity-10" }),
15879
+ /* @__PURE__ */ jsx51(
15880
+ ShadowDomRenderer,
15881
+ {
15882
+ html,
15883
+ focusIdx,
15884
+ hoverIdx,
15885
+ dropIndicator,
15886
+ dropTargetIdx,
15887
+ isDragging,
15888
+ isDragButtonHovered,
15889
+ textEditingIdx: textEditing?.idx || null,
15890
+ showCompanyFooter,
15891
+ onElementClick: handleElementClick,
15892
+ onElementHover: handleElementHover,
15893
+ onContentInput: handleContentInput,
15894
+ onEditingStart: handleEditingStart,
15895
+ onEditingEnd: handleEditingEnd,
15896
+ onDragOver: handleDragOver,
15897
+ onDrop: handleDrop,
15898
+ onDragLeave: handleDragLeave,
15899
+ onSelectionRectChange: handleSelectionRectChange,
15900
+ onShadowRootRef: handleShadowRootRef,
15901
+ onSlashCommand: handleSlashCommand,
15902
+ onSlashCommandClose: handleSlashCommandClose,
15903
+ onTextEditStart: handleTextEditStart
15904
+ }
15905
+ )
15906
+ ]
15366
15907
  }
15367
15908
  ),
15368
- /* @__PURE__ */ jsx50(ElementsSuggestions, {}),
15369
- /* @__PURE__ */ jsx50(TiptapOverlay, {}),
15370
- !isDragging && !isScaling && hasSelectedElement && focusIdx && selectedElement?.type && /* @__PURE__ */ jsx50(
15909
+ /* @__PURE__ */ jsx51(ElementsSuggestions, {}),
15910
+ /* @__PURE__ */ jsx51(MergeFieldSuggestions, {}),
15911
+ /* @__PURE__ */ jsx51(TiptapOverlay, {}),
15912
+ !isDragging && !isScaling && hasSelectedElement && focusIdx && selectedElement?.type && /* @__PURE__ */ jsx51(
15371
15913
  ElementFloat,
15372
15914
  {
15373
15915
  getReferenceRect,
@@ -15375,7 +15917,7 @@ function Editor({ setEditorLoading }) {
15375
15917
  elementType: selectedElement.type
15376
15918
  }
15377
15919
  ),
15378
- !isScaling && hasSelectedElement && focusIdx && canDragSelectedElement && !NOT_DRAGGABLE_ELEMENTS.includes(selectedElement.type) && /* @__PURE__ */ jsx50(
15920
+ !isScaling && hasSelectedElement && focusIdx && canDragSelectedElement && !NOT_DRAGGABLE_ELEMENTS.includes(selectedElement.type) && /* @__PURE__ */ jsx51(
15379
15921
  DragButton,
15380
15922
  {
15381
15923
  getReferenceRect,
@@ -15384,17 +15926,17 @@ function Editor({ setEditorLoading }) {
15384
15926
  isDragging
15385
15927
  }
15386
15928
  ),
15387
- !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "divider" && /* @__PURE__ */ jsx50(DividerScale, { getReferenceRect }),
15388
- !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "button" && /* @__PURE__ */ jsx50(ButtonScale, { getReferenceRect }),
15389
- !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "image" && /* @__PURE__ */ jsx50(ImageScale, { getReferenceRect }),
15390
- !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "space" && /* @__PURE__ */ jsx50(SpacerScale, { getReferenceRect }),
15929
+ !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "divider" && /* @__PURE__ */ jsx51(DividerScale, { getReferenceRect }),
15930
+ !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "button" && /* @__PURE__ */ jsx51(ButtonScale, { getReferenceRect }),
15931
+ !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "image" && /* @__PURE__ */ jsx51(ImageScale, { getReferenceRect }),
15932
+ !isDragging && hasSelectedElement && focusIdx && selectedElement?.type === "space" && /* @__PURE__ */ jsx51(SpacerScale, { getReferenceRect }),
15391
15933
  !isDragging && hasSelectedElement && focusIdx && renderData && (() => {
15392
15934
  const sectionColumnIdx = getSectionColumnIdx(focusIdx, renderData);
15393
15935
  if (!sectionColumnIdx) return null;
15394
15936
  const sectionColumn = getValueByIdx(renderData, sectionColumnIdx);
15395
15937
  if (!sectionColumn || sectionColumn.type !== "section-column") return null;
15396
15938
  if (!sectionColumn.children || sectionColumn.children.length < 2) return null;
15397
- return /* @__PURE__ */ jsx50(
15939
+ return /* @__PURE__ */ jsx51(
15398
15940
  ColumnScale,
15399
15941
  {
15400
15942
  sectionColumnIdx,
@@ -15416,9 +15958,7 @@ export {
15416
15958
  parseBorder,
15417
15959
  formatBorder,
15418
15960
  parsePrice,
15419
- json2mjml,
15420
15961
  MAX_TEMPLATE_SIZE,
15421
- useEditorStore,
15422
15962
  BUTTON_ALIGNMENTS,
15423
15963
  ALIGNMENT_ICONS,
15424
15964
  FONTS,
@@ -15436,6 +15976,9 @@ export {
15436
15976
  MIN_LINE_HEIGHT,
15437
15977
  MAX_LINE_HEIGHT,
15438
15978
  LINE_HEIGHT_STEP,
15979
+ DEFAULT_PROPERTY_PLACEHOLDER_IMAGE,
15980
+ json2mjml,
15981
+ useEditorStore,
15439
15982
  setupDragImage,
15440
15983
  getElementDisplayName,
15441
15984
  cn,