@kontakto/email-template-editor 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import DOMPurify from 'dompurify';
2
2
  import { marked, Renderer } from 'marked';
3
- import React60, { createContext, forwardRef, useRef, useEffect, useImperativeHandle, useMemo, useContext, useState, useCallback, Fragment } from 'react';
3
+ import React58, { createContext, forwardRef, useRef, useEffect, useImperativeHandle, useMemo, useContext, useState, useCallback, Fragment } from 'react';
4
4
  import { z } from 'zod';
5
5
  import { renderToStaticMarkup as renderToStaticMarkup$1 } from 'react-dom/server';
6
6
  import { createTheme, alpha, lighten, darken } from '@mui/material/styles';
7
- import { MenuItem, Stack, ThemeProvider, CssBaseline, useTheme, Drawer, Box, Tabs, Tab, Typography, Tooltip, IconButton, TextField, InputAdornment, Chip, CircularProgress, Alert, Divider as Divider$1, ToggleButtonGroup, ToggleButton, Snackbar, Dialog, DialogTitle, DialogContent, DialogActions, Button as Button$1, InputBase, FormControlLabel, Switch, InputLabel, Menu, Slider, ButtonBase, Paper, Fade } from '@mui/material';
7
+ import { MenuItem, Stack, ThemeProvider, CssBaseline, useTheme, Drawer, Box, Tabs, Tab, Typography, Tooltip, IconButton, TextField, InputAdornment, Chip, CircularProgress, Alert, Divider as Divider$1, ToggleButtonGroup, ToggleButton, Snackbar, Dialog, DialogTitle, DialogContent, DialogActions, Button as Button$1, InputBase, AlertTitle, FormControlLabel, Switch, InputLabel, Menu, Slider, ButtonBase, Popper, Paper, Fade } from '@mui/material';
8
8
  import { create } from 'zustand';
9
- import { AddOutlined, SearchOutlined, MonitorOutlined, PhoneIphoneOutlined, LibraryAddOutlined, ContentCopyOutlined, DriveFileRenameOutlineOutlined, FileUploadOutlined, FileDownloadOutlined, DeleteOutlined, EditOutlined, PreviewOutlined, CodeOutlined, SubjectOutlined, DataObjectOutlined, Add, SaveOutlined, LastPageOutlined, AppRegistrationOutlined, DeleteOutline, FirstPageOutlined, MenuOutlined, RoundedCornerOutlined, AspectRatioOutlined, HeightOutlined, VerticalAlignTopOutlined, VerticalAlignCenterOutlined, VerticalAlignBottomOutlined, SpaceBarOutlined, CloseOutlined, AlignVerticalTopOutlined, AlignVerticalBottomOutlined, AlignHorizontalLeftOutlined, AlignHorizontalRightOutlined, FormatAlignLeftOutlined, FormatAlignCenterOutlined, FormatAlignRightOutlined, TextFieldsOutlined, ArrowUpwardOutlined, ArrowDownwardOutlined, HMobiledataOutlined, NotesOutlined, SmartButtonOutlined, ImageOutlined, AccountCircleOutlined, ContactMailOutlined, BusinessOutlined, HorizontalRuleOutlined, Crop32Outlined, HtmlOutlined, ViewColumnOutlined } from '@mui/icons-material';
9
+ import { AddOutlined, SearchOutlined, MonitorOutlined, PhoneIphoneOutlined, LibraryAddOutlined, ContentCopyOutlined, DriveFileRenameOutlineOutlined, FileUploadOutlined, FileDownloadOutlined, DeleteOutlined, EditOutlined, PreviewOutlined, CodeOutlined, SubjectOutlined, DataObjectOutlined, Add, SaveOutlined, LastPageOutlined, AppRegistrationOutlined, CloudUploadOutlined, FirstPageOutlined, MenuOutlined, InputOutlined, DeleteOutline, RoundedCornerOutlined, AspectRatioOutlined, HeightOutlined, CollectionsOutlined, ErrorOutlineOutlined, VerticalAlignTopOutlined, VerticalAlignCenterOutlined, VerticalAlignBottomOutlined, SpaceBarOutlined, CloseOutlined, AlignVerticalTopOutlined, AlignVerticalBottomOutlined, AlignHorizontalLeftOutlined, AlignHorizontalRightOutlined, FormatAlignLeftOutlined, FormatAlignCenterOutlined, FormatAlignRightOutlined, FormatLineSpacingOutlined, TextFieldsOutlined, FormatBoldOutlined, FormatItalicOutlined, LinkOutlined, ArrowUpwardOutlined, ArrowDownwardOutlined, HMobiledataOutlined, NotesOutlined, SmartButtonOutlined, ImageOutlined, AccountCircleOutlined, ContactMailOutlined, BusinessOutlined, HorizontalRuleOutlined, Crop32Outlined, HtmlOutlined, ViewColumnOutlined } from '@mui/icons-material';
10
10
  import { HexColorPicker, HexColorInput } from 'react-colorful';
11
11
  import hljs from 'highlight.js';
12
12
  import jsonHighlighter from 'highlight.js/lib/languages/json';
@@ -156,10 +156,24 @@ function renderMarkdownString(str) {
156
156
  }
157
157
  return sanitizer(html2);
158
158
  }
159
+ function renderInlineMarkdownString(str) {
160
+ const html2 = marked.parseInline(str, {
161
+ async: false,
162
+ breaks: true,
163
+ gfm: true,
164
+ pedantic: false,
165
+ silent: false,
166
+ renderer: new CustomRenderer()
167
+ });
168
+ if (typeof html2 !== "string") {
169
+ throw new Error("marked.parseInline did not return a string");
170
+ }
171
+ return sanitizer(html2);
172
+ }
159
173
  function EmailMarkdown(_a) {
160
174
  var _b = _a, { markdown } = _b, props = __objRest(_b, ["markdown"]);
161
175
  const data = useMemo(() => renderMarkdownString(markdown), [markdown]);
162
- return /* @__PURE__ */ React60.createElement("div", __spreadProps(__spreadValues({}, props), { dangerouslySetInnerHTML: { __html: data } }));
176
+ return /* @__PURE__ */ React58.createElement("div", __spreadProps(__spreadValues({}, props), { dangerouslySetInnerHTML: { __html: data } }));
163
177
  }
164
178
  var FONT_FAMILY_SCHEMA = z.enum([
165
179
  "MODERN_SANS",
@@ -210,6 +224,8 @@ var TextPropsSchema = z.object({
210
224
  fontSize: z.number().gte(0).optional().nullable(),
211
225
  fontFamily: FONT_FAMILY_SCHEMA,
212
226
  fontWeight: z.enum(["bold", "normal"]).optional().nullable(),
227
+ lineHeight: z.number().gte(0).optional().nullable(),
228
+ letterSpacing: z.number().optional().nullable(),
213
229
  textAlign: z.enum(["left", "center", "right"]).optional().nullable(),
214
230
  padding: PADDING_SCHEMA
215
231
  }).optional().nullable(),
@@ -223,21 +239,23 @@ var TextPropsDefaults = {
223
239
  text: ""
224
240
  };
225
241
  function Text({ style, props }) {
226
- var _a, _b, _c, _d, _e, _f;
242
+ var _a, _b, _c, _d, _e, _f, _g;
227
243
  const wStyle = {
228
244
  color: (_a = style == null ? void 0 : style.color) != null ? _a : void 0,
229
245
  backgroundColor: (_b = style == null ? void 0 : style.backgroundColor) != null ? _b : void 0,
230
246
  fontSize: (_c = style == null ? void 0 : style.fontSize) != null ? _c : void 0,
231
247
  fontFamily: getFontFamily(style == null ? void 0 : style.fontFamily),
232
248
  fontWeight: (_d = style == null ? void 0 : style.fontWeight) != null ? _d : void 0,
233
- textAlign: (_e = style == null ? void 0 : style.textAlign) != null ? _e : void 0,
249
+ lineHeight: (_e = style == null ? void 0 : style.lineHeight) != null ? _e : void 0,
250
+ letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
251
+ textAlign: (_f = style == null ? void 0 : style.textAlign) != null ? _f : void 0,
234
252
  padding: getPadding(style == null ? void 0 : style.padding)
235
253
  };
236
- const text = (_f = props == null ? void 0 : props.text) != null ? _f : TextPropsDefaults.text;
254
+ const text = (_g = props == null ? void 0 : props.text) != null ? _g : TextPropsDefaults.text;
237
255
  if (props == null ? void 0 : props.markdown) {
238
- return /* @__PURE__ */ React60.createElement(EmailMarkdown, { style: wStyle, markdown: text });
256
+ return /* @__PURE__ */ React58.createElement(EmailMarkdown, { style: wStyle, markdown: text });
239
257
  }
240
- return /* @__PURE__ */ React60.createElement("div", { style: wStyle }, text);
258
+ return /* @__PURE__ */ React58.createElement("div", { style: wStyle }, text);
241
259
  }
242
260
  var PADDING_SCHEMA2 = z.object({
243
261
  top: z.number(),
@@ -286,7 +304,7 @@ function Avatar({ style, props }) {
286
304
  textAlign: (_e = style == null ? void 0 : style.textAlign) != null ? _e : void 0,
287
305
  padding: getPadding2(style == null ? void 0 : style.padding)
288
306
  };
289
- return /* @__PURE__ */ React60.createElement("div", { style: sectionStyle }, /* @__PURE__ */ React60.createElement(
307
+ return /* @__PURE__ */ React58.createElement("div", { style: sectionStyle }, /* @__PURE__ */ React58.createElement(
290
308
  "img",
291
309
  {
292
310
  alt,
@@ -358,6 +376,8 @@ var ButtonPropsSchema = z.object({
358
376
  fontSize: z.number().min(0).optional().nullable(),
359
377
  fontFamily: FONT_FAMILY_SCHEMA2,
360
378
  fontWeight: z.enum(["bold", "normal"]).optional().nullable(),
379
+ lineHeight: z.number().gte(0).optional().nullable(),
380
+ letterSpacing: z.number().optional().nullable(),
361
381
  textAlign: z.enum(["left", "center", "right"]).optional().nullable(),
362
382
  padding: PADDING_SCHEMA3
363
383
  }).optional().nullable(),
@@ -410,7 +430,7 @@ var ButtonPropsDefaults = {
410
430
  buttonBackgroundColor: "#999999"
411
431
  };
412
432
  function Button({ style, props }) {
413
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
433
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
414
434
  const text = (_a = props == null ? void 0 : props.text) != null ? _a : ButtonPropsDefaults.text;
415
435
  const url = (_b = props == null ? void 0 : props.url) != null ? _b : ButtonPropsDefaults.url;
416
436
  const fullWidth = (_c = props == null ? void 0 : props.fullWidth) != null ? _c : ButtonPropsDefaults.fullWidth;
@@ -428,20 +448,22 @@ function Button({ style, props }) {
428
448
  fontSize: (_h = style == null ? void 0 : style.fontSize) != null ? _h : 16,
429
449
  fontFamily: getFontFamily2(style == null ? void 0 : style.fontFamily),
430
450
  fontWeight: (_i = style == null ? void 0 : style.fontWeight) != null ? _i : "bold",
451
+ lineHeight: (_j = style == null ? void 0 : style.lineHeight) != null ? _j : void 0,
452
+ letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
431
453
  backgroundColor: buttonBackgroundColor,
432
454
  borderRadius: getRoundedCorners(props),
433
455
  display: fullWidth ? "block" : "inline-block",
434
456
  padding: `${padding[0]}px ${padding[1]}px`,
435
457
  textDecoration: "none"
436
458
  };
437
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React60.createElement("a", { href: url, style: linkStyle, target: "_blank" }, /* @__PURE__ */ React60.createElement(
459
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React58.createElement("a", { href: url, style: linkStyle, target: "_blank" }, /* @__PURE__ */ React58.createElement(
438
460
  "span",
439
461
  {
440
462
  dangerouslySetInnerHTML: {
441
463
  __html: `<!--[if mso]><i style="letter-spacing: ${padding[1]}px;mso-font-width:-100%;mso-text-raise:${textRaise}" hidden>&nbsp;</i><![endif]-->`
442
464
  }
443
465
  }
444
- ), /* @__PURE__ */ React60.createElement("span", null, text), /* @__PURE__ */ React60.createElement(
466
+ ), /* @__PURE__ */ React58.createElement("span", null, text), /* @__PURE__ */ React58.createElement(
445
467
  "span",
446
468
  {
447
469
  dangerouslySetInnerHTML: {
@@ -490,7 +512,7 @@ function ColumnsContainer({ style, columns, props }) {
490
512
  contentAlignment: (_d = props == null ? void 0 : props.contentAlignment) != null ? _d : ColumnsContainerPropsDefaults.contentAlignment,
491
513
  fixedWidths: props == null ? void 0 : props.fixedWidths
492
514
  };
493
- return /* @__PURE__ */ React60.createElement("div", { style: wStyle }, /* @__PURE__ */ React60.createElement(
515
+ return /* @__PURE__ */ React58.createElement("div", { style: wStyle }, /* @__PURE__ */ React58.createElement(
494
516
  "table",
495
517
  {
496
518
  align: "center",
@@ -499,7 +521,7 @@ function ColumnsContainer({ style, columns, props }) {
499
521
  border: 0,
500
522
  style: { tableLayout: "fixed", borderCollapse: "collapse" }
501
523
  },
502
- /* @__PURE__ */ React60.createElement("tbody", { style: { width: "100%" } }, /* @__PURE__ */ React60.createElement("tr", { style: { width: "100%" } }, /* @__PURE__ */ React60.createElement(TableCell, { index: 0, props: blockProps, columns }), /* @__PURE__ */ React60.createElement(TableCell, { index: 1, props: blockProps, columns }), /* @__PURE__ */ React60.createElement(TableCell, { index: 2, props: blockProps, columns })))
524
+ /* @__PURE__ */ React58.createElement("tbody", { style: { width: "100%" } }, /* @__PURE__ */ React58.createElement("tr", { style: { width: "100%" } }, /* @__PURE__ */ React58.createElement(TableCell, { index: 0, props: blockProps, columns }), /* @__PURE__ */ React58.createElement(TableCell, { index: 1, props: blockProps, columns }), /* @__PURE__ */ React58.createElement(TableCell, { index: 2, props: blockProps, columns })))
503
525
  ));
504
526
  }
505
527
  function TableCell({ index, props, columns }) {
@@ -517,7 +539,7 @@ function TableCell({ index, props, columns }) {
517
539
  width: (_d = (_c = props.fixedWidths) == null ? void 0 : _c[index]) != null ? _d : void 0
518
540
  };
519
541
  const children = (_e = columns && columns[index]) != null ? _e : null;
520
- return /* @__PURE__ */ React60.createElement("td", { style }, children);
542
+ return /* @__PURE__ */ React58.createElement("td", { style }, children);
521
543
  }
522
544
  function getPaddingBefore(index, { columnsGap, columnsCount }) {
523
545
  if (index === 0) {
@@ -579,9 +601,9 @@ function Container({ style, children }) {
579
601
  padding: getPadding5(style == null ? void 0 : style.padding)
580
602
  };
581
603
  if (!children) {
582
- return /* @__PURE__ */ React60.createElement("div", { style: wStyle });
604
+ return /* @__PURE__ */ React58.createElement("div", { style: wStyle });
583
605
  }
584
- return /* @__PURE__ */ React60.createElement("div", { style: wStyle }, children);
606
+ return /* @__PURE__ */ React58.createElement("div", { style: wStyle }, children);
585
607
  }
586
608
  var container_default = Container;
587
609
  var COLOR_SCHEMA5 = z.string().regex(/^#[0-9a-fA-F]{6}$/).nullable().optional();
@@ -615,7 +637,7 @@ function Divider({ style, props }) {
615
637
  };
616
638
  const borderTopWidth = (_b = props == null ? void 0 : props.lineHeight) != null ? _b : DividerPropsDefaults.lineHeight;
617
639
  const borderTopColor = (_c = props == null ? void 0 : props.lineColor) != null ? _c : DividerPropsDefaults.lineColor;
618
- return /* @__PURE__ */ React60.createElement("div", { style: st }, /* @__PURE__ */ React60.createElement(
640
+ return /* @__PURE__ */ React58.createElement("div", { style: st }, /* @__PURE__ */ React58.createElement(
619
641
  "hr",
620
642
  {
621
643
  style: {
@@ -673,13 +695,16 @@ function getFontFamily3(fontFamily) {
673
695
  var HeadingPropsSchema = z.object({
674
696
  props: z.object({
675
697
  text: z.string().optional().nullable(),
676
- level: z.enum(["h1", "h2", "h3"]).optional().nullable()
698
+ level: z.enum(["h1", "h2", "h3"]).optional().nullable(),
699
+ markdown: z.boolean().optional().nullable()
677
700
  }).optional().nullable(),
678
701
  style: z.object({
679
702
  color: COLOR_SCHEMA6,
680
703
  backgroundColor: COLOR_SCHEMA6,
681
704
  fontFamily: FONT_FAMILY_SCHEMA3,
682
705
  fontWeight: z.enum(["bold", "normal"]).optional().nullable(),
706
+ lineHeight: z.number().gte(0).optional().nullable(),
707
+ letterSpacing: z.number().optional().nullable(),
683
708
  textAlign: z.enum(["left", "center", "right"]).optional().nullable(),
684
709
  padding: PADDING_SCHEMA7
685
710
  }).optional().nullable()
@@ -690,26 +715,31 @@ var HeadingPropsDefaults = {
690
715
  text: ""
691
716
  };
692
717
  function Heading({ props, style }) {
693
- var _a, _b, _c, _d, _e, _f;
718
+ var _a, _b, _c, _d, _e, _f, _g, _h;
694
719
  const level = (_a = props == null ? void 0 : props.level) != null ? _a : HeadingPropsDefaults.level;
695
720
  const text = (_b = props == null ? void 0 : props.text) != null ? _b : HeadingPropsDefaults.text;
721
+ const isMarkdown = (_c = props == null ? void 0 : props.markdown) != null ? _c : false;
696
722
  const hStyle = {
697
- color: (_c = style == null ? void 0 : style.color) != null ? _c : void 0,
698
- backgroundColor: (_d = style == null ? void 0 : style.backgroundColor) != null ? _d : void 0,
699
- fontWeight: (_e = style == null ? void 0 : style.fontWeight) != null ? _e : "bold",
700
- textAlign: (_f = style == null ? void 0 : style.textAlign) != null ? _f : void 0,
723
+ color: (_d = style == null ? void 0 : style.color) != null ? _d : void 0,
724
+ backgroundColor: (_e = style == null ? void 0 : style.backgroundColor) != null ? _e : void 0,
725
+ fontWeight: (_f = style == null ? void 0 : style.fontWeight) != null ? _f : "bold",
726
+ lineHeight: (_g = style == null ? void 0 : style.lineHeight) != null ? _g : void 0,
727
+ letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
728
+ textAlign: (_h = style == null ? void 0 : style.textAlign) != null ? _h : void 0,
701
729
  margin: 0,
702
730
  fontFamily: getFontFamily3(style == null ? void 0 : style.fontFamily),
703
731
  fontSize: getFontSize(level),
704
732
  padding: getPadding7(style == null ? void 0 : style.padding)
705
733
  };
734
+ const html2 = useMemo(() => isMarkdown ? renderInlineMarkdownString(text) : null, [isMarkdown, text]);
735
+ const renderProps = isMarkdown ? { style: hStyle, dangerouslySetInnerHTML: { __html: html2 != null ? html2 : "" } } : { style: hStyle, children: text };
706
736
  switch (level) {
707
737
  case "h1":
708
- return /* @__PURE__ */ React60.createElement("h1", { style: hStyle }, text);
738
+ return /* @__PURE__ */ React58.createElement("h1", __spreadValues({}, renderProps));
709
739
  case "h2":
710
- return /* @__PURE__ */ React60.createElement("h2", { style: hStyle }, text);
740
+ return /* @__PURE__ */ React58.createElement("h2", __spreadValues({}, renderProps));
711
741
  case "h3":
712
- return /* @__PURE__ */ React60.createElement("h3", { style: hStyle }, text);
742
+ return /* @__PURE__ */ React58.createElement("h3", __spreadValues({}, renderProps));
713
743
  }
714
744
  }
715
745
  function getFontSize(level) {
@@ -791,9 +821,9 @@ function Html({ style, props }) {
791
821
  padding: getPadding8(style == null ? void 0 : style.padding)
792
822
  };
793
823
  if (!children) {
794
- return /* @__PURE__ */ React60.createElement("div", { style: cssStyle });
824
+ return /* @__PURE__ */ React58.createElement("div", { style: cssStyle });
795
825
  }
796
- return /* @__PURE__ */ React60.createElement("div", { style: cssStyle, dangerouslySetInnerHTML: { __html: children } });
826
+ return /* @__PURE__ */ React58.createElement("div", { style: cssStyle, dangerouslySetInnerHTML: { __html: children } });
797
827
  }
798
828
  var html_default = Html;
799
829
  var PADDING_SCHEMA9 = z.object({
@@ -829,7 +859,7 @@ function Image({ style, props }) {
829
859
  const linkHref = (_c = props == null ? void 0 : props.linkHref) != null ? _c : null;
830
860
  const width = (_d = props == null ? void 0 : props.width) != null ? _d : void 0;
831
861
  const height = (_e = props == null ? void 0 : props.height) != null ? _e : void 0;
832
- const imageElement = /* @__PURE__ */ React60.createElement(
862
+ const imageElement = /* @__PURE__ */ React58.createElement(
833
863
  "img",
834
864
  {
835
865
  alt: (_f = props == null ? void 0 : props.alt) != null ? _f : "",
@@ -849,9 +879,9 @@ function Image({ style, props }) {
849
879
  }
850
880
  );
851
881
  if (!linkHref) {
852
- return /* @__PURE__ */ React60.createElement("div", { style: sectionStyle }, imageElement);
882
+ return /* @__PURE__ */ React58.createElement("div", { style: sectionStyle }, imageElement);
853
883
  }
854
- return /* @__PURE__ */ React60.createElement("div", { style: sectionStyle }, /* @__PURE__ */ React60.createElement("a", { href: linkHref, style: { textDecoration: "none" }, target: "_blank" }, imageElement));
884
+ return /* @__PURE__ */ React58.createElement("div", { style: sectionStyle }, /* @__PURE__ */ React58.createElement("a", { href: linkHref, style: { textDecoration: "none" }, target: "_blank" }, imageElement));
855
885
  }
856
886
  var image_default = Image;
857
887
  var FONT_FAMILY_SCHEMA5 = z.enum([
@@ -997,7 +1027,7 @@ function Signature({ style, props }) {
997
1027
  color: linkColor,
998
1028
  textDecoration: "none"
999
1029
  };
1000
- const imageElement = imageUrl ? /* @__PURE__ */ React60.createElement(
1030
+ const imageElement = imageUrl ? /* @__PURE__ */ React58.createElement(
1001
1031
  "img",
1002
1032
  {
1003
1033
  src: imageUrl,
@@ -1016,18 +1046,18 @@ function Signature({ style, props }) {
1016
1046
  }
1017
1047
  ) : null;
1018
1048
  const contactParts = [];
1019
- if (email) contactParts.push(/* @__PURE__ */ React60.createElement("a", { key: "email", href: `mailto:${email}`, style: linkStyle }, email));
1020
- if (phone) contactParts.push(/* @__PURE__ */ React60.createElement("a", { key: "phone", href: `tel:${phone}`, style: linkStyle }, phone));
1049
+ if (email) contactParts.push(/* @__PURE__ */ React58.createElement("a", { key: "email", href: `mailto:${email}`, style: linkStyle }, email));
1050
+ if (phone) contactParts.push(/* @__PURE__ */ React58.createElement("a", { key: "phone", href: `tel:${phone}`, style: linkStyle }, phone));
1021
1051
  if (website) {
1022
1052
  const href = website.startsWith("http") ? website : `https://${website}`;
1023
- contactParts.push(/* @__PURE__ */ React60.createElement("a", { key: "website", href, style: linkStyle, target: "_blank" }, website));
1053
+ contactParts.push(/* @__PURE__ */ React58.createElement("a", { key: "website", href, style: linkStyle, target: "_blank" }, website));
1024
1054
  }
1025
- const textContent = /* @__PURE__ */ React60.createElement("div", null, name && /* @__PURE__ */ React60.createElement("p", { style: nameStyle }, name), title && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, title), company && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, company), address && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, address), contactParts.length > 0 && /* @__PURE__ */ React60.createElement("p", { style: __spreadProps(__spreadValues({}, detailStyle), { marginTop: 4 }) }, contactParts.map((part, i) => /* @__PURE__ */ React60.createElement(React60.Fragment, { key: i }, i > 0 && /* @__PURE__ */ React60.createElement("span", { style: detailStyle }, " \xB7 "), part))));
1026
- const greetingElement = greeting ? /* @__PURE__ */ React60.createElement("p", { style: greetingStyle }, greeting) : null;
1055
+ const textContent = /* @__PURE__ */ React58.createElement("div", null, name && /* @__PURE__ */ React58.createElement("p", { style: nameStyle }, name), title && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, title), company && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, company), address && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, address), contactParts.length > 0 && /* @__PURE__ */ React58.createElement("p", { style: __spreadProps(__spreadValues({}, detailStyle), { marginTop: 4 }) }, contactParts.map((part, i) => /* @__PURE__ */ React58.createElement(React58.Fragment, { key: i }, i > 0 && /* @__PURE__ */ React58.createElement("span", { style: detailStyle }, " \xB7 "), part))));
1056
+ const greetingElement = greeting ? /* @__PURE__ */ React58.createElement("p", { style: greetingStyle }, greeting) : null;
1027
1057
  if (layout === "vertical") {
1028
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, greetingElement, imageElement && /* @__PURE__ */ React60.createElement("div", { style: { marginBottom: 12 } }, imageElement), textContent);
1058
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, greetingElement, imageElement && /* @__PURE__ */ React58.createElement("div", { style: { marginBottom: 12 } }, imageElement), textContent);
1029
1059
  }
1030
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, greetingElement, /* @__PURE__ */ React60.createElement("table", { cellPadding: "0", cellSpacing: "0", border: 0, role: "presentation" }, /* @__PURE__ */ React60.createElement("tbody", null, /* @__PURE__ */ React60.createElement("tr", null, imageElement && /* @__PURE__ */ React60.createElement("td", { style: { verticalAlign: "middle", paddingRight: 16 } }, imageElement), /* @__PURE__ */ React60.createElement("td", { style: { verticalAlign: "middle" } }, textContent)))));
1060
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, greetingElement, /* @__PURE__ */ React58.createElement("table", { cellPadding: "0", cellSpacing: "0", border: 0, role: "presentation" }, /* @__PURE__ */ React58.createElement("tbody", null, /* @__PURE__ */ React58.createElement("tr", null, imageElement && /* @__PURE__ */ React58.createElement("td", { style: { verticalAlign: "middle", paddingRight: 16 } }, imageElement), /* @__PURE__ */ React58.createElement("td", { style: { verticalAlign: "middle" } }, textContent)))));
1031
1061
  }
1032
1062
  var signature_default = Signature;
1033
1063
  var SpacerPropsSchema = z.object({
@@ -1044,13 +1074,13 @@ function Spacer({ props }) {
1044
1074
  const style = {
1045
1075
  height: (_a = props == null ? void 0 : props.height) != null ? _a : SpacerPropsDefaults.height
1046
1076
  };
1047
- return /* @__PURE__ */ React60.createElement("div", { style });
1077
+ return /* @__PURE__ */ React58.createElement("div", { style });
1048
1078
  }
1049
1079
  var spacer_default = Spacer;
1050
1080
  function buildBlockComponent(blocks) {
1051
1081
  return function BlockComponent({ type, data }) {
1052
1082
  const Component = blocks[type].Component;
1053
- return /* @__PURE__ */ React60.createElement(Component, __spreadValues({}, data));
1083
+ return /* @__PURE__ */ React58.createElement(Component, __spreadValues({}, data));
1054
1084
  };
1055
1085
  }
1056
1086
  function buildBlockConfigurationSchema(blocks) {
@@ -1087,9 +1117,9 @@ function ColumnsContainerReader({ style, props }) {
1087
1117
  const _a = props != null ? props : {}, { columns } = _a, restProps = __objRest(_a, ["columns"]);
1088
1118
  let cols = void 0;
1089
1119
  if (columns) {
1090
- cols = columns.map((col) => col.childrenIds.map((childId) => /* @__PURE__ */ React60.createElement(ReaderBlock, { key: childId, id: childId })));
1120
+ cols = columns.map((col) => col.childrenIds.map((childId) => /* @__PURE__ */ React58.createElement(ReaderBlock, { key: childId, id: childId })));
1091
1121
  }
1092
- return /* @__PURE__ */ React60.createElement(columns_container_default, { props: restProps, columns: cols, style });
1122
+ return /* @__PURE__ */ React58.createElement(columns_container_default, { props: restProps, columns: cols, style });
1093
1123
  }
1094
1124
  var ContainerPropsSchema2 = z.object({
1095
1125
  style: ContainerPropsSchema.shape.style,
@@ -1100,7 +1130,7 @@ var ContainerPropsSchema2 = z.object({
1100
1130
  function ContainerReader({ style, props }) {
1101
1131
  var _a;
1102
1132
  const childrenIds = (_a = props == null ? void 0 : props.childrenIds) != null ? _a : [];
1103
- return /* @__PURE__ */ React60.createElement(container_default, { style }, childrenIds.map((childId) => /* @__PURE__ */ React60.createElement(ReaderBlock, { key: childId, id: childId })));
1133
+ return /* @__PURE__ */ React58.createElement(container_default, { style }, childrenIds.map((childId) => /* @__PURE__ */ React58.createElement(ReaderBlock, { key: childId, id: childId })));
1104
1134
  }
1105
1135
  var COLOR_SCHEMA9 = z.string().regex(/^#[0-9a-fA-F]{6}$/).nullable().optional();
1106
1136
  var FONT_FAMILY_SCHEMA6 = z.enum([
@@ -1116,7 +1146,8 @@ var FONT_FAMILY_SCHEMA6 = z.enum([
1116
1146
  ]).nullable().optional();
1117
1147
  var TemplateVariableSchema = z.object({
1118
1148
  name: z.string(),
1119
- description: z.string().optional().nullable()
1149
+ description: z.string().optional().nullable(),
1150
+ sampleValue: z.string().optional().nullable()
1120
1151
  });
1121
1152
  var EmailLayoutPropsSchema = z.object({
1122
1153
  backdropColor: COLOR_SCHEMA9,
@@ -1172,9 +1203,9 @@ function EmailLayoutReader(props) {
1172
1203
  margin: "0"
1173
1204
  };
1174
1205
  if (props.backdropDisabled) {
1175
- return /* @__PURE__ */ React60.createElement("div", { style: baseStyle }, childrenIds.map((childId) => /* @__PURE__ */ React60.createElement(ReaderBlock, { key: childId, id: childId })));
1206
+ return /* @__PURE__ */ React58.createElement("div", { style: baseStyle }, childrenIds.map((childId) => /* @__PURE__ */ React58.createElement(ReaderBlock, { key: childId, id: childId })));
1176
1207
  }
1177
- return /* @__PURE__ */ React60.createElement(
1208
+ return /* @__PURE__ */ React58.createElement(
1178
1209
  "div",
1179
1210
  {
1180
1211
  style: __spreadProps(__spreadValues({}, baseStyle), {
@@ -1184,7 +1215,7 @@ function EmailLayoutReader(props) {
1184
1215
  width: "100%"
1185
1216
  })
1186
1217
  },
1187
- /* @__PURE__ */ React60.createElement(
1218
+ /* @__PURE__ */ React58.createElement(
1188
1219
  "table",
1189
1220
  {
1190
1221
  align: "center",
@@ -1202,7 +1233,7 @@ function EmailLayoutReader(props) {
1202
1233
  cellPadding: "0",
1203
1234
  border: 0
1204
1235
  },
1205
- /* @__PURE__ */ React60.createElement("tbody", null, /* @__PURE__ */ React60.createElement("tr", { style: { width: "100%" } }, /* @__PURE__ */ React60.createElement("td", null, childrenIds.map((childId) => /* @__PURE__ */ React60.createElement(ReaderBlock, { key: childId, id: childId })))))
1236
+ /* @__PURE__ */ React58.createElement("tbody", null, /* @__PURE__ */ React58.createElement("tr", { style: { width: "100%" } }, /* @__PURE__ */ React58.createElement("td", null, childrenIds.map((childId) => /* @__PURE__ */ React58.createElement(ReaderBlock, { key: childId, id: childId })))))
1206
1237
  )
1207
1238
  );
1208
1239
  }
@@ -1214,7 +1245,7 @@ function useReaderDocument() {
1214
1245
  }
1215
1246
  function ReaderBlock({ id }) {
1216
1247
  const document2 = useReaderDocument();
1217
- return document2[id] ? /* @__PURE__ */ React60.createElement(BaseReaderBlock, __spreadValues({}, document2[id])) : null;
1248
+ return document2[id] ? /* @__PURE__ */ React58.createElement(BaseReaderBlock, __spreadValues({}, document2[id])) : null;
1218
1249
  }
1219
1250
  var READER_DICTIONARY = buildBlockConfigurationDictionary({
1220
1251
  ColumnsContainer: {
@@ -1271,13 +1302,13 @@ var ReaderBlockSchema = buildBlockConfigurationSchema(READER_DICTIONARY);
1271
1302
  var ReaderDocumentSchema = z.record(z.string(), ReaderBlockSchema);
1272
1303
  var BaseReaderBlock = buildBlockComponent(READER_DICTIONARY);
1273
1304
  function Reader({ document: document2, rootBlockId }) {
1274
- return /* @__PURE__ */ React60.createElement(ReaderContext.Provider, { value: document2 }, /* @__PURE__ */ React60.createElement(ReaderBlock, { id: rootBlockId }));
1305
+ return /* @__PURE__ */ React58.createElement(ReaderContext.Provider, { value: document2 }, /* @__PURE__ */ React58.createElement(ReaderBlock, { id: rootBlockId }));
1275
1306
  }
1276
1307
 
1277
1308
  // src/email-builder/renderers/render-to-static-markup.tsx
1278
1309
  function renderToStaticMarkup(document2, { rootBlockId }) {
1279
1310
  return "<!DOCTYPE html>" + renderToStaticMarkup$1(
1280
- /* @__PURE__ */ React60.createElement("html", null, /* @__PURE__ */ React60.createElement("body", null, /* @__PURE__ */ React60.createElement(Reader, { document: document2, rootBlockId })))
1311
+ /* @__PURE__ */ React58.createElement("html", null, /* @__PURE__ */ React58.createElement("body", null, /* @__PURE__ */ React58.createElement(Reader, { document: document2, rootBlockId })))
1281
1312
  );
1282
1313
  }
1283
1314
 
@@ -1945,7 +1976,8 @@ var editorStateStore = create(() => ({
1945
1976
  selectedScreenSize: "desktop",
1946
1977
  inspectorDrawerOpen: true,
1947
1978
  samplesDrawerOpen: true,
1948
- persistenceEnabled: false
1979
+ persistenceEnabled: false,
1980
+ lastFocusedEditable: null
1949
1981
  }));
1950
1982
  function useDocument() {
1951
1983
  return editorStateStore((s) => s.document);
@@ -2018,6 +2050,15 @@ function setSelectedScreenSize(selectedScreenSize) {
2018
2050
  function setPersistenceEnabled(persistenceEnabled) {
2019
2051
  return editorStateStore.setState({ persistenceEnabled });
2020
2052
  }
2053
+ function useLastFocusedEditable() {
2054
+ return editorStateStore((s) => s.lastFocusedEditable);
2055
+ }
2056
+ function getLastFocusedEditable() {
2057
+ return editorStateStore.getState().lastFocusedEditable;
2058
+ }
2059
+ function setLastFocusedEditable(lastFocusedEditable) {
2060
+ return editorStateStore.setState({ lastFocusedEditable });
2061
+ }
2021
2062
 
2022
2063
  // src/app/save-payload.ts
2023
2064
  var ROOT_BLOCK_ID = "root";
@@ -2089,7 +2130,7 @@ var EmailEditorProvider = ({
2089
2130
  registerSaveListener,
2090
2131
  setCurrentTemplate
2091
2132
  }), [currentTemplateId, currentTemplateName, currentTemplateKind, saveTemplate, loadTemplate, registerSaveListener, setCurrentTemplate]);
2092
- return /* @__PURE__ */ React60.createElement(EmailEditorContext.Provider, { value }, children);
2133
+ return /* @__PURE__ */ React58.createElement(EmailEditorContext.Provider, { value }, children);
2093
2134
  };
2094
2135
  var useEmailEditor = () => {
2095
2136
  const context = useContext(EmailEditorContext);
@@ -2098,15 +2139,25 @@ var useEmailEditor = () => {
2098
2139
  }
2099
2140
  return context;
2100
2141
  };
2142
+ var ImageCallbacksContext = createContext({});
2143
+ function ImageCallbacksProvider({
2144
+ callbacks,
2145
+ children
2146
+ }) {
2147
+ return /* @__PURE__ */ React58.createElement(ImageCallbacksContext.Provider, { value: callbacks }, children);
2148
+ }
2149
+ function useImageCallbacks() {
2150
+ return useContext(ImageCallbacksContext);
2151
+ }
2101
2152
  function BaseSidebarPanel({ title, children }) {
2102
- return /* @__PURE__ */ React60.createElement(Box, { p: 2 }, /* @__PURE__ */ React60.createElement(Typography, { variant: "overline", color: "text.secondary", sx: { display: "block", mb: 2 } }, title), /* @__PURE__ */ React60.createElement(Stack, { spacing: 5, mb: 3 }, children));
2153
+ return /* @__PURE__ */ React58.createElement(Box, { p: 2 }, /* @__PURE__ */ React58.createElement(Typography, { variant: "overline", color: "text.secondary", sx: { display: "block", mb: 2 } }, title), /* @__PURE__ */ React58.createElement(Stack, { spacing: 5, mb: 3 }, children));
2103
2154
  }
2104
2155
  function RadioGroupInput({ label, children, defaultValue, onChange }) {
2105
2156
  const [value, setValue] = useState(defaultValue);
2106
2157
  useEffect(() => {
2107
2158
  setValue(defaultValue);
2108
2159
  }, [defaultValue]);
2109
- return /* @__PURE__ */ React60.createElement(Stack, { alignItems: "flex-start" }, /* @__PURE__ */ React60.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React60.createElement(
2160
+ return /* @__PURE__ */ React58.createElement(Stack, { alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React58.createElement(
2110
2161
  ToggleButtonGroup,
2111
2162
  {
2112
2163
  exclusive: true,
@@ -2126,7 +2177,7 @@ function RadioGroupInput({ label, children, defaultValue, onChange }) {
2126
2177
  }
2127
2178
  function RawSliderInput(_a) {
2128
2179
  var _b = _a, { iconLabel, value, setValue, units } = _b, props = __objRest(_b, ["iconLabel", "value", "setValue", "units"]);
2129
- return /* @__PURE__ */ React60.createElement(Stack, { direction: "row", alignItems: "center", spacing: 2, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React60.createElement(Box, { sx: { minWidth: 24, lineHeight: 1, flexShrink: 0 } }, iconLabel), /* @__PURE__ */ React60.createElement(
2180
+ return /* @__PURE__ */ React58.createElement(Stack, { direction: "row", alignItems: "center", spacing: 2, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React58.createElement(Box, { sx: { minWidth: 24, lineHeight: 1, flexShrink: 0 } }, iconLabel), /* @__PURE__ */ React58.createElement(
2130
2181
  Slider,
2131
2182
  __spreadProps(__spreadValues({}, props), {
2132
2183
  value,
@@ -2137,14 +2188,14 @@ function RawSliderInput(_a) {
2137
2188
  setValue(value2);
2138
2189
  }
2139
2190
  })
2140
- ), /* @__PURE__ */ React60.createElement(Box, { sx: { minWidth: 32, textAlign: "right", flexShrink: 0 } }, /* @__PURE__ */ React60.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { lineHeight: 1 } }, value, units)));
2191
+ ), /* @__PURE__ */ React58.createElement(Box, { sx: { minWidth: 32, textAlign: "right", flexShrink: 0 } }, /* @__PURE__ */ React58.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { lineHeight: 1 } }, value, units)));
2141
2192
  }
2142
2193
 
2143
2194
  // src/app/inspector-drawer/configuration-panel/input-panels/helpers/inputs/slider-input.tsx
2144
2195
  function SliderInput(_a) {
2145
2196
  var _b = _a, { label, defaultValue, onChange } = _b, props = __objRest(_b, ["label", "defaultValue", "onChange"]);
2146
2197
  const [value, setValue] = useState(defaultValue);
2147
- return /* @__PURE__ */ React60.createElement(Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React60.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React60.createElement(
2198
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React58.createElement(
2148
2199
  RawSliderInput,
2149
2200
  __spreadValues({
2150
2201
  value,
@@ -2161,7 +2212,7 @@ function TextInput({ helperText, label, placeholder, rows, InputProps: InputProp
2161
2212
  useEffect(() => {
2162
2213
  setValue(defaultValue);
2163
2214
  }, [defaultValue]);
2164
- return /* @__PURE__ */ React60.createElement(
2215
+ return /* @__PURE__ */ React58.createElement(
2165
2216
  TextField,
2166
2217
  {
2167
2218
  fullWidth: true,
@@ -2187,7 +2238,7 @@ var TILE_BUTTON = {
2187
2238
  };
2188
2239
  function Swatch({ paletteColors, value, onChange }) {
2189
2240
  const renderButton2 = (colorValue) => {
2190
- return /* @__PURE__ */ React60.createElement(
2241
+ return /* @__PURE__ */ React58.createElement(
2191
2242
  Button$1,
2192
2243
  {
2193
2244
  key: colorValue,
@@ -2206,7 +2257,7 @@ function Swatch({ paletteColors, value, onChange }) {
2206
2257
  }
2207
2258
  );
2208
2259
  };
2209
- return /* @__PURE__ */ React60.createElement(Box, { width: "100%", sx: { display: "grid", gap: 1, gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr 1fr" } }, paletteColors.map((c) => renderButton2(c)));
2260
+ return /* @__PURE__ */ React58.createElement(Box, { width: "100%", sx: { display: "grid", gap: 1, gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr 1fr" } }, paletteColors.map((c) => renderButton2(c)));
2210
2261
  }
2211
2262
 
2212
2263
  // src/app/inspector-drawer/configuration-panel/input-panels/helpers/inputs/color-input/picker.tsx
@@ -2273,7 +2324,7 @@ var SX = {
2273
2324
  }
2274
2325
  };
2275
2326
  function Picker({ value, onChange }) {
2276
- return /* @__PURE__ */ React60.createElement(Stack, { spacing: 1, sx: SX }, /* @__PURE__ */ React60.createElement(HexColorPicker, { color: value, onChange }), /* @__PURE__ */ React60.createElement(Swatch, { paletteColors: DEFAULT_PRESET_COLORS, value, onChange }), /* @__PURE__ */ React60.createElement(Box, { pt: 1 }, /* @__PURE__ */ React60.createElement(HexColorInput, { prefixed: true, color: value, onChange })));
2327
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 1, sx: SX }, /* @__PURE__ */ React58.createElement(HexColorPicker, { color: value, onChange }), /* @__PURE__ */ React58.createElement(Swatch, { paletteColors: DEFAULT_PRESET_COLORS, value, onChange }), /* @__PURE__ */ React58.createElement(Box, { pt: 1 }, /* @__PURE__ */ React58.createElement(HexColorInput, { prefixed: true, color: value, onChange })));
2277
2328
  }
2278
2329
 
2279
2330
  // src/app/inspector-drawer/configuration-panel/input-panels/helpers/inputs/color-input/base-color-input.tsx
@@ -2298,7 +2349,7 @@ function ColorInput({ label, defaultValue, onChange, nullable }) {
2298
2349
  if (typeof value !== "string" || value.trim().length === 0) {
2299
2350
  return null;
2300
2351
  }
2301
- return /* @__PURE__ */ React60.createElement(
2352
+ return /* @__PURE__ */ React58.createElement(
2302
2353
  ButtonBase,
2303
2354
  {
2304
2355
  onClick: () => {
@@ -2306,16 +2357,16 @@ function ColorInput({ label, defaultValue, onChange, nullable }) {
2306
2357
  onChange(null);
2307
2358
  }
2308
2359
  },
2309
- /* @__PURE__ */ React60.createElement(CloseOutlined, { fontSize: "small", sx: { color: "grey.600" } })
2360
+ /* @__PURE__ */ React58.createElement(CloseOutlined, { fontSize: "small", sx: { color: "grey.600" } })
2310
2361
  );
2311
2362
  };
2312
2363
  const renderOpenButton = () => {
2313
2364
  if (value) {
2314
- return /* @__PURE__ */ React60.createElement(ButtonBase, { onClick: handleClickOpen, sx: __spreadProps(__spreadValues({}, BUTTON_SX), { bgcolor: value }) });
2365
+ return /* @__PURE__ */ React58.createElement(ButtonBase, { onClick: handleClickOpen, sx: __spreadProps(__spreadValues({}, BUTTON_SX), { bgcolor: value }) });
2315
2366
  }
2316
- return /* @__PURE__ */ React60.createElement(ButtonBase, { onClick: handleClickOpen, sx: __spreadValues({}, BUTTON_SX) }, /* @__PURE__ */ React60.createElement(AddOutlined, { fontSize: "small" }));
2367
+ return /* @__PURE__ */ React58.createElement(ButtonBase, { onClick: handleClickOpen, sx: __spreadValues({}, BUTTON_SX) }, /* @__PURE__ */ React58.createElement(AddOutlined, { fontSize: "small" }));
2317
2368
  };
2318
- return /* @__PURE__ */ React60.createElement(Stack, { alignItems: "flex-start" }, /* @__PURE__ */ React60.createElement(InputLabel, { sx: { mb: 0.5 } }, label), /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 1 }, renderOpenButton(), renderResetButton()), /* @__PURE__ */ React60.createElement(
2369
+ return /* @__PURE__ */ React58.createElement(Stack, { alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(InputLabel, { sx: { mb: 0.5 } }, label), /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 1 }, renderOpenButton(), renderResetButton()), /* @__PURE__ */ React58.createElement(
2319
2370
  Menu,
2320
2371
  {
2321
2372
  anchorEl,
@@ -2325,7 +2376,7 @@ function ColorInput({ label, defaultValue, onChange, nullable }) {
2325
2376
  sx: { height: "auto", padding: 0 }
2326
2377
  }
2327
2378
  },
2328
- /* @__PURE__ */ React60.createElement(
2379
+ /* @__PURE__ */ React58.createElement(
2329
2380
  Picker,
2330
2381
  {
2331
2382
  value: value || "",
@@ -2340,10 +2391,10 @@ function ColorInput({ label, defaultValue, onChange, nullable }) {
2340
2391
 
2341
2392
  // src/app/inspector-drawer/configuration-panel/input-panels/helpers/inputs/color-input/index.tsx
2342
2393
  function ColorInput2(props) {
2343
- return /* @__PURE__ */ React60.createElement(ColorInput, __spreadProps(__spreadValues({}, props), { nullable: false }));
2394
+ return /* @__PURE__ */ React58.createElement(ColorInput, __spreadProps(__spreadValues({}, props), { nullable: false }));
2344
2395
  }
2345
2396
  function NullableColorInput(props) {
2346
- return /* @__PURE__ */ React60.createElement(ColorInput, __spreadProps(__spreadValues({}, props), { nullable: true }));
2397
+ return /* @__PURE__ */ React58.createElement(ColorInput, __spreadProps(__spreadValues({}, props), { nullable: true }));
2347
2398
  }
2348
2399
 
2349
2400
  // src/editor/blocks/helpers/font-family.ts
@@ -2396,13 +2447,13 @@ var FONT_FAMILIES = [
2396
2447
  ];
2397
2448
 
2398
2449
  // src/app/inspector-drawer/configuration-panel/input-panels/helpers/inputs/font-family.tsx
2399
- var OPTIONS = FONT_FAMILIES.map((option) => /* @__PURE__ */ React60.createElement(MenuItem, { key: option.key, value: option.key, sx: { fontFamily: option.value } }, option.label));
2450
+ var OPTIONS = FONT_FAMILIES.map((option) => /* @__PURE__ */ React58.createElement(MenuItem, { key: option.key, value: option.key, sx: { fontFamily: option.value } }, option.label));
2400
2451
  function NullableFontFamily({ label, onChange, defaultValue }) {
2401
2452
  const [value, setValue] = useState(defaultValue != null ? defaultValue : "inherit");
2402
2453
  useEffect(() => {
2403
2454
  setValue(defaultValue != null ? defaultValue : "inherit");
2404
2455
  }, [defaultValue]);
2405
- return /* @__PURE__ */ React60.createElement(
2456
+ return /* @__PURE__ */ React58.createElement(
2406
2457
  TextField,
2407
2458
  {
2408
2459
  select: true,
@@ -2415,7 +2466,7 @@ function NullableFontFamily({ label, onChange, defaultValue }) {
2415
2466
  onChange(v === null ? null : v);
2416
2467
  }
2417
2468
  },
2418
- /* @__PURE__ */ React60.createElement(MenuItem, { value: "inherit" }, "Match email settings"),
2469
+ /* @__PURE__ */ React58.createElement(MenuItem, { value: "inherit" }, "Match email settings"),
2419
2470
  OPTIONS
2420
2471
  );
2421
2472
  }
@@ -2428,10 +2479,10 @@ function FontSizeInput({ label, defaultValue, onChange }) {
2428
2479
  setValue(value2);
2429
2480
  onChange(value2);
2430
2481
  };
2431
- return /* @__PURE__ */ React60.createElement(Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React60.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React60.createElement(
2482
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React58.createElement(
2432
2483
  RawSliderInput,
2433
2484
  {
2434
- iconLabel: /* @__PURE__ */ React60.createElement(TextFieldsOutlined, { sx: { fontSize: 16 } }),
2485
+ iconLabel: /* @__PURE__ */ React58.createElement(TextFieldsOutlined, { sx: { fontSize: 16 } }),
2435
2486
  value,
2436
2487
  setValue: handleChange,
2437
2488
  units: "px",
@@ -2446,7 +2497,7 @@ function FontWeightInput({ label, defaultValue, onChange }) {
2446
2497
  useEffect(() => {
2447
2498
  setValue(defaultValue);
2448
2499
  }, [defaultValue]);
2449
- return /* @__PURE__ */ React60.createElement(
2500
+ return /* @__PURE__ */ React58.createElement(
2450
2501
  RadioGroupInput,
2451
2502
  {
2452
2503
  label,
@@ -2456,10 +2507,54 @@ function FontWeightInput({ label, defaultValue, onChange }) {
2456
2507
  onChange(fontWeight);
2457
2508
  }
2458
2509
  },
2459
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "normal" }, "Regular"),
2460
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "bold" }, "Bold")
2510
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "normal" }, "Regular"),
2511
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "bold" }, "Bold")
2461
2512
  );
2462
2513
  }
2514
+ function LetterSpacingInput({ label, defaultValue, onChange }) {
2515
+ const [value, setValue] = useState(defaultValue != null ? defaultValue : 0);
2516
+ useEffect(() => {
2517
+ setValue(defaultValue != null ? defaultValue : 0);
2518
+ }, [defaultValue]);
2519
+ const handleChange = (v) => {
2520
+ setValue(v);
2521
+ onChange(v === 0 ? null : v);
2522
+ };
2523
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React58.createElement(
2524
+ RawSliderInput,
2525
+ {
2526
+ iconLabel: /* @__PURE__ */ React58.createElement(SpaceBarOutlined, { sx: { fontSize: 16 } }),
2527
+ value,
2528
+ setValue: handleChange,
2529
+ units: "px",
2530
+ step: 0.1,
2531
+ min: 0,
2532
+ max: 2
2533
+ }
2534
+ ));
2535
+ }
2536
+ function LineHeightInput({ label, defaultValue, onChange }) {
2537
+ const [value, setValue] = useState(defaultValue != null ? defaultValue : 0);
2538
+ useEffect(() => {
2539
+ setValue(defaultValue != null ? defaultValue : 0);
2540
+ }, [defaultValue]);
2541
+ const handleChange = (v) => {
2542
+ setValue(v);
2543
+ onChange(v === 0 ? null : v);
2544
+ };
2545
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React58.createElement(
2546
+ RawSliderInput,
2547
+ {
2548
+ iconLabel: /* @__PURE__ */ React58.createElement(FormatLineSpacingOutlined, { sx: { fontSize: 16 } }),
2549
+ value,
2550
+ setValue: handleChange,
2551
+ units: "",
2552
+ step: 0.1,
2553
+ min: 0,
2554
+ max: 2
2555
+ }
2556
+ ));
2557
+ }
2463
2558
  function PaddingInput({ label, defaultValue, onChange }) {
2464
2559
  const [value, setValue] = useState(() => {
2465
2560
  if (defaultValue) {
@@ -2479,10 +2574,10 @@ function PaddingInput({ label, defaultValue, onChange }) {
2479
2574
  setValue(v);
2480
2575
  onChange(v);
2481
2576
  }
2482
- return /* @__PURE__ */ React60.createElement(Stack, { spacing: 2, alignItems: "flex-start", pb: 1 }, /* @__PURE__ */ React60.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React60.createElement(
2577
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 2, alignItems: "flex-start", pb: 1 }, /* @__PURE__ */ React58.createElement(InputLabel, { shrink: true }, label), /* @__PURE__ */ React58.createElement(
2483
2578
  RawSliderInput,
2484
2579
  {
2485
- iconLabel: /* @__PURE__ */ React60.createElement(AlignVerticalTopOutlined, { sx: { fontSize: 16 } }),
2580
+ iconLabel: /* @__PURE__ */ React58.createElement(AlignVerticalTopOutlined, { sx: { fontSize: 16 } }),
2486
2581
  value: value.top,
2487
2582
  setValue: (num) => handleChange("top", num),
2488
2583
  units: "px",
@@ -2491,10 +2586,10 @@ function PaddingInput({ label, defaultValue, onChange }) {
2491
2586
  max: 80,
2492
2587
  marks: true
2493
2588
  }
2494
- ), /* @__PURE__ */ React60.createElement(
2589
+ ), /* @__PURE__ */ React58.createElement(
2495
2590
  RawSliderInput,
2496
2591
  {
2497
- iconLabel: /* @__PURE__ */ React60.createElement(AlignVerticalBottomOutlined, { sx: { fontSize: 16 } }),
2592
+ iconLabel: /* @__PURE__ */ React58.createElement(AlignVerticalBottomOutlined, { sx: { fontSize: 16 } }),
2498
2593
  value: value.bottom,
2499
2594
  setValue: (num) => handleChange("bottom", num),
2500
2595
  units: "px",
@@ -2503,10 +2598,10 @@ function PaddingInput({ label, defaultValue, onChange }) {
2503
2598
  max: 80,
2504
2599
  marks: true
2505
2600
  }
2506
- ), /* @__PURE__ */ React60.createElement(
2601
+ ), /* @__PURE__ */ React58.createElement(
2507
2602
  RawSliderInput,
2508
2603
  {
2509
- iconLabel: /* @__PURE__ */ React60.createElement(AlignHorizontalLeftOutlined, { sx: { fontSize: 16 } }),
2604
+ iconLabel: /* @__PURE__ */ React58.createElement(AlignHorizontalLeftOutlined, { sx: { fontSize: 16 } }),
2510
2605
  value: value.left,
2511
2606
  setValue: (num) => handleChange("left", num),
2512
2607
  units: "px",
@@ -2515,10 +2610,10 @@ function PaddingInput({ label, defaultValue, onChange }) {
2515
2610
  max: 80,
2516
2611
  marks: true
2517
2612
  }
2518
- ), /* @__PURE__ */ React60.createElement(
2613
+ ), /* @__PURE__ */ React58.createElement(
2519
2614
  RawSliderInput,
2520
2615
  {
2521
- iconLabel: /* @__PURE__ */ React60.createElement(AlignHorizontalRightOutlined, { sx: { fontSize: 16 } }),
2616
+ iconLabel: /* @__PURE__ */ React58.createElement(AlignHorizontalRightOutlined, { sx: { fontSize: 16 } }),
2522
2617
  value: value.right,
2523
2618
  setValue: (num) => handleChange("right", num),
2524
2619
  units: "px",
@@ -2534,7 +2629,7 @@ function TextAlignInput({ label, defaultValue, onChange }) {
2534
2629
  useEffect(() => {
2535
2630
  setValue(defaultValue != null ? defaultValue : "left");
2536
2631
  }, [defaultValue]);
2537
- return /* @__PURE__ */ React60.createElement(
2632
+ return /* @__PURE__ */ React58.createElement(
2538
2633
  RadioGroupInput,
2539
2634
  {
2540
2635
  label,
@@ -2544,9 +2639,9 @@ function TextAlignInput({ label, defaultValue, onChange }) {
2544
2639
  onChange(value2);
2545
2640
  }
2546
2641
  },
2547
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "left" }, /* @__PURE__ */ React60.createElement(FormatAlignLeftOutlined, { fontSize: "small" })),
2548
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "center" }, /* @__PURE__ */ React60.createElement(FormatAlignCenterOutlined, { fontSize: "small" })),
2549
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "right" }, /* @__PURE__ */ React60.createElement(FormatAlignRightOutlined, { fontSize: "small" }))
2642
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "left" }, /* @__PURE__ */ React58.createElement(FormatAlignLeftOutlined, { fontSize: "small" })),
2643
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "center" }, /* @__PURE__ */ React58.createElement(FormatAlignCenterOutlined, { fontSize: "small" })),
2644
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "right" }, /* @__PURE__ */ React58.createElement(FormatAlignRightOutlined, { fontSize: "small" }))
2550
2645
  );
2551
2646
  }
2552
2647
 
@@ -2559,14 +2654,14 @@ function SingleStylePropertyPanel({ name, value, onChange }) {
2559
2654
  };
2560
2655
  switch (name) {
2561
2656
  case "backgroundColor":
2562
- return /* @__PURE__ */ React60.createElement(NullableColorInput, { label: "Background color", defaultValue, onChange: handleChange });
2657
+ return /* @__PURE__ */ React58.createElement(NullableColorInput, { label: "Background color", defaultValue, onChange: handleChange });
2563
2658
  case "borderColor":
2564
- return /* @__PURE__ */ React60.createElement(NullableColorInput, { label: "Border color", defaultValue, onChange: handleChange });
2659
+ return /* @__PURE__ */ React58.createElement(NullableColorInput, { label: "Border color", defaultValue, onChange: handleChange });
2565
2660
  case "borderRadius":
2566
- return /* @__PURE__ */ React60.createElement(
2661
+ return /* @__PURE__ */ React58.createElement(
2567
2662
  SliderInput,
2568
2663
  {
2569
- iconLabel: /* @__PURE__ */ React60.createElement(RoundedCornerOutlined, null),
2664
+ iconLabel: /* @__PURE__ */ React58.createElement(RoundedCornerOutlined, null),
2570
2665
  units: "px",
2571
2666
  step: 4,
2572
2667
  marks: true,
@@ -2578,23 +2673,27 @@ function SingleStylePropertyPanel({ name, value, onChange }) {
2578
2673
  }
2579
2674
  );
2580
2675
  case "color":
2581
- return /* @__PURE__ */ React60.createElement(NullableColorInput, { label: "Text color", defaultValue, onChange: handleChange });
2676
+ return /* @__PURE__ */ React58.createElement(NullableColorInput, { label: "Text color", defaultValue, onChange: handleChange });
2582
2677
  case "fontFamily":
2583
- return /* @__PURE__ */ React60.createElement(NullableFontFamily, { label: "Font family", defaultValue, onChange: handleChange });
2678
+ return /* @__PURE__ */ React58.createElement(NullableFontFamily, { label: "Font family", defaultValue, onChange: handleChange });
2584
2679
  case "fontSize":
2585
- return /* @__PURE__ */ React60.createElement(FontSizeInput, { label: "Font size", defaultValue, onChange: handleChange });
2680
+ return /* @__PURE__ */ React58.createElement(FontSizeInput, { label: "Font size", defaultValue, onChange: handleChange });
2586
2681
  case "fontWeight":
2587
- return /* @__PURE__ */ React60.createElement(FontWeightInput, { label: "Font weight", defaultValue, onChange: handleChange });
2682
+ return /* @__PURE__ */ React58.createElement(FontWeightInput, { label: "Font weight", defaultValue, onChange: handleChange });
2683
+ case "lineHeight":
2684
+ return /* @__PURE__ */ React58.createElement(LineHeightInput, { label: "Line height", defaultValue, onChange: handleChange });
2685
+ case "letterSpacing":
2686
+ return /* @__PURE__ */ React58.createElement(LetterSpacingInput, { label: "Letter spacing", defaultValue, onChange: handleChange });
2588
2687
  case "textAlign":
2589
- return /* @__PURE__ */ React60.createElement(TextAlignInput, { label: "Alignment", defaultValue, onChange: handleChange });
2688
+ return /* @__PURE__ */ React58.createElement(TextAlignInput, { label: "Alignment", defaultValue, onChange: handleChange });
2590
2689
  case "padding":
2591
- return /* @__PURE__ */ React60.createElement(PaddingInput, { label: "Padding", defaultValue, onChange: handleChange });
2690
+ return /* @__PURE__ */ React58.createElement(PaddingInput, { label: "Padding", defaultValue, onChange: handleChange });
2592
2691
  }
2593
2692
  }
2594
2693
 
2595
2694
  // src/app/inspector-drawer/configuration-panel/input-panels/helpers/style-inputs/multi-style-property-panel.tsx
2596
2695
  function MultiStylePropertyPanel({ names, value, onChange }) {
2597
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, names.map((name) => /* @__PURE__ */ React60.createElement(SingleStylePropertyPanel, { key: name, name, value: value || {}, onChange })));
2696
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, names.map((name) => /* @__PURE__ */ React58.createElement(SingleStylePropertyPanel, { key: name, name, value: value || {}, onChange })));
2598
2697
  }
2599
2698
 
2600
2699
  // src/app/inspector-drawer/configuration-panel/input-panels/avatar-sidebar-panel.tsx
@@ -2614,11 +2713,11 @@ function AvatarSidebarPanel({ data, setData }) {
2614
2713
  const imageUrl = (_d = (_c = data.props) == null ? void 0 : _c.imageUrl) != null ? _d : AvatarPropsDefaults.imageUrl;
2615
2714
  const alt = (_f = (_e = data.props) == null ? void 0 : _e.alt) != null ? _f : AvatarPropsDefaults.alt;
2616
2715
  const shape = (_h = (_g = data.props) == null ? void 0 : _g.shape) != null ? _h : AvatarPropsDefaults.shape;
2617
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Avatar block" }, /* @__PURE__ */ React60.createElement(
2716
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Avatar block" }, /* @__PURE__ */ React58.createElement(
2618
2717
  SliderInput,
2619
2718
  {
2620
2719
  label: "Size",
2621
- iconLabel: /* @__PURE__ */ React60.createElement(AspectRatioOutlined, { sx: { color: "text.secondary" } }),
2720
+ iconLabel: /* @__PURE__ */ React58.createElement(AspectRatioOutlined, { sx: { color: "text.secondary" } }),
2622
2721
  units: "px",
2623
2722
  step: 3,
2624
2723
  min: 32,
@@ -2628,7 +2727,7 @@ function AvatarSidebarPanel({ data, setData }) {
2628
2727
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { size: size2 }) }));
2629
2728
  }
2630
2729
  }
2631
- ), /* @__PURE__ */ React60.createElement(
2730
+ ), /* @__PURE__ */ React58.createElement(
2632
2731
  RadioGroupInput,
2633
2732
  {
2634
2733
  label: "Shape",
@@ -2637,10 +2736,10 @@ function AvatarSidebarPanel({ data, setData }) {
2637
2736
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { shape: shape2 }) }));
2638
2737
  }
2639
2738
  },
2640
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "circle" }, "Circle"),
2641
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "square" }, "Square"),
2642
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "rounded" }, "Rounded")
2643
- ), /* @__PURE__ */ React60.createElement(
2739
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "circle" }, "Circle"),
2740
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "square" }, "Square"),
2741
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "rounded" }, "Rounded")
2742
+ ), /* @__PURE__ */ React58.createElement(
2644
2743
  TextInput,
2645
2744
  {
2646
2745
  label: "Image URL",
@@ -2649,7 +2748,7 @@ function AvatarSidebarPanel({ data, setData }) {
2649
2748
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { imageUrl: imageUrl2 }) }));
2650
2749
  }
2651
2750
  }
2652
- ), /* @__PURE__ */ React60.createElement(
2751
+ ), /* @__PURE__ */ React58.createElement(
2653
2752
  TextInput,
2654
2753
  {
2655
2754
  label: "Alt text",
@@ -2658,7 +2757,7 @@ function AvatarSidebarPanel({ data, setData }) {
2658
2757
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { alt: alt2 }) }));
2659
2758
  }
2660
2759
  }
2661
- ), /* @__PURE__ */ React60.createElement(
2760
+ ), /* @__PURE__ */ React58.createElement(
2662
2761
  MultiStylePropertyPanel,
2663
2762
  {
2664
2763
  names: ["textAlign", "padding"],
@@ -2686,68 +2785,77 @@ function ButtonSidebarPanel({ data, setData }) {
2686
2785
  const buttonStyle = (_j = (_i = data.props) == null ? void 0 : _i.buttonStyle) != null ? _j : ButtonPropsDefaults.buttonStyle;
2687
2786
  const buttonTextColor = (_l = (_k = data.props) == null ? void 0 : _k.buttonTextColor) != null ? _l : ButtonPropsDefaults.buttonTextColor;
2688
2787
  const buttonBackgroundColor = (_n = (_m = data.props) == null ? void 0 : _m.buttonBackgroundColor) != null ? _n : ButtonPropsDefaults.buttonBackgroundColor;
2689
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Button block" }, /* @__PURE__ */ React60.createElement(
2788
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Button block" }, /* @__PURE__ */ React58.createElement(
2690
2789
  TextInput,
2691
2790
  {
2692
2791
  label: "Text",
2693
2792
  defaultValue: text,
2694
2793
  onChange: (text2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { text: text2 }) }))
2695
2794
  }
2696
- ), /* @__PURE__ */ React60.createElement(
2795
+ ), /* @__PURE__ */ React58.createElement(
2697
2796
  TextInput,
2698
2797
  {
2699
2798
  label: "Url",
2700
2799
  defaultValue: url,
2701
2800
  onChange: (url2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { url: url2 }) }))
2702
2801
  }
2703
- ), /* @__PURE__ */ React60.createElement(
2802
+ ), /* @__PURE__ */ React58.createElement(
2704
2803
  RadioGroupInput,
2705
2804
  {
2706
2805
  label: "Width",
2707
2806
  defaultValue: fullWidth ? "FULL_WIDTH" : "AUTO",
2708
2807
  onChange: (v) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { fullWidth: v === "FULL_WIDTH" }) }))
2709
2808
  },
2710
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "FULL_WIDTH" }, "Full"),
2711
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "AUTO" }, "Auto")
2712
- ), /* @__PURE__ */ React60.createElement(
2809
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "FULL_WIDTH" }, "Full"),
2810
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "AUTO" }, "Auto")
2811
+ ), /* @__PURE__ */ React58.createElement(
2713
2812
  RadioGroupInput,
2714
2813
  {
2715
2814
  label: "Size",
2716
2815
  defaultValue: size,
2717
2816
  onChange: (size2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { size: size2 }) }))
2718
2817
  },
2719
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "x-small" }, "Xs"),
2720
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "small" }, "Sm"),
2721
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "medium" }, "Md"),
2722
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "large" }, "Lg")
2723
- ), /* @__PURE__ */ React60.createElement(
2818
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "x-small" }, "Xs"),
2819
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "small" }, "Sm"),
2820
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "medium" }, "Md"),
2821
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "large" }, "Lg")
2822
+ ), /* @__PURE__ */ React58.createElement(
2724
2823
  RadioGroupInput,
2725
2824
  {
2726
2825
  label: "Style",
2727
2826
  defaultValue: buttonStyle,
2728
2827
  onChange: (buttonStyle2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { buttonStyle: buttonStyle2 }) }))
2729
2828
  },
2730
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "rectangle" }, "Rectangle"),
2731
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "rounded" }, "Rounded"),
2732
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "pill" }, "Pill")
2733
- ), /* @__PURE__ */ React60.createElement(
2829
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "rectangle" }, "Rectangle"),
2830
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "rounded" }, "Rounded"),
2831
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "pill" }, "Pill")
2832
+ ), /* @__PURE__ */ React58.createElement(
2734
2833
  ColorInput2,
2735
2834
  {
2736
2835
  label: "Text color",
2737
2836
  defaultValue: buttonTextColor,
2738
2837
  onChange: (buttonTextColor2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { buttonTextColor: buttonTextColor2 }) }))
2739
2838
  }
2740
- ), /* @__PURE__ */ React60.createElement(
2839
+ ), /* @__PURE__ */ React58.createElement(
2741
2840
  ColorInput2,
2742
2841
  {
2743
2842
  label: "Button color",
2744
2843
  defaultValue: buttonBackgroundColor,
2745
2844
  onChange: (buttonBackgroundColor2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { buttonBackgroundColor: buttonBackgroundColor2 }) }))
2746
2845
  }
2747
- ), /* @__PURE__ */ React60.createElement(
2846
+ ), /* @__PURE__ */ React58.createElement(
2748
2847
  MultiStylePropertyPanel,
2749
2848
  {
2750
- names: ["backgroundColor", "fontFamily", "fontSize", "fontWeight", "textAlign", "padding"],
2849
+ names: [
2850
+ "backgroundColor",
2851
+ "fontFamily",
2852
+ "fontSize",
2853
+ "fontWeight",
2854
+ "lineHeight",
2855
+ "letterSpacing",
2856
+ "textAlign",
2857
+ "padding"
2858
+ ],
2751
2859
  value: data.style,
2752
2860
  onChange: (style) => updateData(__spreadProps(__spreadValues({}, data), { style }))
2753
2861
  }
@@ -2770,7 +2878,7 @@ function TextDimensionInput({ label, defaultValue, onChange }) {
2770
2878
  const value = parseInt(ev.target.value);
2771
2879
  onChange(isNaN(value) ? null : value);
2772
2880
  };
2773
- return /* @__PURE__ */ React60.createElement(
2881
+ return /* @__PURE__ */ React58.createElement(
2774
2882
  TextField,
2775
2883
  {
2776
2884
  fullWidth: true,
@@ -2781,7 +2889,7 @@ function TextDimensionInput({ label, defaultValue, onChange }) {
2781
2889
  placeholder: "auto",
2782
2890
  size: "small",
2783
2891
  InputProps: {
2784
- endAdornment: /* @__PURE__ */ React60.createElement(Typography, { variant: "body2", color: "text.secondary" }, "px")
2892
+ endAdornment: /* @__PURE__ */ React58.createElement(Typography, { variant: "body2", color: "text.secondary" }, "px")
2785
2893
  }
2786
2894
  }
2787
2895
  );
@@ -2803,7 +2911,7 @@ function ColumnWidthsInput({ defaultValue, onChange }) {
2803
2911
  };
2804
2912
  let column3 = null;
2805
2913
  {
2806
- column3 = /* @__PURE__ */ React60.createElement(
2914
+ column3 = /* @__PURE__ */ React58.createElement(
2807
2915
  TextDimensionInput,
2808
2916
  {
2809
2917
  label: "Column 3",
@@ -2814,7 +2922,7 @@ function ColumnWidthsInput({ defaultValue, onChange }) {
2814
2922
  }
2815
2923
  );
2816
2924
  }
2817
- return /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 1 }, /* @__PURE__ */ React60.createElement(
2925
+ return /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 1 }, /* @__PURE__ */ React58.createElement(
2818
2926
  TextDimensionInput,
2819
2927
  {
2820
2928
  label: "Column 1",
@@ -2823,7 +2931,7 @@ function ColumnWidthsInput({ defaultValue, onChange }) {
2823
2931
  setIndexValue(0, v);
2824
2932
  }
2825
2933
  }
2826
- ), /* @__PURE__ */ React60.createElement(
2934
+ ), /* @__PURE__ */ React58.createElement(
2827
2935
  TextDimensionInput,
2828
2936
  {
2829
2937
  label: "Column 2",
@@ -2848,7 +2956,7 @@ function ColumnsContainerPanel({ data, setData }) {
2848
2956
  setErrors(res.error);
2849
2957
  }
2850
2958
  };
2851
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Columns block" }, /* @__PURE__ */ React60.createElement(
2959
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Columns block" }, /* @__PURE__ */ React58.createElement(
2852
2960
  RadioGroupInput,
2853
2961
  {
2854
2962
  label: "Number of columns",
@@ -2857,9 +2965,9 @@ function ColumnsContainerPanel({ data, setData }) {
2857
2965
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { columnsCount: v === "2" ? 2 : 3 }) }));
2858
2966
  }
2859
2967
  },
2860
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "2" }, "2"),
2861
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "3" }, "3")
2862
- ), /* @__PURE__ */ React60.createElement(
2968
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "2" }, "2"),
2969
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "3" }, "3")
2970
+ ), /* @__PURE__ */ React58.createElement(
2863
2971
  ColumnWidthsInput,
2864
2972
  {
2865
2973
  defaultValue: (_b = data.props) == null ? void 0 : _b.fixedWidths,
@@ -2867,11 +2975,11 @@ function ColumnsContainerPanel({ data, setData }) {
2867
2975
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { fixedWidths }) }));
2868
2976
  }
2869
2977
  }
2870
- ), /* @__PURE__ */ React60.createElement(
2978
+ ), /* @__PURE__ */ React58.createElement(
2871
2979
  SliderInput,
2872
2980
  {
2873
2981
  label: "Columns gap",
2874
- iconLabel: /* @__PURE__ */ React60.createElement(SpaceBarOutlined, { sx: { color: "text.secondary" } }),
2982
+ iconLabel: /* @__PURE__ */ React58.createElement(SpaceBarOutlined, { sx: { color: "text.secondary" } }),
2875
2983
  units: "px",
2876
2984
  step: 4,
2877
2985
  marks: true,
@@ -2880,7 +2988,7 @@ function ColumnsContainerPanel({ data, setData }) {
2880
2988
  defaultValue: (_d = (_c = data.props) == null ? void 0 : _c.columnsGap) != null ? _d : 0,
2881
2989
  onChange: (columnsGap) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { columnsGap }) }))
2882
2990
  }
2883
- ), /* @__PURE__ */ React60.createElement(
2991
+ ), /* @__PURE__ */ React58.createElement(
2884
2992
  RadioGroupInput,
2885
2993
  {
2886
2994
  label: "Alignment",
@@ -2889,10 +2997,10 @@ function ColumnsContainerPanel({ data, setData }) {
2889
2997
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { contentAlignment }) }));
2890
2998
  }
2891
2999
  },
2892
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "top" }, /* @__PURE__ */ React60.createElement(VerticalAlignTopOutlined, { fontSize: "small" })),
2893
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "middle" }, /* @__PURE__ */ React60.createElement(VerticalAlignCenterOutlined, { fontSize: "small" })),
2894
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "bottom" }, /* @__PURE__ */ React60.createElement(VerticalAlignBottomOutlined, { fontSize: "small" }))
2895
- ), /* @__PURE__ */ React60.createElement(
3000
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "top" }, /* @__PURE__ */ React58.createElement(VerticalAlignTopOutlined, { fontSize: "small" })),
3001
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "middle" }, /* @__PURE__ */ React58.createElement(VerticalAlignCenterOutlined, { fontSize: "small" })),
3002
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "bottom" }, /* @__PURE__ */ React58.createElement(VerticalAlignBottomOutlined, { fontSize: "small" }))
3003
+ ), /* @__PURE__ */ React58.createElement(
2896
3004
  MultiStylePropertyPanel,
2897
3005
  {
2898
3006
  names: ["backgroundColor", "padding"],
@@ -2921,7 +3029,7 @@ function ContainerSidebarPanel({ data, setData }) {
2921
3029
  setErrors(res.error);
2922
3030
  }
2923
3031
  };
2924
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Container block" }, /* @__PURE__ */ React60.createElement(
3032
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Container block" }, /* @__PURE__ */ React58.createElement(
2925
3033
  MultiStylePropertyPanel,
2926
3034
  {
2927
3035
  names: ["backgroundColor", "borderColor", "borderRadius", "padding"],
@@ -2944,18 +3052,18 @@ function DividerSidebarPanel({ data, setData }) {
2944
3052
  };
2945
3053
  const lineColor = (_b = (_a = data.props) == null ? void 0 : _a.lineColor) != null ? _b : DividerPropsDefaults.lineColor;
2946
3054
  const lineHeight = (_d = (_c = data.props) == null ? void 0 : _c.lineHeight) != null ? _d : DividerPropsDefaults.lineHeight;
2947
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Divider block" }, /* @__PURE__ */ React60.createElement(
3055
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Divider block" }, /* @__PURE__ */ React58.createElement(
2948
3056
  ColorInput2,
2949
3057
  {
2950
3058
  label: "Color",
2951
3059
  defaultValue: lineColor,
2952
3060
  onChange: (lineColor2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { lineColor: lineColor2 }) }))
2953
3061
  }
2954
- ), /* @__PURE__ */ React60.createElement(
3062
+ ), /* @__PURE__ */ React58.createElement(
2955
3063
  SliderInput,
2956
3064
  {
2957
3065
  label: "Height",
2958
- iconLabel: /* @__PURE__ */ React60.createElement(HeightOutlined, { sx: { color: "text.secondary" } }),
3066
+ iconLabel: /* @__PURE__ */ React58.createElement(HeightOutlined, { sx: { color: "text.secondary" } }),
2959
3067
  units: "px",
2960
3068
  step: 1,
2961
3069
  min: 1,
@@ -2963,7 +3071,7 @@ function DividerSidebarPanel({ data, setData }) {
2963
3071
  defaultValue: lineHeight,
2964
3072
  onChange: (lineHeight2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { lineHeight: lineHeight2 }) }))
2965
3073
  }
2966
- ), /* @__PURE__ */ React60.createElement(
3074
+ ), /* @__PURE__ */ React58.createElement(
2967
3075
  MultiStylePropertyPanel,
2968
3076
  {
2969
3077
  names: ["backgroundColor", "padding"],
@@ -2986,7 +3094,8 @@ var FONT_FAMILY_SCHEMA7 = z.enum([
2986
3094
  ]).nullable().optional();
2987
3095
  var TemplateVariableSchema2 = z.object({
2988
3096
  name: z.string(),
2989
- description: z.string().optional().nullable()
3097
+ description: z.string().optional().nullable(),
3098
+ sampleValue: z.string().optional().nullable()
2990
3099
  });
2991
3100
  var EmailLayoutPropsSchema2 = z.object({
2992
3101
  backdropColor: COLOR_SCHEMA10,
@@ -3006,11 +3115,11 @@ function BooleanInput({ label, defaultValue, onChange }) {
3006
3115
  useEffect(() => {
3007
3116
  setValue(defaultValue);
3008
3117
  }, [defaultValue]);
3009
- return /* @__PURE__ */ React60.createElement(
3118
+ return /* @__PURE__ */ React58.createElement(
3010
3119
  FormControlLabel,
3011
3120
  {
3012
3121
  label,
3013
- control: /* @__PURE__ */ React60.createElement(
3122
+ control: /* @__PURE__ */ React58.createElement(
3014
3123
  Switch,
3015
3124
  {
3016
3125
  checked: value,
@@ -3038,38 +3147,38 @@ function EmailLayoutSidebarFields({ data, setData }) {
3038
3147
  }
3039
3148
  };
3040
3149
  const backdropDisabled = (_a = data.backdropDisabled) != null ? _a : false;
3041
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Global" }, /* @__PURE__ */ React60.createElement(
3150
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Global" }, /* @__PURE__ */ React58.createElement(
3042
3151
  BooleanInput,
3043
3152
  {
3044
3153
  label: "Disable backdrop",
3045
3154
  defaultValue: backdropDisabled,
3046
3155
  onChange: (backdropDisabled2) => updateData(__spreadProps(__spreadValues({}, data), { backdropDisabled: backdropDisabled2 }))
3047
3156
  }
3048
- ), !backdropDisabled && /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
3157
+ ), !backdropDisabled && /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
3049
3158
  ColorInput2,
3050
3159
  {
3051
3160
  label: "Backdrop color",
3052
3161
  defaultValue: (_b = data.backdropColor) != null ? _b : "#F5F5F5",
3053
3162
  onChange: (backdropColor) => updateData(__spreadProps(__spreadValues({}, data), { backdropColor }))
3054
3163
  }
3055
- ), /* @__PURE__ */ React60.createElement(
3164
+ ), /* @__PURE__ */ React58.createElement(
3056
3165
  ColorInput2,
3057
3166
  {
3058
3167
  label: "Canvas color",
3059
3168
  defaultValue: (_c = data.canvasColor) != null ? _c : "#FFFFFF",
3060
3169
  onChange: (canvasColor) => updateData(__spreadProps(__spreadValues({}, data), { canvasColor }))
3061
3170
  }
3062
- ), /* @__PURE__ */ React60.createElement(
3171
+ ), /* @__PURE__ */ React58.createElement(
3063
3172
  NullableColorInput,
3064
3173
  {
3065
3174
  label: "Canvas border color",
3066
3175
  defaultValue: (_d = data.borderColor) != null ? _d : null,
3067
3176
  onChange: (borderColor) => updateData(__spreadProps(__spreadValues({}, data), { borderColor }))
3068
3177
  }
3069
- ), /* @__PURE__ */ React60.createElement(
3178
+ ), /* @__PURE__ */ React58.createElement(
3070
3179
  SliderInput,
3071
3180
  {
3072
- iconLabel: /* @__PURE__ */ React60.createElement(RoundedCornerOutlined, null),
3181
+ iconLabel: /* @__PURE__ */ React58.createElement(RoundedCornerOutlined, null),
3073
3182
  units: "px",
3074
3183
  step: 4,
3075
3184
  marks: true,
@@ -3079,14 +3188,14 @@ function EmailLayoutSidebarFields({ data, setData }) {
3079
3188
  defaultValue: (_e = data.borderRadius) != null ? _e : 0,
3080
3189
  onChange: (borderRadius) => updateData(__spreadProps(__spreadValues({}, data), { borderRadius }))
3081
3190
  }
3082
- )), /* @__PURE__ */ React60.createElement(
3191
+ )), /* @__PURE__ */ React58.createElement(
3083
3192
  NullableFontFamily,
3084
3193
  {
3085
3194
  label: "Font family",
3086
3195
  defaultValue: "MODERN_SANS",
3087
3196
  onChange: (fontFamily) => updateData(__spreadProps(__spreadValues({}, data), { fontFamily }))
3088
3197
  }
3089
- ), /* @__PURE__ */ React60.createElement(
3198
+ ), /* @__PURE__ */ React58.createElement(
3090
3199
  ColorInput2,
3091
3200
  {
3092
3201
  label: "Text color",
@@ -3107,7 +3216,7 @@ function HeadingSidebarPanel({ data, setData }) {
3107
3216
  setErrors(res.error);
3108
3217
  }
3109
3218
  };
3110
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Heading block" }, /* @__PURE__ */ React60.createElement(
3219
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Heading block" }, /* @__PURE__ */ React58.createElement(
3111
3220
  TextInput,
3112
3221
  {
3113
3222
  label: "Content",
@@ -3117,7 +3226,7 @@ function HeadingSidebarPanel({ data, setData }) {
3117
3226
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { text }) }));
3118
3227
  }
3119
3228
  }
3120
- ), /* @__PURE__ */ React60.createElement(
3229
+ ), /* @__PURE__ */ React58.createElement(
3121
3230
  RadioGroupInput,
3122
3231
  {
3123
3232
  label: "Level",
@@ -3126,13 +3235,22 @@ function HeadingSidebarPanel({ data, setData }) {
3126
3235
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { level }) }));
3127
3236
  }
3128
3237
  },
3129
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "h1" }, "H1"),
3130
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "h2" }, "H2"),
3131
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "h3" }, "H3")
3132
- ), /* @__PURE__ */ React60.createElement(
3238
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "h1" }, "H1"),
3239
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "h2" }, "H2"),
3240
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "h3" }, "H3")
3241
+ ), /* @__PURE__ */ React58.createElement(
3133
3242
  MultiStylePropertyPanel,
3134
3243
  {
3135
- names: ["color", "backgroundColor", "fontFamily", "fontWeight", "textAlign", "padding"],
3244
+ names: [
3245
+ "color",
3246
+ "backgroundColor",
3247
+ "fontFamily",
3248
+ "fontWeight",
3249
+ "lineHeight",
3250
+ "letterSpacing",
3251
+ "textAlign",
3252
+ "padding"
3253
+ ],
3136
3254
  value: data.style,
3137
3255
  onChange: (style) => updateData(__spreadProps(__spreadValues({}, data), { style }))
3138
3256
  }
@@ -3150,7 +3268,7 @@ function HtmlSidebarPanel({ data, setData }) {
3150
3268
  setErrors(res.error);
3151
3269
  }
3152
3270
  };
3153
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Html block" }, /* @__PURE__ */ React60.createElement(
3271
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Html block" }, /* @__PURE__ */ React58.createElement(
3154
3272
  TextInput,
3155
3273
  {
3156
3274
  label: "Content",
@@ -3158,7 +3276,7 @@ function HtmlSidebarPanel({ data, setData }) {
3158
3276
  defaultValue: (_b = (_a = data.props) == null ? void 0 : _a.contents) != null ? _b : "",
3159
3277
  onChange: (contents) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { contents }) }))
3160
3278
  }
3161
- ), /* @__PURE__ */ React60.createElement(
3279
+ ), /* @__PURE__ */ React58.createElement(
3162
3280
  MultiStylePropertyPanel,
3163
3281
  {
3164
3282
  names: ["color", "backgroundColor", "fontFamily", "fontSize", "textAlign", "padding"],
@@ -3167,9 +3285,160 @@ function HtmlSidebarPanel({ data, setData }) {
3167
3285
  }
3168
3286
  ));
3169
3287
  }
3288
+ function ImageLibraryDialog({ open, onClose, onPick }) {
3289
+ const { loadImages, deleteImage } = useImageCallbacks();
3290
+ const [images, setImages] = useState(null);
3291
+ const [error, setError] = useState(null);
3292
+ const [query, setQuery] = useState("");
3293
+ const [busy, setBusy] = useState(false);
3294
+ const refresh = () => __async(null, null, function* () {
3295
+ if (!loadImages) return;
3296
+ setBusy(true);
3297
+ setError(null);
3298
+ try {
3299
+ const list = yield loadImages();
3300
+ setImages(list);
3301
+ } catch (e) {
3302
+ setError(e instanceof Error ? e.message : "Failed to load images");
3303
+ } finally {
3304
+ setBusy(false);
3305
+ }
3306
+ });
3307
+ useEffect(() => {
3308
+ if (open) {
3309
+ setQuery("");
3310
+ void refresh();
3311
+ }
3312
+ }, [open]);
3313
+ const filtered = useMemo(() => {
3314
+ if (!images) return null;
3315
+ const q = query.trim().toLowerCase();
3316
+ if (!q) return images;
3317
+ return images.filter((img) => {
3318
+ var _a;
3319
+ const haystack = `${(_a = img.alt) != null ? _a : ""} ${img.url}`.toLowerCase();
3320
+ return haystack.includes(q);
3321
+ });
3322
+ }, [images, query]);
3323
+ const handleDelete = (url) => __async(null, null, function* () {
3324
+ if (!deleteImage) return;
3325
+ const ok = window.confirm("Delete this image from the library?");
3326
+ if (!ok) return;
3327
+ setBusy(true);
3328
+ try {
3329
+ yield deleteImage(url);
3330
+ yield refresh();
3331
+ } catch (e) {
3332
+ setError(e instanceof Error ? e.message : "Failed to delete image");
3333
+ setBusy(false);
3334
+ }
3335
+ });
3336
+ return /* @__PURE__ */ React58.createElement(Dialog, { open, onClose, maxWidth: "md", fullWidth: true }, /* @__PURE__ */ React58.createElement(DialogTitle, null, "Image library"), /* @__PURE__ */ React58.createElement(DialogContent, { dividers: true }, /* @__PURE__ */ React58.createElement(
3337
+ TextField,
3338
+ {
3339
+ fullWidth: true,
3340
+ size: "small",
3341
+ placeholder: "Search by alt text or URL",
3342
+ value: query,
3343
+ onChange: (e) => setQuery(e.target.value),
3344
+ autoFocus: true,
3345
+ InputProps: {
3346
+ startAdornment: /* @__PURE__ */ React58.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React58.createElement(SearchOutlined, { fontSize: "small" }))
3347
+ },
3348
+ sx: { mb: 2 }
3349
+ }
3350
+ ), error && /* @__PURE__ */ React58.createElement(Alert, { severity: "error", sx: { mb: 2 } }, error), busy && !images && /* @__PURE__ */ React58.createElement(Stack, { alignItems: "center", sx: { py: 4 } }, /* @__PURE__ */ React58.createElement(CircularProgress, { size: 28 })), filtered && filtered.length === 0 && /* @__PURE__ */ React58.createElement(Typography, { variant: "body2", sx: { color: "text.secondary", textAlign: "center", py: 4 } }, query ? "No images match your search." : "No images in the library yet."), filtered && filtered.length > 0 && /* @__PURE__ */ React58.createElement(
3351
+ Box,
3352
+ {
3353
+ sx: {
3354
+ display: "grid",
3355
+ gridTemplateColumns: "repeat(auto-fill, minmax(140px, 1fr))",
3356
+ gap: 1.5
3357
+ }
3358
+ },
3359
+ filtered.map((img) => /* @__PURE__ */ React58.createElement(
3360
+ ImageTile,
3361
+ {
3362
+ key: img.url,
3363
+ image: img,
3364
+ onPick: () => onPick(img),
3365
+ onDelete: deleteImage ? () => handleDelete(img.url) : void 0
3366
+ }
3367
+ ))
3368
+ )), /* @__PURE__ */ React58.createElement(DialogActions, null, /* @__PURE__ */ React58.createElement(Button$1, { onClick: onClose }, "Close")));
3369
+ }
3370
+ function ImageTile({
3371
+ image,
3372
+ onPick,
3373
+ onDelete
3374
+ }) {
3375
+ var _a, _b;
3376
+ const src = (_a = image.thumbnailUrl) != null ? _a : image.url;
3377
+ const label = image.alt || image.url.split("/").pop() || "image";
3378
+ return /* @__PURE__ */ React58.createElement(
3379
+ Box,
3380
+ {
3381
+ sx: {
3382
+ position: "relative",
3383
+ borderRadius: 1,
3384
+ border: 1,
3385
+ borderColor: "divider",
3386
+ overflow: "hidden",
3387
+ cursor: "pointer",
3388
+ transition: "border-color 120ms",
3389
+ "&:hover": { borderColor: "primary.main" },
3390
+ "&:hover .delete-btn": { opacity: 1 }
3391
+ },
3392
+ onClick: onPick
3393
+ },
3394
+ /* @__PURE__ */ React58.createElement(
3395
+ Box,
3396
+ {
3397
+ component: "img",
3398
+ src,
3399
+ alt: (_b = image.alt) != null ? _b : "",
3400
+ sx: { display: "block", width: "100%", aspectRatio: "1 / 1", objectFit: "cover", backgroundColor: "#f5f5f5" }
3401
+ }
3402
+ ),
3403
+ /* @__PURE__ */ React58.createElement(Box, { sx: { p: 0.75, fontSize: 11, color: "text.secondary", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, label),
3404
+ onDelete && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Delete from library" }, /* @__PURE__ */ React58.createElement(
3405
+ IconButton,
3406
+ {
3407
+ size: "small",
3408
+ className: "delete-btn",
3409
+ onClick: (e) => {
3410
+ e.stopPropagation();
3411
+ onDelete();
3412
+ },
3413
+ sx: {
3414
+ position: "absolute",
3415
+ top: 4,
3416
+ right: 4,
3417
+ opacity: 0,
3418
+ backgroundColor: "rgba(255,255,255,0.85)",
3419
+ transition: "opacity 120ms",
3420
+ "&:hover": { backgroundColor: "rgba(255,255,255,0.95)" }
3421
+ },
3422
+ "aria-label": "Delete image"
3423
+ },
3424
+ /* @__PURE__ */ React58.createElement(DeleteOutline, { fontSize: "small" })
3425
+ ))
3426
+ );
3427
+ }
3428
+
3429
+ // src/app/inspector-drawer/configuration-panel/input-panels/image-sidebar-panel.tsx
3430
+ function isHttpUrl(value) {
3431
+ if (!value) return false;
3432
+ return /^http:\/\//i.test(value.trim());
3433
+ }
3170
3434
  function ImageSidebarPanel({ data, setData }) {
3171
3435
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3172
3436
  const [, setErrors] = useState(null);
3437
+ const { uploadImage, loadImages } = useImageCallbacks();
3438
+ const fileInputRef = useRef(null);
3439
+ const [uploading, setUploading] = useState(false);
3440
+ const [uploadError, setUploadError] = useState(null);
3441
+ const [libraryOpen, setLibraryOpen] = useState(false);
3173
3442
  const updateData = (d) => {
3174
3443
  const res = ImagePropsSchema.safeParse(d);
3175
3444
  if (res.success) {
@@ -3179,24 +3448,88 @@ function ImageSidebarPanel({ data, setData }) {
3179
3448
  setErrors(res.error);
3180
3449
  }
3181
3450
  };
3182
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Image block" }, /* @__PURE__ */ React60.createElement(
3451
+ const applyUploadedImage = (uploaded) => {
3452
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2;
3453
+ updateData(__spreadProps(__spreadValues({}, data), {
3454
+ props: __spreadProps(__spreadValues({}, data.props), {
3455
+ url: uploaded.url,
3456
+ width: (_c2 = (_b2 = uploaded.width) != null ? _b2 : (_a2 = data.props) == null ? void 0 : _a2.width) != null ? _c2 : null,
3457
+ height: (_f2 = (_e2 = uploaded.height) != null ? _e2 : (_d2 = data.props) == null ? void 0 : _d2.height) != null ? _f2 : null,
3458
+ alt: (_i2 = (_h2 = uploaded.alt) != null ? _h2 : (_g2 = data.props) == null ? void 0 : _g2.alt) != null ? _i2 : ""
3459
+ })
3460
+ }));
3461
+ };
3462
+ const handleFile = (file) => __async(null, null, function* () {
3463
+ if (!uploadImage) return;
3464
+ setUploading(true);
3465
+ setUploadError(null);
3466
+ try {
3467
+ const uploaded = yield uploadImage(file);
3468
+ applyUploadedImage(uploaded);
3469
+ } catch (e) {
3470
+ setUploadError(e instanceof Error ? e.message : "Upload failed");
3471
+ } finally {
3472
+ setUploading(false);
3473
+ }
3474
+ });
3475
+ const url = (_b = (_a = data.props) == null ? void 0 : _a.url) != null ? _b : "";
3476
+ const showHttpWarning = isHttpUrl(url);
3477
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Image block" }, (uploadImage || loadImages) && /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 1 }, uploadImage && /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
3478
+ Button$1,
3479
+ {
3480
+ fullWidth: true,
3481
+ variant: "outlined",
3482
+ size: "small",
3483
+ startIcon: uploading ? /* @__PURE__ */ React58.createElement(CircularProgress, { size: 14 }) : /* @__PURE__ */ React58.createElement(CloudUploadOutlined, { fontSize: "small" }),
3484
+ disabled: uploading,
3485
+ onClick: () => {
3486
+ var _a2;
3487
+ return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
3488
+ }
3489
+ },
3490
+ uploading ? "Uploading\u2026" : "Upload"
3491
+ ), /* @__PURE__ */ React58.createElement(
3492
+ "input",
3493
+ {
3494
+ ref: fileInputRef,
3495
+ type: "file",
3496
+ accept: "image/*",
3497
+ hidden: true,
3498
+ onChange: (e) => __async(null, null, function* () {
3499
+ var _a2;
3500
+ const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
3501
+ e.target.value = "";
3502
+ if (file) yield handleFile(file);
3503
+ })
3504
+ }
3505
+ )), loadImages && /* @__PURE__ */ React58.createElement(
3506
+ Button$1,
3507
+ {
3508
+ fullWidth: true,
3509
+ variant: "outlined",
3510
+ size: "small",
3511
+ startIcon: /* @__PURE__ */ React58.createElement(CollectionsOutlined, { fontSize: "small" }),
3512
+ onClick: () => setLibraryOpen(true)
3513
+ },
3514
+ "Library"
3515
+ )), uploadError && /* @__PURE__ */ React58.createElement(Alert, { severity: "error", onClose: () => setUploadError(null), sx: { mt: 1 } }, uploadError), /* @__PURE__ */ React58.createElement(
3183
3516
  TextInput,
3184
3517
  {
3185
3518
  label: "Source URL",
3186
- defaultValue: (_b = (_a = data.props) == null ? void 0 : _a.url) != null ? _b : "",
3519
+ defaultValue: url,
3187
3520
  onChange: (v) => {
3188
- const url = v.trim().length === 0 ? null : v.trim();
3189
- updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { url }) }));
3521
+ const next = v.trim().length === 0 ? null : v.trim();
3522
+ updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { url: next }) }));
3190
3523
  }
3191
3524
  }
3192
- ), /* @__PURE__ */ React60.createElement(
3525
+ ), showHttpWarning && /* @__PURE__ */ React58.createElement(Box, { sx: { mt: -1, mb: 1, display: "flex", alignItems: "flex-start", gap: 0.75 } }, /* @__PURE__ */ React58.createElement(ErrorOutlineOutlined, { fontSize: "small", sx: { color: "warning.main", mt: "2px" } }), /* @__PURE__ */ React58.createElement(Box, { sx: { fontSize: 12, color: "warning.dark" } }, "Non-HTTPS URL: Gmail and other clients strip mixed content. Use https:// for reliable delivery.")), /* @__PURE__ */ React58.createElement(
3193
3526
  TextInput,
3194
3527
  {
3195
3528
  label: "Alt text",
3196
3529
  defaultValue: (_d = (_c = data.props) == null ? void 0 : _c.alt) != null ? _d : "",
3197
3530
  onChange: (alt) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { alt }) }))
3198
3531
  }
3199
- ), /* @__PURE__ */ React60.createElement(
3532
+ ), /* @__PURE__ */ React58.createElement(
3200
3533
  TextInput,
3201
3534
  {
3202
3535
  label: "Click through URL",
@@ -3206,37 +3539,47 @@ function ImageSidebarPanel({ data, setData }) {
3206
3539
  updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { linkHref }) }));
3207
3540
  }
3208
3541
  }
3209
- ), /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ React60.createElement(
3542
+ ), /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ React58.createElement(
3210
3543
  TextDimensionInput,
3211
3544
  {
3212
3545
  label: "Width",
3213
3546
  defaultValue: (_g = data.props) == null ? void 0 : _g.width,
3214
3547
  onChange: (width) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { width }) }))
3215
3548
  }
3216
- ), /* @__PURE__ */ React60.createElement(
3549
+ ), /* @__PURE__ */ React58.createElement(
3217
3550
  TextDimensionInput,
3218
3551
  {
3219
3552
  label: "Height",
3220
3553
  defaultValue: (_h = data.props) == null ? void 0 : _h.height,
3221
3554
  onChange: (height) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { height }) }))
3222
3555
  }
3223
- )), /* @__PURE__ */ React60.createElement(
3556
+ )), /* @__PURE__ */ React58.createElement(
3224
3557
  RadioGroupInput,
3225
3558
  {
3226
3559
  label: "Alignment",
3227
3560
  defaultValue: (_j = (_i = data.props) == null ? void 0 : _i.contentAlignment) != null ? _j : "middle",
3228
3561
  onChange: (contentAlignment) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { contentAlignment }) }))
3229
3562
  },
3230
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "top" }, /* @__PURE__ */ React60.createElement(VerticalAlignTopOutlined, { fontSize: "small" })),
3231
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "middle" }, /* @__PURE__ */ React60.createElement(VerticalAlignCenterOutlined, { fontSize: "small" })),
3232
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "bottom" }, /* @__PURE__ */ React60.createElement(VerticalAlignBottomOutlined, { fontSize: "small" }))
3233
- ), /* @__PURE__ */ React60.createElement(
3563
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "top" }, /* @__PURE__ */ React58.createElement(VerticalAlignTopOutlined, { fontSize: "small" })),
3564
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "middle" }, /* @__PURE__ */ React58.createElement(VerticalAlignCenterOutlined, { fontSize: "small" })),
3565
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "bottom" }, /* @__PURE__ */ React58.createElement(VerticalAlignBottomOutlined, { fontSize: "small" }))
3566
+ ), /* @__PURE__ */ React58.createElement(
3234
3567
  MultiStylePropertyPanel,
3235
3568
  {
3236
3569
  names: ["backgroundColor", "textAlign", "padding"],
3237
3570
  value: data.style,
3238
3571
  onChange: (style) => updateData(__spreadProps(__spreadValues({}, data), { style }))
3239
3572
  }
3573
+ ), loadImages && /* @__PURE__ */ React58.createElement(
3574
+ ImageLibraryDialog,
3575
+ {
3576
+ open: libraryOpen,
3577
+ onClose: () => setLibraryOpen(false),
3578
+ onPick: (image) => {
3579
+ applyUploadedImage(image);
3580
+ setLibraryOpen(false);
3581
+ }
3582
+ }
3240
3583
  ));
3241
3584
  }
3242
3585
  function SignatureSidebarPanel({ data, setData }) {
@@ -3266,74 +3609,74 @@ function SignatureSidebarPanel({ data, setData }) {
3266
3609
  const nameColor = (_z = (_y = data.props) == null ? void 0 : _y.nameColor) != null ? _z : SignaturePropsDefaults.nameColor;
3267
3610
  const textColor = (_B = (_A = data.props) == null ? void 0 : _A.textColor) != null ? _B : SignaturePropsDefaults.textColor;
3268
3611
  const linkColor = (_D = (_C = data.props) == null ? void 0 : _C.linkColor) != null ? _D : SignaturePropsDefaults.linkColor;
3269
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Signature block" }, /* @__PURE__ */ React60.createElement(
3612
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Signature block" }, /* @__PURE__ */ React58.createElement(
3270
3613
  TextInput,
3271
3614
  {
3272
3615
  label: "Greeting",
3273
3616
  defaultValue: greeting,
3274
3617
  onChange: (greeting2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { greeting: greeting2 }) }))
3275
3618
  }
3276
- ), /* @__PURE__ */ React60.createElement(
3619
+ ), /* @__PURE__ */ React58.createElement(
3277
3620
  TextInput,
3278
3621
  {
3279
3622
  label: "Name",
3280
3623
  defaultValue: name,
3281
3624
  onChange: (name2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { name: name2 }) }))
3282
3625
  }
3283
- ), /* @__PURE__ */ React60.createElement(
3626
+ ), /* @__PURE__ */ React58.createElement(
3284
3627
  TextInput,
3285
3628
  {
3286
3629
  label: "Title",
3287
3630
  defaultValue: title,
3288
3631
  onChange: (title2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { title: title2 }) }))
3289
3632
  }
3290
- ), /* @__PURE__ */ React60.createElement(
3633
+ ), /* @__PURE__ */ React58.createElement(
3291
3634
  TextInput,
3292
3635
  {
3293
3636
  label: "Company",
3294
3637
  defaultValue: company,
3295
3638
  onChange: (company2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { company: company2 }) }))
3296
3639
  }
3297
- ), /* @__PURE__ */ React60.createElement(
3640
+ ), /* @__PURE__ */ React58.createElement(
3298
3641
  TextInput,
3299
3642
  {
3300
3643
  label: "Address",
3301
3644
  defaultValue: address,
3302
3645
  onChange: (address2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { address: address2 }) }))
3303
3646
  }
3304
- ), /* @__PURE__ */ React60.createElement(
3647
+ ), /* @__PURE__ */ React58.createElement(
3305
3648
  TextInput,
3306
3649
  {
3307
3650
  label: "Email",
3308
3651
  defaultValue: email,
3309
3652
  onChange: (email2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { email: email2 }) }))
3310
3653
  }
3311
- ), /* @__PURE__ */ React60.createElement(
3654
+ ), /* @__PURE__ */ React58.createElement(
3312
3655
  TextInput,
3313
3656
  {
3314
3657
  label: "Phone",
3315
3658
  defaultValue: phone,
3316
3659
  onChange: (phone2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { phone: phone2 }) }))
3317
3660
  }
3318
- ), /* @__PURE__ */ React60.createElement(
3661
+ ), /* @__PURE__ */ React58.createElement(
3319
3662
  TextInput,
3320
3663
  {
3321
3664
  label: "Website",
3322
3665
  defaultValue: website,
3323
3666
  onChange: (website2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { website: website2 }) }))
3324
3667
  }
3325
- ), /* @__PURE__ */ React60.createElement(
3668
+ ), /* @__PURE__ */ React58.createElement(
3326
3669
  TextInput,
3327
3670
  {
3328
3671
  label: "Image URL",
3329
3672
  defaultValue: imageUrl,
3330
3673
  onChange: (imageUrl2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { imageUrl: imageUrl2 }) }))
3331
3674
  }
3332
- ), /* @__PURE__ */ React60.createElement(
3675
+ ), /* @__PURE__ */ React58.createElement(
3333
3676
  SliderInput,
3334
3677
  {
3335
3678
  label: "Image size",
3336
- iconLabel: /* @__PURE__ */ React60.createElement(AspectRatioOutlined, { sx: { color: "text.secondary" } }),
3679
+ iconLabel: /* @__PURE__ */ React58.createElement(AspectRatioOutlined, { sx: { color: "text.secondary" } }),
3337
3680
  units: "px",
3338
3681
  step: 4,
3339
3682
  min: 32,
@@ -3341,47 +3684,47 @@ function SignatureSidebarPanel({ data, setData }) {
3341
3684
  defaultValue: imageSize,
3342
3685
  onChange: (imageSize2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { imageSize: imageSize2 }) }))
3343
3686
  }
3344
- ), /* @__PURE__ */ React60.createElement(
3687
+ ), /* @__PURE__ */ React58.createElement(
3345
3688
  RadioGroupInput,
3346
3689
  {
3347
3690
  label: "Image shape",
3348
3691
  defaultValue: imageShape,
3349
3692
  onChange: (imageShape2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { imageShape: imageShape2 }) }))
3350
3693
  },
3351
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "circle" }, "Circle"),
3352
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "square" }, "Square"),
3353
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "rounded" }, "Rounded")
3354
- ), /* @__PURE__ */ React60.createElement(
3694
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "circle" }, "Circle"),
3695
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "square" }, "Square"),
3696
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "rounded" }, "Rounded")
3697
+ ), /* @__PURE__ */ React58.createElement(
3355
3698
  RadioGroupInput,
3356
3699
  {
3357
3700
  label: "Layout",
3358
3701
  defaultValue: layout,
3359
3702
  onChange: (layout2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { layout: layout2 }) }))
3360
3703
  },
3361
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "horizontal" }, "Horizontal"),
3362
- /* @__PURE__ */ React60.createElement(ToggleButton, { value: "vertical" }, "Vertical")
3363
- ), /* @__PURE__ */ React60.createElement(
3704
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "horizontal" }, "Horizontal"),
3705
+ /* @__PURE__ */ React58.createElement(ToggleButton, { value: "vertical" }, "Vertical")
3706
+ ), /* @__PURE__ */ React58.createElement(
3364
3707
  ColorInput2,
3365
3708
  {
3366
3709
  label: "Name color",
3367
3710
  defaultValue: nameColor,
3368
3711
  onChange: (nameColor2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { nameColor: nameColor2 }) }))
3369
3712
  }
3370
- ), /* @__PURE__ */ React60.createElement(
3713
+ ), /* @__PURE__ */ React58.createElement(
3371
3714
  ColorInput2,
3372
3715
  {
3373
3716
  label: "Text color",
3374
3717
  defaultValue: textColor,
3375
3718
  onChange: (textColor2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { textColor: textColor2 }) }))
3376
3719
  }
3377
- ), /* @__PURE__ */ React60.createElement(
3720
+ ), /* @__PURE__ */ React58.createElement(
3378
3721
  ColorInput2,
3379
3722
  {
3380
3723
  label: "Link color",
3381
3724
  defaultValue: linkColor,
3382
3725
  onChange: (linkColor2) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { linkColor: linkColor2 }) }))
3383
3726
  }
3384
- ), /* @__PURE__ */ React60.createElement(
3727
+ ), /* @__PURE__ */ React58.createElement(
3385
3728
  MultiStylePropertyPanel,
3386
3729
  {
3387
3730
  names: ["backgroundColor", "fontFamily", "padding"],
@@ -3402,11 +3745,11 @@ function SpacerSidebarPanel({ data, setData }) {
3402
3745
  setErrors(res.error);
3403
3746
  }
3404
3747
  };
3405
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Spacer block" }, /* @__PURE__ */ React60.createElement(
3748
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Spacer block" }, /* @__PURE__ */ React58.createElement(
3406
3749
  SliderInput,
3407
3750
  {
3408
3751
  label: "Height",
3409
- iconLabel: /* @__PURE__ */ React60.createElement(HeightOutlined, { sx: { color: "text.secondary" } }),
3752
+ iconLabel: /* @__PURE__ */ React58.createElement(HeightOutlined, { sx: { color: "text.secondary" } }),
3410
3753
  units: "px",
3411
3754
  step: 4,
3412
3755
  min: 4,
@@ -3428,7 +3771,7 @@ function TextSidebarPanel({ data, setData }) {
3428
3771
  setErrors(res.error);
3429
3772
  }
3430
3773
  };
3431
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Text block" }, /* @__PURE__ */ React60.createElement(
3774
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Text block" }, /* @__PURE__ */ React58.createElement(
3432
3775
  TextInput,
3433
3776
  {
3434
3777
  label: "Content",
@@ -3436,17 +3779,27 @@ function TextSidebarPanel({ data, setData }) {
3436
3779
  defaultValue: (_b = (_a = data.props) == null ? void 0 : _a.text) != null ? _b : "",
3437
3780
  onChange: (text) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { text }) }))
3438
3781
  }
3439
- ), /* @__PURE__ */ React60.createElement(
3782
+ ), /* @__PURE__ */ React58.createElement(
3440
3783
  BooleanInput,
3441
3784
  {
3442
3785
  label: "Markdown",
3443
3786
  defaultValue: (_d = (_c = data.props) == null ? void 0 : _c.markdown) != null ? _d : false,
3444
3787
  onChange: (markdown) => updateData(__spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, data.props), { markdown }) }))
3445
3788
  }
3446
- ), /* @__PURE__ */ React60.createElement(
3789
+ ), /* @__PURE__ */ React58.createElement(
3447
3790
  MultiStylePropertyPanel,
3448
3791
  {
3449
- names: ["color", "backgroundColor", "fontFamily", "fontSize", "fontWeight", "textAlign", "padding"],
3792
+ names: [
3793
+ "color",
3794
+ "backgroundColor",
3795
+ "fontFamily",
3796
+ "fontSize",
3797
+ "fontWeight",
3798
+ "lineHeight",
3799
+ "letterSpacing",
3800
+ "textAlign",
3801
+ "padding"
3802
+ ],
3450
3803
  value: data.style,
3451
3804
  onChange: (style) => updateData(__spreadProps(__spreadValues({}, data), { style }))
3452
3805
  }
@@ -3455,7 +3808,7 @@ function TextSidebarPanel({ data, setData }) {
3455
3808
 
3456
3809
  // src/app/inspector-drawer/configuration-panel/index.tsx
3457
3810
  function renderMessage(val) {
3458
- return /* @__PURE__ */ React60.createElement(Box, { sx: { m: 3, p: 1, border: "1px dashed", borderColor: "divider" } }, /* @__PURE__ */ React60.createElement(Typography, { color: "text.secondary" }, val));
3811
+ return /* @__PURE__ */ React58.createElement(Box, { sx: { m: 3, p: 1, border: "1px dashed", borderColor: "divider" } }, /* @__PURE__ */ React58.createElement(Typography, { color: "text.secondary" }, val));
3459
3812
  }
3460
3813
  function ConfigurationPanel() {
3461
3814
  const document2 = useDocument();
@@ -3471,55 +3824,55 @@ function ConfigurationPanel() {
3471
3824
  const { data, type } = block;
3472
3825
  switch (type) {
3473
3826
  case "Avatar":
3474
- return /* @__PURE__ */ React60.createElement(AvatarSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3827
+ return /* @__PURE__ */ React58.createElement(AvatarSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3475
3828
  case "Button":
3476
- return /* @__PURE__ */ React60.createElement(ButtonSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3829
+ return /* @__PURE__ */ React58.createElement(ButtonSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3477
3830
  case "ColumnsContainer":
3478
- return /* @__PURE__ */ React60.createElement(ColumnsContainerPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3831
+ return /* @__PURE__ */ React58.createElement(ColumnsContainerPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3479
3832
  case "Container":
3480
- return /* @__PURE__ */ React60.createElement(ContainerSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3833
+ return /* @__PURE__ */ React58.createElement(ContainerSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3481
3834
  case "Divider":
3482
- return /* @__PURE__ */ React60.createElement(DividerSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3835
+ return /* @__PURE__ */ React58.createElement(DividerSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3483
3836
  case "Heading":
3484
- return /* @__PURE__ */ React60.createElement(HeadingSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3837
+ return /* @__PURE__ */ React58.createElement(HeadingSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3485
3838
  case "Html":
3486
- return /* @__PURE__ */ React60.createElement(HtmlSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3839
+ return /* @__PURE__ */ React58.createElement(HtmlSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3487
3840
  case "Image":
3488
- return /* @__PURE__ */ React60.createElement(ImageSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3841
+ return /* @__PURE__ */ React58.createElement(ImageSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3489
3842
  case "EmailLayout":
3490
- return /* @__PURE__ */ React60.createElement(EmailLayoutSidebarFields, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3843
+ return /* @__PURE__ */ React58.createElement(EmailLayoutSidebarFields, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3491
3844
  case "Spacer":
3492
- return /* @__PURE__ */ React60.createElement(SpacerSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3845
+ return /* @__PURE__ */ React58.createElement(SpacerSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3493
3846
  case "Signature":
3494
- return /* @__PURE__ */ React60.createElement(SignatureSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3847
+ return /* @__PURE__ */ React58.createElement(SignatureSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3495
3848
  case "Text":
3496
- return /* @__PURE__ */ React60.createElement(TextSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3849
+ return /* @__PURE__ */ React58.createElement(TextSidebarPanel, { key: selectedBlockId, data, setData: (data2) => setBlock({ type, data: data2 }) });
3497
3850
  default:
3498
- return /* @__PURE__ */ React60.createElement("pre", null, JSON.stringify(block, null, " "));
3851
+ return /* @__PURE__ */ React58.createElement("pre", null, JSON.stringify(block, null, " "));
3499
3852
  }
3500
3853
  }
3501
3854
  function StylesPanel() {
3502
3855
  const block = useDocument().root;
3503
3856
  if (!block) {
3504
- return /* @__PURE__ */ React60.createElement("p", null, "Block not found");
3857
+ return /* @__PURE__ */ React58.createElement("p", null, "Block not found");
3505
3858
  }
3506
3859
  const { data, type } = block;
3507
3860
  if (type !== "EmailLayout") {
3508
3861
  throw new Error('Expected "root" element to be of type EmailLayout');
3509
3862
  }
3510
- return /* @__PURE__ */ React60.createElement(EmailLayoutSidebarFields, { key: "root", data, setData: (data2) => setDocument({ root: { type, data: data2 } }) });
3863
+ return /* @__PURE__ */ React58.createElement(EmailLayoutSidebarFields, { key: "root", data, setData: (data2) => setDocument({ root: { type, data: data2 } }) });
3511
3864
  }
3512
3865
  function TemplateDownloadButton() {
3513
3866
  const doc = useDocument();
3514
3867
  const href = useMemo(() => {
3515
3868
  return `data:text/plain,${encodeURIComponent(JSON.stringify(doc, null, " "))}`;
3516
3869
  }, [doc]);
3517
- return /* @__PURE__ */ React60.createElement(
3870
+ return /* @__PURE__ */ React58.createElement(
3518
3871
  Button$1,
3519
3872
  {
3520
3873
  variant: "outlined",
3521
3874
  color: "primary",
3522
- startIcon: /* @__PURE__ */ React60.createElement(FileDownloadOutlined, null),
3875
+ startIcon: /* @__PURE__ */ React58.createElement(FileDownloadOutlined, null),
3523
3876
  href,
3524
3877
  download: "emailTemplate.json",
3525
3878
  fullWidth: true
@@ -3551,9 +3904,9 @@ function TemplatePanel({ deleteTemplate, copyTemplate }) {
3551
3904
  }
3552
3905
  };
3553
3906
  if (!currentTemplateId) {
3554
- return /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Template" }, "No template selected");
3907
+ return /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Template" }, "No template selected");
3555
3908
  }
3556
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Template" }, /* @__PURE__ */ React60.createElement(Stack, { spacing: 2 }, !persistenceEnabled && /* @__PURE__ */ React60.createElement(
3909
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Template" }, /* @__PURE__ */ React58.createElement(Stack, { spacing: 2 }, !persistenceEnabled && /* @__PURE__ */ React58.createElement(
3557
3910
  Typography,
3558
3911
  {
3559
3912
  variant: "body2",
@@ -3566,110 +3919,449 @@ function TemplatePanel({ deleteTemplate, copyTemplate }) {
3566
3919
  }
3567
3920
  },
3568
3921
  "Save functionality is disabled. To enable saving, provide the necessary callback functions."
3569
- ), persistenceEnabled && /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
3922
+ ), persistenceEnabled && /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
3570
3923
  Button$1,
3571
3924
  {
3572
3925
  variant: "outlined",
3573
3926
  color: "primary",
3574
- startIcon: /* @__PURE__ */ React60.createElement(ContentCopyOutlined, null),
3927
+ startIcon: /* @__PURE__ */ React58.createElement(ContentCopyOutlined, null),
3575
3928
  onClick: handleCopyToSamples,
3576
3929
  fullWidth: true,
3577
3930
  disabled: !copyTemplate
3578
3931
  },
3579
3932
  "Save as Sample Template"
3580
- ), /* @__PURE__ */ React60.createElement(
3933
+ ), /* @__PURE__ */ React58.createElement(
3581
3934
  Button$1,
3582
3935
  {
3583
3936
  variant: "outlined",
3584
3937
  color: "error",
3585
- startIcon: /* @__PURE__ */ React60.createElement(DeleteOutlined, null),
3938
+ startIcon: /* @__PURE__ */ React58.createElement(DeleteOutlined, null),
3586
3939
  onClick: handleDelete,
3587
3940
  fullWidth: true,
3588
3941
  disabled: !deleteTemplate
3589
3942
  },
3590
3943
  "Delete Template"
3591
- )))), persistenceEnabled && /* @__PURE__ */ React60.createElement(BaseSidebarPanel, { title: "Export" }, /* @__PURE__ */ React60.createElement(Stack, { spacing: 2 }, /* @__PURE__ */ React60.createElement(TemplateDownloadButton, null))));
3944
+ )))), persistenceEnabled && /* @__PURE__ */ React58.createElement(BaseSidebarPanel, { title: "Export" }, /* @__PURE__ */ React58.createElement(Stack, { spacing: 2 }, /* @__PURE__ */ React58.createElement(TemplateDownloadButton, null))));
3592
3945
  }
3946
+
3947
+ // src/app/variables/variable-utils.ts
3593
3948
  var VARIABLE_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
3594
- function validateName(name, index, all) {
3595
- if (!name.trim()) return "Name is required";
3596
- if (!VARIABLE_NAME_RE.test(name)) return "Use letters, digits, underscore; start with a letter or underscore";
3597
- const duplicate = all.some((v, i) => i !== index && v.name === name);
3949
+ var MAX_VARIABLE_NAME_LENGTH = 64;
3950
+ var RESERVED_VARIABLE_NAMES = /* @__PURE__ */ new Set(["this", "true", "false", "null", "undefined"]);
3951
+ var HANDLEBARS_KEYWORDS = /* @__PURE__ */ new Set(["if", "each", "unless", "else", "with"]);
3952
+ function validateVariableName(name, siblings, indexBeingEdited) {
3953
+ const trimmed = name.trim();
3954
+ if (!trimmed) return "Name is required";
3955
+ if (trimmed.length > MAX_VARIABLE_NAME_LENGTH) return `Max ${MAX_VARIABLE_NAME_LENGTH} characters`;
3956
+ if (!VARIABLE_NAME_RE.test(trimmed)) return "Use letters, digits, underscore; start with a letter or underscore";
3957
+ if (RESERVED_VARIABLE_NAMES.has(trimmed)) return "Reserved word; pick another name";
3958
+ const duplicate = siblings.some((v, i) => i !== indexBeingEdited && v.name === trimmed);
3598
3959
  if (duplicate) return "Already declared";
3599
3960
  return null;
3600
3961
  }
3962
+ var TOKEN_ROOT_RE = /\{\{\s*(?:#(?:if|each|unless|with)\s+)?([a-zA-Z_][a-zA-Z0-9_]*)(?:\.[\w.]+)?\s*\}\}/g;
3963
+ function extractTokenRoots(text) {
3964
+ if (!text) return [];
3965
+ const roots = /* @__PURE__ */ new Set();
3966
+ for (const m of text.matchAll(TOKEN_ROOT_RE)) {
3967
+ const name = m[1];
3968
+ if (RESERVED_VARIABLE_NAMES.has(name) || HANDLEBARS_KEYWORDS.has(name)) continue;
3969
+ roots.add(name);
3970
+ }
3971
+ return [...roots];
3972
+ }
3973
+ function forEachTextFieldInDocument(doc, visit) {
3974
+ var _a, _b;
3975
+ const root = doc.root;
3976
+ if (root && root.type === "EmailLayout" && typeof ((_a = root.data) == null ? void 0 : _a.subject) === "string") {
3977
+ visit(root.data.subject);
3978
+ }
3979
+ for (const [id, block] of Object.entries(doc)) {
3980
+ if (id === "root" || !block || typeof block !== "object") continue;
3981
+ const type = block.type;
3982
+ const props = (_b = block.data) == null ? void 0 : _b.props;
3983
+ if (!props) continue;
3984
+ if ((type === "Text" || type === "Heading" || type === "Button") && typeof props.text === "string") {
3985
+ visit(props.text);
3986
+ } else if (type === "Html" && typeof props.contents === "string") {
3987
+ visit(props.contents);
3988
+ }
3989
+ }
3990
+ }
3991
+ function collectTokenUsage(doc) {
3992
+ const usage = /* @__PURE__ */ new Map();
3993
+ forEachTextFieldInDocument(doc, (value) => {
3994
+ var _a;
3995
+ for (const root of extractTokenRoots(value)) {
3996
+ usage.set(root, ((_a = usage.get(root)) != null ? _a : 0) + 1);
3997
+ }
3998
+ });
3999
+ return usage;
4000
+ }
4001
+ function escapeRegex(name) {
4002
+ return name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4003
+ }
4004
+ function buildRenameReplacers(oldName, newName) {
4005
+ const esc = escapeRegex(oldName);
4006
+ const simple = new RegExp(`\\{\\{\\s*${esc}(\\.[\\w.]+)?\\s*\\}\\}`, "g");
4007
+ const helper = new RegExp(`(\\{\\{\\s*#(?:if|each|unless|with)\\s+)${esc}(\\.[\\w.]+)?(\\s*\\}\\})`, "g");
4008
+ return (text) => text.replace(helper, `$1${newName}$2$3`).replace(simple, `{{${newName}$1}}`);
4009
+ }
4010
+ function buildRenamePatch(doc, oldName, newName) {
4011
+ var _a;
4012
+ if (oldName === newName) return {};
4013
+ const rewrite = buildRenameReplacers(oldName, newName);
4014
+ const patch = {};
4015
+ const root = doc.root;
4016
+ if (root && root.type === "EmailLayout") {
4017
+ const layoutData = root.data;
4018
+ const oldSubject = (_a = layoutData.subject) != null ? _a : "";
4019
+ const newSubject = rewrite(oldSubject);
4020
+ if (newSubject !== oldSubject) {
4021
+ patch.root = __spreadProps(__spreadValues({}, root), { data: __spreadProps(__spreadValues({}, layoutData), { subject: newSubject }) });
4022
+ }
4023
+ }
4024
+ for (const [id, block] of Object.entries(doc)) {
4025
+ if (id === "root" || !block || typeof block !== "object") continue;
4026
+ const type = block.type;
4027
+ const data = block.data;
4028
+ const props = data == null ? void 0 : data.props;
4029
+ if (!props) continue;
4030
+ if ((type === "Text" || type === "Heading" || type === "Button") && typeof props.text === "string") {
4031
+ const nextText = rewrite(props.text);
4032
+ if (nextText !== props.text) {
4033
+ patch[id] = __spreadProps(__spreadValues({}, block), { data: __spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, props), { text: nextText }) }) });
4034
+ }
4035
+ } else if (type === "Html" && typeof props.contents === "string") {
4036
+ const nextContents = rewrite(props.contents);
4037
+ if (nextContents !== props.contents) {
4038
+ patch[id] = __spreadProps(__spreadValues({}, block), { data: __spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, props), { contents: nextContents }) }) });
4039
+ }
4040
+ }
4041
+ }
4042
+ return patch;
4043
+ }
4044
+ function substituteSampleValues(text, samples) {
4045
+ if (!text) return text;
4046
+ let out = text;
4047
+ out = out.replace(
4048
+ /\{\{\s*#(?:if|each|unless|with)\s+[^}]*\}\}/g,
4049
+ ""
4050
+ );
4051
+ out = out.replace(/\{\{\s*\/(?:if|each|unless|with)\s*\}\}/g, "");
4052
+ out = out.replace(/\{\{\s*else\s*\}\}/g, "");
4053
+ out = out.replace(TOKEN_ROOT_RE, (match, root) => {
4054
+ var _a;
4055
+ if (!samples.has(root)) return match;
4056
+ return (_a = samples.get(root)) != null ? _a : "";
4057
+ });
4058
+ return out;
4059
+ }
4060
+ function buildSampleValueMap(variables) {
4061
+ const m = /* @__PURE__ */ new Map();
4062
+ if (!variables) return m;
4063
+ for (const v of variables) {
4064
+ if (v.name && typeof v.sampleValue === "string" && v.sampleValue.length > 0) {
4065
+ m.set(v.name, v.sampleValue);
4066
+ }
4067
+ }
4068
+ return m;
4069
+ }
4070
+ function applySampleValuesToDocument(doc, samples) {
4071
+ if (samples.size === 0) return doc;
4072
+ const next = __spreadValues({}, doc);
4073
+ const root = doc.root;
4074
+ if (root && root.type === "EmailLayout") {
4075
+ const layoutData = root.data;
4076
+ if (typeof layoutData.subject === "string") {
4077
+ const newSubject = substituteSampleValues(layoutData.subject, samples);
4078
+ if (newSubject !== layoutData.subject) {
4079
+ next.root = __spreadProps(__spreadValues({}, root), { data: __spreadProps(__spreadValues({}, layoutData), { subject: newSubject }) });
4080
+ }
4081
+ }
4082
+ }
4083
+ for (const [id, block] of Object.entries(doc)) {
4084
+ if (id === "root" || !block || typeof block !== "object") continue;
4085
+ const type = block.type;
4086
+ const data = block.data;
4087
+ const props = data == null ? void 0 : data.props;
4088
+ if (!props) continue;
4089
+ if ((type === "Text" || type === "Heading" || type === "Button") && typeof props.text === "string") {
4090
+ const newText = substituteSampleValues(props.text, samples);
4091
+ if (newText !== props.text) {
4092
+ next[id] = __spreadProps(__spreadValues({}, block), { data: __spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, props), { text: newText }) }) });
4093
+ }
4094
+ } else if (type === "Html" && typeof props.contents === "string") {
4095
+ const newContents = substituteSampleValues(props.contents, samples);
4096
+ if (newContents !== props.contents) {
4097
+ next[id] = __spreadProps(__spreadValues({}, block), { data: __spreadProps(__spreadValues({}, data), { props: __spreadProps(__spreadValues({}, props), { contents: newContents }) }) });
4098
+ }
4099
+ }
4100
+ }
4101
+ return next;
4102
+ }
4103
+
4104
+ // src/app/inspector-drawer/variables-panel.tsx
4105
+ function toPersistShape(v) {
4106
+ return {
4107
+ name: v.name,
4108
+ description: v.description ? v.description : void 0,
4109
+ sampleValue: v.sampleValue ? v.sampleValue : void 0
4110
+ };
4111
+ }
3601
4112
  function VariablesPanel() {
3602
4113
  var _a;
3603
4114
  const document2 = useDocument();
4115
+ const lastFocused = useLastFocusedEditable();
3604
4116
  const root = document2.root;
3605
4117
  if (!root || root.type !== "EmailLayout") {
3606
- return /* @__PURE__ */ React60.createElement(Box, { p: 2 }, /* @__PURE__ */ React60.createElement(Alert, { severity: "info" }, "Open a template to manage variables."));
4118
+ return /* @__PURE__ */ React58.createElement(Box, { p: 2 }, /* @__PURE__ */ React58.createElement(Alert, { severity: "info" }, "Open a template to manage variables."));
3607
4119
  }
3608
4120
  const data = root.data;
3609
4121
  const variables = ((_a = data.variables) != null ? _a : []).map((v) => {
3610
- var _a2;
4122
+ var _a2, _b;
3611
4123
  return {
3612
4124
  name: v.name,
3613
- description: (_a2 = v.description) != null ? _a2 : ""
4125
+ description: (_a2 = v.description) != null ? _a2 : "",
4126
+ sampleValue: (_b = v.sampleValue) != null ? _b : ""
3614
4127
  };
3615
4128
  });
3616
- const commit = (next) => {
3617
- setDocument({
3618
- root: __spreadProps(__spreadValues({}, root), {
3619
- data: __spreadProps(__spreadValues({}, data), {
3620
- variables: next.map((v) => ({
3621
- name: v.name,
3622
- description: v.description ? v.description : void 0
3623
- }))
3624
- })
4129
+ const usage = useMemo(() => collectTokenUsage(document2), [document2]);
4130
+ const declaredNames = useMemo(() => new Set(variables.map((v) => v.name)), [variables]);
4131
+ const undeclared = useMemo(
4132
+ () => [...usage.keys()].filter((n) => n && !declaredNames.has(n)),
4133
+ [usage, declaredNames]
4134
+ );
4135
+ const writeVariables = (next, extraPatch = {}) => {
4136
+ var _a2;
4137
+ const baseRoot = (_a2 = extraPatch.root) != null ? _a2 : root;
4138
+ const newRoot = __spreadProps(__spreadValues({}, baseRoot), {
4139
+ data: __spreadProps(__spreadValues({}, baseRoot.data), {
4140
+ variables: next.map(toPersistShape)
3625
4141
  })
3626
4142
  });
4143
+ setDocument(__spreadProps(__spreadValues({}, extraPatch), { root: newRoot }));
3627
4144
  };
3628
4145
  const updateAt = (index, patch) => {
3629
4146
  const next = variables.map((v, i) => i === index ? __spreadValues(__spreadValues({}, v), patch) : v);
3630
- commit(next);
4147
+ writeVariables(next);
3631
4148
  };
3632
4149
  const add = () => {
3633
- commit([...variables, { name: "", description: "" }]);
4150
+ writeVariables([...variables, { name: "", description: "", sampleValue: "" }]);
4151
+ };
4152
+ const addFromToken = (name) => {
4153
+ writeVariables([...variables, { name, description: "", sampleValue: "" }]);
3634
4154
  };
3635
4155
  const removeAt = (index) => {
3636
- commit(variables.filter((_, i) => i !== index));
4156
+ var _a2;
4157
+ const v = variables[index];
4158
+ const usageCount = v.name ? (_a2 = usage.get(v.name)) != null ? _a2 : 0 : 0;
4159
+ if (usageCount > 0) {
4160
+ const ok = window.confirm(
4161
+ `"${v.name}" is still referenced in the body (${usageCount} occurrence${usageCount === 1 ? "" : "s"}). Delete anyway?`
4162
+ );
4163
+ if (!ok) return;
4164
+ }
4165
+ writeVariables(variables.filter((_, i) => i !== index));
4166
+ };
4167
+ const commitRename = (index, newName) => {
4168
+ const oldName = variables[index].name;
4169
+ const trimmed = newName.trim();
4170
+ if (trimmed === oldName) return;
4171
+ const error = validateVariableName(trimmed, variables, index);
4172
+ if (error) return;
4173
+ const patch = oldName ? buildRenamePatch(document2, oldName, trimmed) : {};
4174
+ const next = variables.map((v, i) => i === index ? __spreadProps(__spreadValues({}, v), { name: trimmed }) : v);
4175
+ writeVariables(next, patch);
4176
+ };
4177
+ const canInsert = Boolean(
4178
+ lastFocused && (lastFocused.field === "subject" || lastFocused.blockId && document2[lastFocused.blockId])
4179
+ );
4180
+ const insertIntoFocused = (name) => {
4181
+ var _a2, _b, _c;
4182
+ const focused = getLastFocusedEditable();
4183
+ if (!focused) return;
4184
+ const token = `{{${name}}}`;
4185
+ if (focused.field === "subject") {
4186
+ const layoutData = root.data;
4187
+ const current2 = (_a2 = layoutData.subject) != null ? _a2 : "";
4188
+ const next2 = current2.slice(0, focused.selectionStart) + token + current2.slice(focused.selectionEnd);
4189
+ setDocument({
4190
+ root: __spreadProps(__spreadValues({}, root), { data: __spreadProps(__spreadValues({}, layoutData), { subject: next2 }) })
4191
+ });
4192
+ return;
4193
+ }
4194
+ const block = document2[focused.blockId];
4195
+ if (!block) return;
4196
+ const blockData = block.data;
4197
+ const props = (_b = blockData == null ? void 0 : blockData.props) != null ? _b : {};
4198
+ const field = focused.field;
4199
+ const current = (_c = props[field]) != null ? _c : "";
4200
+ const next = current.slice(0, focused.selectionStart) + token + current.slice(focused.selectionEnd);
4201
+ setDocument({
4202
+ [focused.blockId]: __spreadProps(__spreadValues({}, block), {
4203
+ data: __spreadProps(__spreadValues({}, blockData), { props: __spreadProps(__spreadValues({}, props), { [field]: next }) })
4204
+ })
4205
+ });
3637
4206
  };
3638
- return /* @__PURE__ */ React60.createElement(Box, { p: 2 }, /* @__PURE__ */ React60.createElement(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { mb: 1 } }, /* @__PURE__ */ React60.createElement(Typography, { variant: "subtitle1", sx: { fontWeight: 600 } }, "Variables"), /* @__PURE__ */ React60.createElement(Tooltip, { title: "Add variable" }, /* @__PURE__ */ React60.createElement(IconButton, { size: "small", onClick: add, "aria-label": "Add variable" }, /* @__PURE__ */ React60.createElement(AddOutlined, { fontSize: "small" })))), /* @__PURE__ */ React60.createElement(Typography, { variant: "caption", sx: { color: "text.secondary", display: "block", mb: 2 } }, "Declared variables travel with the template. Reference them in subject and body as", " ", /* @__PURE__ */ React60.createElement(Box, { component: "code", sx: { fontFamily: "monospace" } }, "{{name}}"), "."), variables.length === 0 ? /* @__PURE__ */ React60.createElement(Typography, { variant: "body2", sx: { color: "text.secondary" } }, "No variables declared. Click + to add one.") : /* @__PURE__ */ React60.createElement(Stack, { spacing: 2 }, variables.map((v, i) => {
4207
+ const copy = (name) => __async(null, null, function* () {
4208
+ try {
4209
+ yield navigator.clipboard.writeText(`{{${name}}}`);
4210
+ } catch (e) {
4211
+ }
4212
+ });
4213
+ return /* @__PURE__ */ React58.createElement(Box, { p: 2 }, /* @__PURE__ */ React58.createElement(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { mb: 1 } }, /* @__PURE__ */ React58.createElement(Typography, { variant: "subtitle1", sx: { fontWeight: 600 } }, "Variables"), /* @__PURE__ */ React58.createElement(Tooltip, { title: "Add variable" }, /* @__PURE__ */ React58.createElement(IconButton, { size: "small", onClick: add, "aria-label": "Add variable" }, /* @__PURE__ */ React58.createElement(AddOutlined, { fontSize: "small" })))), /* @__PURE__ */ React58.createElement(Typography, { variant: "caption", sx: { color: "text.secondary", display: "block", mb: 2 } }, "Declared variables travel with the template. Reference them in subject and body as", " ", /* @__PURE__ */ React58.createElement(Box, { component: "code", sx: { fontFamily: "monospace" } }, "{{name}}"), ". In Preview mode, tokens render with the sample values below."), undeclared.length > 0 && /* @__PURE__ */ React58.createElement(Alert, { severity: "warning", sx: { mb: 2 } }, /* @__PURE__ */ React58.createElement(AlertTitle, { sx: { fontSize: 13 } }, "Undeclared in body"), /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 0.5, useFlexGap: true, flexWrap: "wrap" }, undeclared.map((name) => /* @__PURE__ */ React58.createElement(
4214
+ Chip,
4215
+ {
4216
+ key: name,
4217
+ size: "small",
4218
+ label: name,
4219
+ onClick: () => addFromToken(name),
4220
+ onDelete: () => addFromToken(name),
4221
+ deleteIcon: /* @__PURE__ */ React58.createElement(AddOutlined, null),
4222
+ sx: { fontFamily: "monospace" }
4223
+ }
4224
+ ))), /* @__PURE__ */ React58.createElement(Typography, { variant: "caption", sx: { color: "text.secondary", display: "block", mt: 0.5 } }, "Click a token to declare it.")), variables.length === 0 ? /* @__PURE__ */ React58.createElement(Typography, { variant: "body2", sx: { color: "text.secondary" } }, "No variables declared. Click + to add one.") : /* @__PURE__ */ React58.createElement(Stack, { spacing: 2 }, variables.map((v, i) => {
3639
4225
  var _a2;
3640
- const nameError = validateName(v.name, i, variables);
3641
- return /* @__PURE__ */ React60.createElement(Stack, { key: i, spacing: 0.75, sx: { pb: 1, borderBottom: 1, borderColor: "divider" } }, /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React60.createElement(
3642
- TextField,
4226
+ return /* @__PURE__ */ React58.createElement(
4227
+ VariableRow,
3643
4228
  {
3644
- label: "Name",
3645
- size: "small",
3646
- fullWidth: true,
3647
- value: v.name,
3648
- onChange: (e) => updateAt(i, { name: e.target.value }),
3649
- error: Boolean(nameError),
3650
- helperText: nameError != null ? nameError : " "
4229
+ key: i,
4230
+ index: i,
4231
+ variable: v,
4232
+ siblings: variables,
4233
+ usageCount: v.name ? (_a2 = usage.get(v.name)) != null ? _a2 : 0 : 0,
4234
+ canInsert,
4235
+ onCommitRename: (name) => commitRename(i, name),
4236
+ onChangeDescription: (description) => updateAt(i, { description }),
4237
+ onChangeSampleValue: (sampleValue) => updateAt(i, { sampleValue }),
4238
+ onRemove: () => removeAt(i),
4239
+ onInsert: () => v.name && insertIntoFocused(v.name),
4240
+ onCopy: () => v.name && copy(v.name)
3651
4241
  }
3652
- ), /* @__PURE__ */ React60.createElement(Tooltip, { title: "Remove" }, /* @__PURE__ */ React60.createElement(
3653
- IconButton,
3654
- {
3655
- size: "small",
3656
- onClick: () => removeAt(i),
3657
- "aria-label": `Remove ${v.name || "variable"}`,
3658
- sx: { mt: 0.5 }
4242
+ );
4243
+ })));
4244
+ }
4245
+ function VariableRow({
4246
+ index,
4247
+ variable,
4248
+ siblings,
4249
+ usageCount,
4250
+ canInsert,
4251
+ onCommitRename,
4252
+ onChangeDescription,
4253
+ onChangeSampleValue,
4254
+ onRemove,
4255
+ onInsert,
4256
+ onCopy
4257
+ }) {
4258
+ var _a, _b;
4259
+ const [draftName, setDraftName] = useState(variable.name);
4260
+ const [isEditing, setIsEditing] = useState(false);
4261
+ useEffect(() => {
4262
+ if (!isEditing) setDraftName(variable.name);
4263
+ }, [variable.name, isEditing]);
4264
+ const nameError = validateVariableName(draftName, siblings, index);
4265
+ const unused = Boolean(variable.name) && usageCount === 0;
4266
+ const hasName = Boolean(variable.name);
4267
+ const commit = () => {
4268
+ setIsEditing(false);
4269
+ if (nameError) {
4270
+ setDraftName(variable.name);
4271
+ return;
4272
+ }
4273
+ if (draftName.trim() !== variable.name) {
4274
+ onCommitRename(draftName.trim());
4275
+ }
4276
+ };
4277
+ return /* @__PURE__ */ React58.createElement(Stack, { spacing: 0.75, sx: { pb: 1, borderBottom: 1, borderColor: "divider" } }, /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58.createElement(
4278
+ TextField,
4279
+ {
4280
+ label: "Name",
4281
+ size: "small",
4282
+ fullWidth: true,
4283
+ value: draftName,
4284
+ onChange: (e) => {
4285
+ setDraftName(e.target.value);
4286
+ setIsEditing(true);
3659
4287
  },
3660
- /* @__PURE__ */ React60.createElement(DeleteOutline, { fontSize: "small" })
3661
- ))), /* @__PURE__ */ React60.createElement(
3662
- TextField,
3663
- {
3664
- label: "Description",
3665
- size: "small",
3666
- fullWidth: true,
3667
- value: (_a2 = v.description) != null ? _a2 : "",
3668
- onChange: (e) => updateAt(i, { description: e.target.value }),
3669
- placeholder: "Optional"
4288
+ onFocus: () => setIsEditing(true),
4289
+ onBlur: commit,
4290
+ onKeyDown: (e) => {
4291
+ if (e.key === "Enter") {
4292
+ e.target.blur();
4293
+ } else if (e.key === "Escape") {
4294
+ setDraftName(variable.name);
4295
+ setIsEditing(false);
4296
+ e.target.blur();
4297
+ }
4298
+ },
4299
+ error: Boolean(nameError),
4300
+ helperText: nameError != null ? nameError : " "
4301
+ }
4302
+ ), /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 0.25, sx: { mt: 0.5 } }, /* @__PURE__ */ React58.createElement(Tooltip, { title: "Copy {{name}}" }, /* @__PURE__ */ React58.createElement("span", null, /* @__PURE__ */ React58.createElement(
4303
+ IconButton,
4304
+ {
4305
+ size: "small",
4306
+ onClick: onCopy,
4307
+ disabled: !hasName,
4308
+ "aria-label": `Copy ${variable.name || "variable"} token`
4309
+ },
4310
+ /* @__PURE__ */ React58.createElement(ContentCopyOutlined, { fontSize: "small" })
4311
+ ))), /* @__PURE__ */ React58.createElement(Tooltip, { title: canInsert ? "Insert at cursor" : "Focus a text field first" }, /* @__PURE__ */ React58.createElement("span", null, /* @__PURE__ */ React58.createElement(
4312
+ IconButton,
4313
+ {
4314
+ size: "small",
4315
+ onClick: onInsert,
4316
+ disabled: !hasName || !canInsert,
4317
+ "aria-label": `Insert ${variable.name || "variable"} at cursor`
4318
+ },
4319
+ /* @__PURE__ */ React58.createElement(InputOutlined, { fontSize: "small" })
4320
+ ))), /* @__PURE__ */ React58.createElement(Tooltip, { title: "Remove" }, /* @__PURE__ */ React58.createElement(
4321
+ IconButton,
4322
+ {
4323
+ size: "small",
4324
+ onClick: onRemove,
4325
+ "aria-label": `Remove ${variable.name || "variable"}`
4326
+ },
4327
+ /* @__PURE__ */ React58.createElement(DeleteOutline, { fontSize: "small" })
4328
+ )))), /* @__PURE__ */ React58.createElement(
4329
+ TextField,
4330
+ {
4331
+ label: "Description",
4332
+ size: "small",
4333
+ fullWidth: true,
4334
+ value: (_a = variable.description) != null ? _a : "",
4335
+ onChange: (e) => onChangeDescription(e.target.value),
4336
+ placeholder: "Optional"
4337
+ }
4338
+ ), /* @__PURE__ */ React58.createElement(
4339
+ TextField,
4340
+ {
4341
+ label: "Sample value",
4342
+ size: "small",
4343
+ fullWidth: true,
4344
+ value: (_b = variable.sampleValue) != null ? _b : "",
4345
+ onChange: (e) => onChangeSampleValue(e.target.value),
4346
+ placeholder: "Shown in Preview mode",
4347
+ InputProps: {
4348
+ startAdornment: /* @__PURE__ */ React58.createElement(
4349
+ DataObjectOutlined,
4350
+ {
4351
+ fontSize: "small",
4352
+ sx: { color: "text.secondary", mr: 0.75 }
4353
+ }
4354
+ )
3670
4355
  }
3671
- ));
3672
- })));
4356
+ }
4357
+ ), /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 0.5, sx: { pt: 0.25 } }, hasName && (unused ? /* @__PURE__ */ React58.createElement(Chip, { size: "small", color: "warning", variant: "outlined", label: "Unused in body" }) : /* @__PURE__ */ React58.createElement(
4358
+ Chip,
4359
+ {
4360
+ size: "small",
4361
+ variant: "outlined",
4362
+ label: `${usageCount} ref${usageCount === 1 ? "" : "s"}`
4363
+ }
4364
+ ))));
3673
4365
  }
3674
4366
 
3675
4367
  // src/app/inspector-drawer/index.tsx
@@ -3686,13 +4378,13 @@ function InspectorDrawer({
3686
4378
  const renderCurrentSidebarPanel = () => {
3687
4379
  switch (selectedSidebarTab) {
3688
4380
  case "block-configuration":
3689
- return /* @__PURE__ */ React60.createElement(ConfigurationPanel, null);
4381
+ return /* @__PURE__ */ React58.createElement(ConfigurationPanel, null);
3690
4382
  case "styles":
3691
- return /* @__PURE__ */ React60.createElement(StylesPanel, null);
4383
+ return /* @__PURE__ */ React58.createElement(StylesPanel, null);
3692
4384
  case "variables":
3693
- return /* @__PURE__ */ React60.createElement(VariablesPanel, null);
4385
+ return /* @__PURE__ */ React58.createElement(VariablesPanel, null);
3694
4386
  case "template-settings":
3695
- return /* @__PURE__ */ React60.createElement(
4387
+ return /* @__PURE__ */ React58.createElement(
3696
4388
  TemplatePanel,
3697
4389
  {
3698
4390
  deleteTemplate,
@@ -3701,7 +4393,7 @@ function InspectorDrawer({
3701
4393
  );
3702
4394
  }
3703
4395
  };
3704
- return /* @__PURE__ */ React60.createElement(
4396
+ return /* @__PURE__ */ React58.createElement(
3705
4397
  Drawer,
3706
4398
  {
3707
4399
  variant: "persistent",
@@ -3723,7 +4415,7 @@ function InspectorDrawer({
3723
4415
  width: inspectorDrawerOpen ? INSPECTOR_DRAWER_WIDTH : 0
3724
4416
  }
3725
4417
  },
3726
- /* @__PURE__ */ React60.createElement(Box, { sx: { width: INSPECTOR_DRAWER_WIDTH, height: 49, borderBottom: 1, borderColor: "divider" } }, /* @__PURE__ */ React60.createElement(Box, { px: 1 }, /* @__PURE__ */ React60.createElement(
4418
+ /* @__PURE__ */ React58.createElement(Box, { sx: { width: INSPECTOR_DRAWER_WIDTH, height: 49, borderBottom: 1, borderColor: "divider" } }, /* @__PURE__ */ React58.createElement(Box, { px: 1 }, /* @__PURE__ */ React58.createElement(
3727
4419
  Tabs,
3728
4420
  {
3729
4421
  value: selectedSidebarTab,
@@ -3731,12 +4423,12 @@ function InspectorDrawer({
3731
4423
  variant: "fullWidth",
3732
4424
  sx: { "& .MuiTab-root": { minWidth: 0, px: 1, fontSize: 13 } }
3733
4425
  },
3734
- /* @__PURE__ */ React60.createElement(Tab, { value: "styles", label: "Styles" }),
3735
- /* @__PURE__ */ React60.createElement(Tab, { value: "block-configuration", label: "Inspect" }),
3736
- /* @__PURE__ */ React60.createElement(Tab, { value: "variables", label: "Variables" }),
3737
- /* @__PURE__ */ React60.createElement(Tab, { value: "template-settings", label: "Settings" })
4426
+ /* @__PURE__ */ React58.createElement(Tab, { value: "styles", label: "Styles" }),
4427
+ /* @__PURE__ */ React58.createElement(Tab, { value: "block-configuration", label: "Inspect" }),
4428
+ /* @__PURE__ */ React58.createElement(Tab, { value: "variables", label: "Variables" }),
4429
+ /* @__PURE__ */ React58.createElement(Tab, { value: "template-settings", label: "Settings" })
3738
4430
  ))),
3739
- /* @__PURE__ */ React60.createElement(Box, { sx: { width: INSPECTOR_DRAWER_WIDTH, height: "calc(100% - 49px)", overflow: "auto" } }, renderCurrentSidebarPanel())
4431
+ /* @__PURE__ */ React58.createElement(Box, { sx: { width: INSPECTOR_DRAWER_WIDTH, height: "calc(100% - 49px)", overflow: "auto" } }, renderCurrentSidebarPanel())
3740
4432
  );
3741
4433
  }
3742
4434
  var SnackbarContext = createContext(null);
@@ -3757,7 +4449,7 @@ function SnackbarProvider({ children }) {
3757
4449
  const handleClose = () => {
3758
4450
  setMessage(null);
3759
4451
  };
3760
- return /* @__PURE__ */ React60.createElement(SnackbarContext.Provider, { value: { showMessage } }, children, /* @__PURE__ */ React60.createElement(
4452
+ return /* @__PURE__ */ React58.createElement(SnackbarContext.Provider, { value: { showMessage } }, children, /* @__PURE__ */ React58.createElement(
3761
4453
  Snackbar,
3762
4454
  {
3763
4455
  anchorOrigin: { vertical: "top", horizontal: "center" },
@@ -3823,7 +4515,7 @@ function TemplateRow({
3823
4515
  const hasActions = Boolean(
3824
4516
  onDuplicate || onRename || onDelete || onPromote || onDemote || onDuplicateAsTemplate
3825
4517
  );
3826
- return /* @__PURE__ */ React60.createElement(
4518
+ return /* @__PURE__ */ React58.createElement(
3827
4519
  Box,
3828
4520
  {
3829
4521
  role: "button",
@@ -3849,7 +4541,7 @@ function TemplateRow({
3849
4541
  "&:focus-visible": { outline: "2px solid", outlineColor: "primary.main" }
3850
4542
  }
3851
4543
  },
3852
- /* @__PURE__ */ React60.createElement(Stack, { direction: "row", alignItems: "flex-start", spacing: 1 }, /* @__PURE__ */ React60.createElement(Box, { sx: { flexGrow: 1, minWidth: 0 } }, /* @__PURE__ */ React60.createElement(Stack, { direction: "row", alignItems: "baseline", spacing: 1, sx: { minWidth: 0 } }, /* @__PURE__ */ React60.createElement(
4544
+ /* @__PURE__ */ React58.createElement(Stack, { direction: "row", alignItems: "flex-start", spacing: 1 }, /* @__PURE__ */ React58.createElement(Box, { sx: { flexGrow: 1, minWidth: 0 } }, /* @__PURE__ */ React58.createElement(Stack, { direction: "row", alignItems: "baseline", spacing: 1, sx: { minWidth: 0 } }, /* @__PURE__ */ React58.createElement(
3853
4545
  Typography,
3854
4546
  {
3855
4547
  variant: "body2",
@@ -3863,14 +4555,14 @@ function TemplateRow({
3863
4555
  title: template.slug
3864
4556
  },
3865
4557
  template.slug
3866
- ), updated && /* @__PURE__ */ React60.createElement(
4558
+ ), updated && /* @__PURE__ */ React58.createElement(
3867
4559
  Typography,
3868
4560
  {
3869
4561
  variant: "caption",
3870
4562
  sx: { color: "text.secondary", flexShrink: 0, fontSize: "0.7rem" }
3871
4563
  },
3872
4564
  updated
3873
- )), template.description && /* @__PURE__ */ React60.createElement(
4565
+ )), template.description && /* @__PURE__ */ React58.createElement(
3874
4566
  Typography,
3875
4567
  {
3876
4568
  variant: "caption",
@@ -3884,7 +4576,7 @@ function TemplateRow({
3884
4576
  }
3885
4577
  },
3886
4578
  template.description
3887
- ), template.tags && template.tags.length > 0 && /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 0.5, sx: { mt: 0.5, flexWrap: "wrap", gap: 0.5 } }, template.tags.map((tag) => /* @__PURE__ */ React60.createElement(
4579
+ ), template.tags && template.tags.length > 0 && /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 0.5, sx: { mt: 0.5, flexWrap: "wrap", gap: 0.5 } }, template.tags.map((tag) => /* @__PURE__ */ React58.createElement(
3888
4580
  Chip,
3889
4581
  {
3890
4582
  key: tag,
@@ -3893,7 +4585,7 @@ function TemplateRow({
3893
4585
  sx: { height: 18, fontSize: "0.65rem", "& .MuiChip-label": { px: 0.75 } }
3894
4586
  }
3895
4587
  ))))),
3896
- hasActions && hover && /* @__PURE__ */ React60.createElement(
4588
+ hasActions && hover && /* @__PURE__ */ React58.createElement(
3897
4589
  Stack,
3898
4590
  {
3899
4591
  direction: "row",
@@ -3909,7 +4601,7 @@ function TemplateRow({
3909
4601
  p: 0.25
3910
4602
  }
3911
4603
  },
3912
- onDuplicateAsTemplate && /* @__PURE__ */ React60.createElement(Tooltip, { title: "Duplicate as template" }, /* @__PURE__ */ React60.createElement(
4604
+ onDuplicateAsTemplate && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Duplicate as template" }, /* @__PURE__ */ React58.createElement(
3913
4605
  IconButton,
3914
4606
  {
3915
4607
  size: "small",
@@ -3918,9 +4610,9 @@ function TemplateRow({
3918
4610
  onDuplicateAsTemplate();
3919
4611
  }
3920
4612
  },
3921
- /* @__PURE__ */ React60.createElement(LibraryAddOutlined, { fontSize: "small" })
4613
+ /* @__PURE__ */ React58.createElement(LibraryAddOutlined, { fontSize: "small" })
3922
4614
  )),
3923
- onDuplicate && /* @__PURE__ */ React60.createElement(Tooltip, { title: "Duplicate" }, /* @__PURE__ */ React60.createElement(
4615
+ onDuplicate && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Duplicate" }, /* @__PURE__ */ React58.createElement(
3924
4616
  IconButton,
3925
4617
  {
3926
4618
  size: "small",
@@ -3929,9 +4621,9 @@ function TemplateRow({
3929
4621
  onDuplicate();
3930
4622
  }
3931
4623
  },
3932
- /* @__PURE__ */ React60.createElement(ContentCopyOutlined, { fontSize: "small" })
4624
+ /* @__PURE__ */ React58.createElement(ContentCopyOutlined, { fontSize: "small" })
3933
4625
  )),
3934
- onRename && /* @__PURE__ */ React60.createElement(Tooltip, { title: "Rename" }, /* @__PURE__ */ React60.createElement(
4626
+ onRename && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Rename" }, /* @__PURE__ */ React58.createElement(
3935
4627
  IconButton,
3936
4628
  {
3937
4629
  size: "small",
@@ -3940,9 +4632,9 @@ function TemplateRow({
3940
4632
  onRename();
3941
4633
  }
3942
4634
  },
3943
- /* @__PURE__ */ React60.createElement(DriveFileRenameOutlineOutlined, { fontSize: "small" })
4635
+ /* @__PURE__ */ React58.createElement(DriveFileRenameOutlineOutlined, { fontSize: "small" })
3944
4636
  )),
3945
- onPromote && /* @__PURE__ */ React60.createElement(Tooltip, { title: "Promote to sample" }, /* @__PURE__ */ React60.createElement(
4637
+ onPromote && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Promote to sample" }, /* @__PURE__ */ React58.createElement(
3946
4638
  IconButton,
3947
4639
  {
3948
4640
  size: "small",
@@ -3951,9 +4643,9 @@ function TemplateRow({
3951
4643
  onPromote();
3952
4644
  }
3953
4645
  },
3954
- /* @__PURE__ */ React60.createElement(FileUploadOutlined, { fontSize: "small" })
4646
+ /* @__PURE__ */ React58.createElement(FileUploadOutlined, { fontSize: "small" })
3955
4647
  )),
3956
- onDemote && /* @__PURE__ */ React60.createElement(Tooltip, { title: "Demote to template" }, /* @__PURE__ */ React60.createElement(
4648
+ onDemote && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Demote to template" }, /* @__PURE__ */ React58.createElement(
3957
4649
  IconButton,
3958
4650
  {
3959
4651
  size: "small",
@@ -3962,9 +4654,9 @@ function TemplateRow({
3962
4654
  onDemote();
3963
4655
  }
3964
4656
  },
3965
- /* @__PURE__ */ React60.createElement(FileDownloadOutlined, { fontSize: "small" })
4657
+ /* @__PURE__ */ React58.createElement(FileDownloadOutlined, { fontSize: "small" })
3966
4658
  )),
3967
- onDelete && /* @__PURE__ */ React60.createElement(Tooltip, { title: "Delete" }, /* @__PURE__ */ React60.createElement(
4659
+ onDelete && /* @__PURE__ */ React58.createElement(Tooltip, { title: "Delete" }, /* @__PURE__ */ React58.createElement(
3968
4660
  IconButton,
3969
4661
  {
3970
4662
  size: "small",
@@ -3973,7 +4665,7 @@ function TemplateRow({
3973
4665
  onDelete();
3974
4666
  }
3975
4667
  },
3976
- /* @__PURE__ */ React60.createElement(DeleteOutlined, { fontSize: "small" })
4668
+ /* @__PURE__ */ React58.createElement(DeleteOutlined, { fontSize: "small" })
3977
4669
  ))
3978
4670
  )
3979
4671
  );
@@ -4024,7 +4716,7 @@ function RenameDialog({
4024
4716
  setSubmitting(false);
4025
4717
  }
4026
4718
  });
4027
- return /* @__PURE__ */ React60.createElement(Dialog, { open, onClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React60.createElement(DialogTitle, null, "Rename template"), /* @__PURE__ */ React60.createElement(DialogContent, null, /* @__PURE__ */ React60.createElement(
4719
+ return /* @__PURE__ */ React58.createElement(Dialog, { open, onClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React58.createElement(DialogTitle, null, "Rename template"), /* @__PURE__ */ React58.createElement(DialogContent, null, /* @__PURE__ */ React58.createElement(
4028
4720
  TextField,
4029
4721
  {
4030
4722
  autoFocus: true,
@@ -4043,7 +4735,7 @@ function RenameDialog({
4043
4735
  }
4044
4736
  }
4045
4737
  }
4046
- )), /* @__PURE__ */ React60.createElement(DialogActions, null, /* @__PURE__ */ React60.createElement(Button$1, { onClick: onClose, disabled: submitting }, "Cancel"), /* @__PURE__ */ React60.createElement(
4738
+ )), /* @__PURE__ */ React58.createElement(DialogActions, null, /* @__PURE__ */ React58.createElement(Button$1, { onClick: onClose, disabled: submitting }, "Cancel"), /* @__PURE__ */ React58.createElement(
4047
4739
  Button$1,
4048
4740
  {
4049
4741
  onClick: handleSubmit,
@@ -4112,7 +4804,7 @@ function SaveTemplateDialog({
4112
4804
  setInternalError("");
4113
4805
  onClose();
4114
4806
  };
4115
- return /* @__PURE__ */ React60.createElement(
4807
+ return /* @__PURE__ */ React58.createElement(
4116
4808
  Dialog,
4117
4809
  {
4118
4810
  open,
@@ -4120,8 +4812,8 @@ function SaveTemplateDialog({
4120
4812
  maxWidth: "sm",
4121
4813
  fullWidth: true
4122
4814
  },
4123
- /* @__PURE__ */ React60.createElement(DialogTitle, null, "Save Email Template"),
4124
- /* @__PURE__ */ React60.createElement(DialogContent, null, /* @__PURE__ */ React60.createElement(Box, { sx: { pt: 1 } }, /* @__PURE__ */ React60.createElement(
4815
+ /* @__PURE__ */ React58.createElement(DialogTitle, null, "Save Email Template"),
4816
+ /* @__PURE__ */ React58.createElement(DialogContent, null, /* @__PURE__ */ React58.createElement(Box, { sx: { pt: 1 } }, /* @__PURE__ */ React58.createElement(
4125
4817
  TextField,
4126
4818
  {
4127
4819
  autoFocus: true,
@@ -4143,7 +4835,7 @@ function SaveTemplateDialog({
4143
4835
  disabled: isSubmitting
4144
4836
  }
4145
4837
  ))),
4146
- /* @__PURE__ */ React60.createElement(DialogActions, null, /* @__PURE__ */ React60.createElement(Button$1, { onClick: handleCancel, disabled: isSubmitting }, "Cancel"), /* @__PURE__ */ React60.createElement(
4838
+ /* @__PURE__ */ React58.createElement(DialogActions, null, /* @__PURE__ */ React58.createElement(Button$1, { onClick: handleCancel, disabled: isSubmitting }, "Cancel"), /* @__PURE__ */ React58.createElement(
4147
4839
  Button$1,
4148
4840
  {
4149
4841
  onClick: handleSave,
@@ -4409,7 +5101,7 @@ function SamplesDrawer({
4409
5101
  return null;
4410
5102
  }
4411
5103
  const existingSlugs = templates.map((t) => t.slug);
4412
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
5104
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
4413
5105
  Drawer,
4414
5106
  {
4415
5107
  variant: "persistent",
@@ -4424,7 +5116,7 @@ function SamplesDrawer({
4424
5116
  transitionDuration: { enter: enterDuration, exit: exitDuration },
4425
5117
  sx: { width: samplesDrawerOpen ? SAMPLES_DRAWER_WIDTH : 0 }
4426
5118
  },
4427
- /* @__PURE__ */ React60.createElement(
5119
+ /* @__PURE__ */ React58.createElement(
4428
5120
  Stack,
4429
5121
  {
4430
5122
  py: 1,
@@ -4434,16 +5126,16 @@ function SamplesDrawer({
4434
5126
  spacing: 1.5,
4435
5127
  sx: { overflowY: "auto" }
4436
5128
  },
4437
- /* @__PURE__ */ React60.createElement(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { pt: 1 } }, /* @__PURE__ */ React60.createElement(Typography, { variant: "h6", component: "h1" }, "Templates"), saveAs && /* @__PURE__ */ React60.createElement(Tooltip, { title: "New template" }, /* @__PURE__ */ React60.createElement(
5129
+ /* @__PURE__ */ React58.createElement(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { pt: 1 } }, /* @__PURE__ */ React58.createElement(Typography, { variant: "h6", component: "h1" }, "Templates"), saveAs && /* @__PURE__ */ React58.createElement(Tooltip, { title: "New template" }, /* @__PURE__ */ React58.createElement(
4438
5130
  IconButton,
4439
5131
  {
4440
5132
  size: "small",
4441
5133
  onClick: openNewTemplateDialog,
4442
5134
  "aria-label": "New template"
4443
5135
  },
4444
- /* @__PURE__ */ React60.createElement(AddOutlined, { fontSize: "small" })
5136
+ /* @__PURE__ */ React58.createElement(AddOutlined, { fontSize: "small" })
4445
5137
  ))),
4446
- loadTemplates && /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
5138
+ loadTemplates && /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
4447
5139
  TextField,
4448
5140
  {
4449
5141
  size: "small",
@@ -4451,10 +5143,10 @@ function SamplesDrawer({
4451
5143
  value: search,
4452
5144
  onChange: (e) => setSearch(e.target.value),
4453
5145
  InputProps: {
4454
- startAdornment: /* @__PURE__ */ React60.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React60.createElement(SearchOutlined, { fontSize: "small" }))
5146
+ startAdornment: /* @__PURE__ */ React58.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React58.createElement(SearchOutlined, { fontSize: "small" }))
4455
5147
  }
4456
5148
  }
4457
- ), /* @__PURE__ */ React60.createElement(
5149
+ ), /* @__PURE__ */ React58.createElement(
4458
5150
  TextField,
4459
5151
  {
4460
5152
  select: true,
@@ -4463,8 +5155,8 @@ function SamplesDrawer({
4463
5155
  value: sortKey,
4464
5156
  onChange: (e) => setSortKey(e.target.value)
4465
5157
  },
4466
- SORT_OPTIONS.map((opt) => /* @__PURE__ */ React60.createElement(MenuItem, { key: opt.value, value: opt.value }, opt.label))
4467
- ), allTags.length > 0 && /* @__PURE__ */ React60.createElement(Stack, { direction: "row", sx: { flexWrap: "wrap", gap: 0.5 } }, allTags.map((tag) => /* @__PURE__ */ React60.createElement(
5158
+ SORT_OPTIONS.map((opt) => /* @__PURE__ */ React58.createElement(MenuItem, { key: opt.value, value: opt.value }, opt.label))
5159
+ ), allTags.length > 0 && /* @__PURE__ */ React58.createElement(Stack, { direction: "row", sx: { flexWrap: "wrap", gap: 0.5 } }, allTags.map((tag) => /* @__PURE__ */ React58.createElement(
4468
5160
  Chip,
4469
5161
  {
4470
5162
  key: tag,
@@ -4475,7 +5167,7 @@ function SamplesDrawer({
4475
5167
  variant: activeTags.includes(tag) ? "filled" : "outlined",
4476
5168
  onClick: () => toggleTag(tag)
4477
5169
  }
4478
- ))), /* @__PURE__ */ React60.createElement(Box, null, /* @__PURE__ */ React60.createElement(Typography, { variant: "subtitle2", component: "h2", sx: { fontWeight: "bold", mb: 0.5 } }, "Your Templates"), loadingTemplates ? /* @__PURE__ */ React60.createElement(Stack, { alignItems: "center", width: "100%", py: 2 }, /* @__PURE__ */ React60.createElement(CircularProgress, { size: 24 })) : templatesError ? /* @__PURE__ */ React60.createElement(Alert, { severity: "error", sx: { my: 1 } }, templatesError) : filteredTemplates.length > 0 ? /* @__PURE__ */ React60.createElement(Stack, { spacing: 0.25, sx: { width: "100%" } }, filteredTemplates.map((template) => /* @__PURE__ */ React60.createElement(
5170
+ ))), /* @__PURE__ */ React58.createElement(Box, null, /* @__PURE__ */ React58.createElement(Typography, { variant: "subtitle2", component: "h2", sx: { fontWeight: "bold", mb: 0.5 } }, "Your Templates"), loadingTemplates ? /* @__PURE__ */ React58.createElement(Stack, { alignItems: "center", width: "100%", py: 2 }, /* @__PURE__ */ React58.createElement(CircularProgress, { size: 24 })) : templatesError ? /* @__PURE__ */ React58.createElement(Alert, { severity: "error", sx: { my: 1 } }, templatesError) : filteredTemplates.length > 0 ? /* @__PURE__ */ React58.createElement(Stack, { spacing: 0.25, sx: { width: "100%" } }, filteredTemplates.map((template) => /* @__PURE__ */ React58.createElement(
4479
5171
  TemplateRow,
4480
5172
  {
4481
5173
  key: template.id,
@@ -4487,8 +5179,8 @@ function SamplesDrawer({
4487
5179
  onDelete: deleteTemplate ? () => handleDelete(template) : void 0,
4488
5180
  onPromote: setTemplateKind ? () => handleSetKind(template, "sample") : void 0
4489
5181
  }
4490
- ))) : /* @__PURE__ */ React60.createElement(Typography, { variant: "body2", sx: { color: "text.secondary", py: 1 } }, templateRows.length === 0 ? "No saved templates yet" : "No templates match your filters")), /* @__PURE__ */ React60.createElement(Divider$1, null)),
4491
- /* @__PURE__ */ React60.createElement(Box, null, /* @__PURE__ */ React60.createElement(Typography, { variant: "subtitle2", component: "h2", sx: { fontWeight: "bold", mb: 0.5 } }, "Sample Templates"), loadingSamples ? /* @__PURE__ */ React60.createElement(Stack, { alignItems: "center", width: "100%", py: 2 }, /* @__PURE__ */ React60.createElement(CircularProgress, { size: 24 })) : sampleRows.length > 0 ? /* @__PURE__ */ React60.createElement(Stack, { spacing: 0.25, sx: { width: "100%" } }, sampleRows.map((sample) => /* @__PURE__ */ React60.createElement(
5182
+ ))) : /* @__PURE__ */ React58.createElement(Typography, { variant: "body2", sx: { color: "text.secondary", py: 1 } }, templateRows.length === 0 ? "No saved templates yet" : "No templates match your filters")), /* @__PURE__ */ React58.createElement(Divider$1, null)),
5183
+ /* @__PURE__ */ React58.createElement(Box, null, /* @__PURE__ */ React58.createElement(Typography, { variant: "subtitle2", component: "h2", sx: { fontWeight: "bold", mb: 0.5 } }, "Sample Templates"), loadingSamples ? /* @__PURE__ */ React58.createElement(Stack, { alignItems: "center", width: "100%", py: 2 }, /* @__PURE__ */ React58.createElement(CircularProgress, { size: 24 })) : sampleRows.length > 0 ? /* @__PURE__ */ React58.createElement(Stack, { spacing: 0.25, sx: { width: "100%" } }, sampleRows.map((sample) => /* @__PURE__ */ React58.createElement(
4492
5184
  TemplateRow,
4493
5185
  {
4494
5186
  key: sample.id,
@@ -4498,9 +5190,9 @@ function SamplesDrawer({
4498
5190
  onDuplicateAsTemplate: saveAs ? () => handleDuplicateAsTemplate(sample) : void 0,
4499
5191
  onDemote: setTemplateKind && sample.id !== "empty-email" ? () => handleSetKind(sample, "template") : void 0
4500
5192
  }
4501
- ))) : /* @__PURE__ */ React60.createElement(Typography, { variant: "body2", sx: { color: "text.secondary", py: 1 } }, "No samples available"))
5193
+ ))) : /* @__PURE__ */ React58.createElement(Typography, { variant: "body2", sx: { color: "text.secondary", py: 1 } }, "No samples available"))
4502
5194
  )
4503
- ), renameTarget && /* @__PURE__ */ React60.createElement(
5195
+ ), renameTarget && /* @__PURE__ */ React58.createElement(
4504
5196
  RenameDialog,
4505
5197
  {
4506
5198
  open: !!renameTarget,
@@ -4509,7 +5201,7 @@ function SamplesDrawer({
4509
5201
  onClose: () => setRenameTarget(null),
4510
5202
  onSubmit: handleRenameSubmit
4511
5203
  }
4512
- ), /* @__PURE__ */ React60.createElement(
5204
+ ), /* @__PURE__ */ React58.createElement(
4513
5205
  SaveTemplateDialog,
4514
5206
  {
4515
5207
  open: !!pendingSaveAs,
@@ -4536,7 +5228,7 @@ var ICON_SX = {
4536
5228
  borderColor: "cadet.300"
4537
5229
  };
4538
5230
  function BlockTypeButton({ label, icon, onClick }) {
4539
- return /* @__PURE__ */ React60.createElement(
5231
+ return /* @__PURE__ */ React58.createElement(
4540
5232
  Button$1,
4541
5233
  {
4542
5234
  sx: BUTTON_SX2,
@@ -4545,14 +5237,14 @@ function BlockTypeButton({ label, icon, onClick }) {
4545
5237
  onClick();
4546
5238
  }
4547
5239
  },
4548
- /* @__PURE__ */ React60.createElement(Box, { sx: ICON_SX }, icon),
4549
- /* @__PURE__ */ React60.createElement(Typography, { variant: "body2" }, label)
5240
+ /* @__PURE__ */ React58.createElement(Box, { sx: ICON_SX }, icon),
5241
+ /* @__PURE__ */ React58.createElement(Typography, { variant: "body2" }, label)
4550
5242
  );
4551
5243
  }
4552
5244
  var BUTTONS = [
4553
5245
  {
4554
5246
  label: "Heading",
4555
- icon: /* @__PURE__ */ React60.createElement(HMobiledataOutlined, null),
5247
+ icon: /* @__PURE__ */ React58.createElement(HMobiledataOutlined, null),
4556
5248
  block: () => ({
4557
5249
  type: "Heading",
4558
5250
  data: {
@@ -4565,7 +5257,7 @@ var BUTTONS = [
4565
5257
  },
4566
5258
  {
4567
5259
  label: "Text",
4568
- icon: /* @__PURE__ */ React60.createElement(NotesOutlined, null),
5260
+ icon: /* @__PURE__ */ React58.createElement(NotesOutlined, null),
4569
5261
  block: () => ({
4570
5262
  type: "Text",
4571
5263
  data: {
@@ -4579,7 +5271,7 @@ var BUTTONS = [
4579
5271
  },
4580
5272
  {
4581
5273
  label: "Button",
4582
- icon: /* @__PURE__ */ React60.createElement(SmartButtonOutlined, null),
5274
+ icon: /* @__PURE__ */ React58.createElement(SmartButtonOutlined, null),
4583
5275
  block: () => ({
4584
5276
  type: "Button",
4585
5277
  data: {
@@ -4593,7 +5285,7 @@ var BUTTONS = [
4593
5285
  },
4594
5286
  {
4595
5287
  label: "Image",
4596
- icon: /* @__PURE__ */ React60.createElement(ImageOutlined, null),
5288
+ icon: /* @__PURE__ */ React58.createElement(ImageOutlined, null),
4597
5289
  block: () => ({
4598
5290
  type: "Image",
4599
5291
  data: {
@@ -4609,7 +5301,7 @@ var BUTTONS = [
4609
5301
  },
4610
5302
  {
4611
5303
  label: "Avatar",
4612
- icon: /* @__PURE__ */ React60.createElement(AccountCircleOutlined, null),
5304
+ icon: /* @__PURE__ */ React58.createElement(AccountCircleOutlined, null),
4613
5305
  block: () => ({
4614
5306
  type: "Avatar",
4615
5307
  data: {
@@ -4623,7 +5315,7 @@ var BUTTONS = [
4623
5315
  },
4624
5316
  {
4625
5317
  label: "Personal Signature",
4626
- icon: /* @__PURE__ */ React60.createElement(ContactMailOutlined, null),
5318
+ icon: /* @__PURE__ */ React58.createElement(ContactMailOutlined, null),
4627
5319
  block: () => ({
4628
5320
  type: "Signature",
4629
5321
  data: {
@@ -4645,7 +5337,7 @@ var BUTTONS = [
4645
5337
  },
4646
5338
  {
4647
5339
  label: "Company Signature",
4648
- icon: /* @__PURE__ */ React60.createElement(BusinessOutlined, null),
5340
+ icon: /* @__PURE__ */ React58.createElement(BusinessOutlined, null),
4649
5341
  block: () => ({
4650
5342
  type: "Signature",
4651
5343
  data: {
@@ -4665,7 +5357,7 @@ var BUTTONS = [
4665
5357
  },
4666
5358
  {
4667
5359
  label: "Divider",
4668
- icon: /* @__PURE__ */ React60.createElement(HorizontalRuleOutlined, null),
5360
+ icon: /* @__PURE__ */ React58.createElement(HorizontalRuleOutlined, null),
4669
5361
  block: () => ({
4670
5362
  type: "Divider",
4671
5363
  data: {
@@ -4678,7 +5370,7 @@ var BUTTONS = [
4678
5370
  },
4679
5371
  {
4680
5372
  label: "Spacer",
4681
- icon: /* @__PURE__ */ React60.createElement(Crop32Outlined, null),
5373
+ icon: /* @__PURE__ */ React58.createElement(Crop32Outlined, null),
4682
5374
  block: () => ({
4683
5375
  type: "Spacer",
4684
5376
  data: {}
@@ -4686,7 +5378,7 @@ var BUTTONS = [
4686
5378
  },
4687
5379
  {
4688
5380
  label: "Html",
4689
- icon: /* @__PURE__ */ React60.createElement(HtmlOutlined, null),
5381
+ icon: /* @__PURE__ */ React58.createElement(HtmlOutlined, null),
4690
5382
  block: () => ({
4691
5383
  type: "Html",
4692
5384
  data: {
@@ -4701,7 +5393,7 @@ var BUTTONS = [
4701
5393
  },
4702
5394
  {
4703
5395
  label: "Columns",
4704
- icon: /* @__PURE__ */ React60.createElement(ViewColumnOutlined, null),
5396
+ icon: /* @__PURE__ */ React58.createElement(ViewColumnOutlined, null),
4705
5397
  block: () => ({
4706
5398
  type: "ColumnsContainer",
4707
5399
  data: {
@@ -4716,7 +5408,7 @@ var BUTTONS = [
4716
5408
  },
4717
5409
  {
4718
5410
  label: "Container",
4719
- icon: /* @__PURE__ */ React60.createElement(LibraryAddOutlined, null),
5411
+ icon: /* @__PURE__ */ React58.createElement(LibraryAddOutlined, null),
4720
5412
  block: () => ({
4721
5413
  type: "Container",
4722
5414
  data: {
@@ -4740,7 +5432,7 @@ function BlocksMenu({ anchorEl, setAnchorEl, onSelect }) {
4740
5432
  if (anchorEl === null) {
4741
5433
  return null;
4742
5434
  }
4743
- return /* @__PURE__ */ React60.createElement(
5435
+ return /* @__PURE__ */ React58.createElement(
4744
5436
  Menu,
4745
5437
  {
4746
5438
  open: true,
@@ -4749,7 +5441,7 @@ function BlocksMenu({ anchorEl, setAnchorEl, onSelect }) {
4749
5441
  anchorOrigin: { vertical: "bottom", horizontal: "center" },
4750
5442
  transformOrigin: { vertical: "top", horizontal: "center" }
4751
5443
  },
4752
- /* @__PURE__ */ React60.createElement(Box, { sx: { p: 1, display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr" } }, BUTTONS.map((k, i) => /* @__PURE__ */ React60.createElement(BlockTypeButton, { key: i, label: k.label, icon: k.icon, onClick: () => onClick(k.block()) })))
5444
+ /* @__PURE__ */ React58.createElement(Box, { sx: { p: 1, display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr" } }, BUTTONS.map((k, i) => /* @__PURE__ */ React58.createElement(BlockTypeButton, { key: i, label: k.label, icon: k.icon, onClick: () => onClick(k.block()) })))
4753
5445
  );
4754
5446
  }
4755
5447
  function DividerButton({ buttonElement, onClick }) {
@@ -4776,7 +5468,7 @@ function DividerButton({ buttonElement, onClick }) {
4776
5468
  window.removeEventListener("mousemove", listener);
4777
5469
  };
4778
5470
  }, [buttonElement, setVisible]);
4779
- return /* @__PURE__ */ React60.createElement(Fade, { in: visible }, /* @__PURE__ */ React60.createElement(
5471
+ return /* @__PURE__ */ React58.createElement(Fade, { in: visible }, /* @__PURE__ */ React58.createElement(
4780
5472
  IconButton,
4781
5473
  {
4782
5474
  size: "small",
@@ -4799,11 +5491,11 @@ function DividerButton({ buttonElement, onClick }) {
4799
5491
  onClick();
4800
5492
  }
4801
5493
  },
4802
- /* @__PURE__ */ React60.createElement(AddOutlined, { fontSize: "small" })
5494
+ /* @__PURE__ */ React58.createElement(AddOutlined, { fontSize: "small" })
4803
5495
  ));
4804
5496
  }
4805
5497
  function PlaceholderButton({ onClick }) {
4806
- return /* @__PURE__ */ React60.createElement(
5498
+ return /* @__PURE__ */ React58.createElement(
4807
5499
  ButtonBase,
4808
5500
  {
4809
5501
  onClick: (ev) => {
@@ -4819,7 +5511,7 @@ function PlaceholderButton({ onClick }) {
4819
5511
  bgcolor: "rgba(0,0,0, 0.05)"
4820
5512
  }
4821
5513
  },
4822
- /* @__PURE__ */ React60.createElement(
5514
+ /* @__PURE__ */ React58.createElement(
4823
5515
  AddOutlined,
4824
5516
  {
4825
5517
  sx: {
@@ -4843,12 +5535,12 @@ function AddBlockButton({ onSelect, placeholder }) {
4843
5535
  };
4844
5536
  const renderButton2 = () => {
4845
5537
  if (placeholder) {
4846
- return /* @__PURE__ */ React60.createElement(PlaceholderButton, { onClick: handleButtonClick });
5538
+ return /* @__PURE__ */ React58.createElement(PlaceholderButton, { onClick: handleButtonClick });
4847
5539
  } else {
4848
- return /* @__PURE__ */ React60.createElement(DividerButton, { buttonElement, onClick: handleButtonClick });
5540
+ return /* @__PURE__ */ React58.createElement(DividerButton, { buttonElement, onClick: handleButtonClick });
4849
5541
  }
4850
5542
  };
4851
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement("div", { ref: setButtonElement, style: { position: "relative" } }, renderButton2()), /* @__PURE__ */ React60.createElement(BlocksMenu, { anchorEl: menuAnchorEl, setAnchorEl: setMenuAnchorEl, onSelect }));
5543
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement("div", { ref: setButtonElement, style: { position: "relative" } }, renderButton2()), /* @__PURE__ */ React58.createElement(BlocksMenu, { anchorEl: menuAnchorEl, setAnchorEl: setMenuAnchorEl, onSelect }));
4852
5544
  }
4853
5545
 
4854
5546
  // src/editor/blocks/helpers/editor-children-ids/index.tsx
@@ -4875,9 +5567,9 @@ function EditorChildrenIds({ childrenIds, onChange }) {
4875
5567
  });
4876
5568
  };
4877
5569
  if (!childrenIds || childrenIds.length === 0) {
4878
- return /* @__PURE__ */ React60.createElement(AddBlockButton, { placeholder: true, onSelect: appendBlock });
5570
+ return /* @__PURE__ */ React58.createElement(AddBlockButton, { placeholder: true, onSelect: appendBlock });
4879
5571
  }
4880
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, childrenIds.map((childId, i) => /* @__PURE__ */ React60.createElement(Fragment, { key: childId }, /* @__PURE__ */ React60.createElement(AddBlockButton, { onSelect: (block) => insertBlock(block, i) }), /* @__PURE__ */ React60.createElement(EditorBlock, { id: childId }))), /* @__PURE__ */ React60.createElement(AddBlockButton, { onSelect: appendBlock }));
5572
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, childrenIds.map((childId, i) => /* @__PURE__ */ React58.createElement(Fragment, { key: childId }, /* @__PURE__ */ React58.createElement(AddBlockButton, { onSelect: (block) => insertBlock(block, i) }), /* @__PURE__ */ React58.createElement(EditorBlock, { id: childId }))), /* @__PURE__ */ React58.createElement(AddBlockButton, { onSelect: appendBlock }));
4881
5573
  }
4882
5574
 
4883
5575
  // src/editor/blocks/columns-container/columns-container-editor.tsx
@@ -4904,15 +5596,15 @@ function ColumnsContainerEditor({ style, props }) {
4904
5596
  });
4905
5597
  setSelectedBlockId(blockId);
4906
5598
  };
4907
- return /* @__PURE__ */ React60.createElement(
5599
+ return /* @__PURE__ */ React58.createElement(
4908
5600
  columns_container_default,
4909
5601
  {
4910
5602
  props: restProps,
4911
5603
  style,
4912
5604
  columns: [
4913
- /* @__PURE__ */ React60.createElement(EditorChildrenIds, { childrenIds: (_b = columns == null ? void 0 : columns[0]) == null ? void 0 : _b.childrenIds, onChange: (change) => updateColumn(0, change) }),
4914
- /* @__PURE__ */ React60.createElement(EditorChildrenIds, { childrenIds: (_c = columns == null ? void 0 : columns[1]) == null ? void 0 : _c.childrenIds, onChange: (change) => updateColumn(1, change) }),
4915
- /* @__PURE__ */ React60.createElement(EditorChildrenIds, { childrenIds: (_d = columns == null ? void 0 : columns[2]) == null ? void 0 : _d.childrenIds, onChange: (change) => updateColumn(2, change) })
5605
+ /* @__PURE__ */ React58.createElement(EditorChildrenIds, { childrenIds: (_b = columns == null ? void 0 : columns[0]) == null ? void 0 : _b.childrenIds, onChange: (change) => updateColumn(0, change) }),
5606
+ /* @__PURE__ */ React58.createElement(EditorChildrenIds, { childrenIds: (_c = columns == null ? void 0 : columns[1]) == null ? void 0 : _c.childrenIds, onChange: (change) => updateColumn(1, change) }),
5607
+ /* @__PURE__ */ React58.createElement(EditorChildrenIds, { childrenIds: (_d = columns == null ? void 0 : columns[2]) == null ? void 0 : _d.childrenIds, onChange: (change) => updateColumn(2, change) })
4916
5608
  ]
4917
5609
  }
4918
5610
  );
@@ -4922,7 +5614,7 @@ function ContainerEditor({ style, props }) {
4922
5614
  const childrenIds = (_a = props == null ? void 0 : props.childrenIds) != null ? _a : [];
4923
5615
  const document2 = useDocument();
4924
5616
  const currentBlockId = useCurrentBlockId();
4925
- return /* @__PURE__ */ React60.createElement(container_default, { style }, /* @__PURE__ */ React60.createElement(
5617
+ return /* @__PURE__ */ React58.createElement(container_default, { style }, /* @__PURE__ */ React58.createElement(
4926
5618
  EditorChildrenIds,
4927
5619
  {
4928
5620
  childrenIds,
@@ -5122,7 +5814,7 @@ function EmailLayoutEditor(props) {
5122
5814
  lineHeight: "1.5",
5123
5815
  margin: "0"
5124
5816
  };
5125
- const editorChildren = /* @__PURE__ */ React60.createElement(
5817
+ const editorChildren = /* @__PURE__ */ React58.createElement(
5126
5818
  EditorChildrenIds,
5127
5819
  {
5128
5820
  childrenIds,
@@ -5141,7 +5833,7 @@ function EmailLayoutEditor(props) {
5141
5833
  }
5142
5834
  );
5143
5835
  if (props.backdropDisabled) {
5144
- return /* @__PURE__ */ React60.createElement(
5836
+ return /* @__PURE__ */ React58.createElement(
5145
5837
  "div",
5146
5838
  {
5147
5839
  onClick: () => {
@@ -5154,10 +5846,10 @@ function EmailLayoutEditor(props) {
5154
5846
  minHeight: "100%"
5155
5847
  })
5156
5848
  },
5157
- /* @__PURE__ */ React60.createElement("div", { style: { maxWidth: "600px" } }, editorChildren)
5849
+ /* @__PURE__ */ React58.createElement("div", { style: { maxWidth: "600px" } }, editorChildren)
5158
5850
  );
5159
5851
  }
5160
- return /* @__PURE__ */ React60.createElement(
5852
+ return /* @__PURE__ */ React58.createElement(
5161
5853
  "div",
5162
5854
  {
5163
5855
  onClick: () => {
@@ -5170,7 +5862,7 @@ function EmailLayoutEditor(props) {
5170
5862
  minHeight: "100%"
5171
5863
  })
5172
5864
  },
5173
- /* @__PURE__ */ React60.createElement(
5865
+ /* @__PURE__ */ React58.createElement(
5174
5866
  "table",
5175
5867
  {
5176
5868
  align: "center",
@@ -5194,7 +5886,7 @@ function EmailLayoutEditor(props) {
5194
5886
  cellPadding: "0",
5195
5887
  border: 0
5196
5888
  },
5197
- /* @__PURE__ */ React60.createElement("tbody", null, /* @__PURE__ */ React60.createElement("tr", { style: { width: "100%" } }, /* @__PURE__ */ React60.createElement("td", null, editorChildren)))
5889
+ /* @__PURE__ */ React58.createElement("tbody", null, /* @__PURE__ */ React58.createElement("tr", { style: { width: "100%" } }, /* @__PURE__ */ React58.createElement("td", null, editorChildren)))
5198
5890
  )
5199
5891
  );
5200
5892
  }
@@ -5353,7 +6045,7 @@ function TuneMenu({ blockId }) {
5353
6045
  resetDocument(nDocument);
5354
6046
  setSelectedBlockId(blockId);
5355
6047
  };
5356
- return /* @__PURE__ */ React60.createElement(Paper, { sx, onClick: (ev) => ev.stopPropagation() }, /* @__PURE__ */ React60.createElement(Stack, null, /* @__PURE__ */ React60.createElement(Tooltip, { title: "Move up", placement: "left-start" }, /* @__PURE__ */ React60.createElement(IconButton, { onClick: () => handleMoveClick("up"), sx: { color: "text.primary" } }, /* @__PURE__ */ React60.createElement(ArrowUpwardOutlined, { fontSize: "small" }))), /* @__PURE__ */ React60.createElement(Tooltip, { title: "Move down", placement: "left-start" }, /* @__PURE__ */ React60.createElement(IconButton, { onClick: () => handleMoveClick("down"), sx: { color: "text.primary" } }, /* @__PURE__ */ React60.createElement(ArrowDownwardOutlined, { fontSize: "small" }))), /* @__PURE__ */ React60.createElement(Tooltip, { title: "Copy block", placement: "left-start" }, /* @__PURE__ */ React60.createElement(IconButton, { onClick: handleCopyClick, sx: { color: "text.primary" } }, /* @__PURE__ */ React60.createElement(ContentCopyOutlined, { fontSize: "small" }))), /* @__PURE__ */ React60.createElement(Tooltip, { title: "Delete", placement: "left-start" }, /* @__PURE__ */ React60.createElement(IconButton, { onClick: handleDeleteClick, sx: { color: "text.primary" } }, /* @__PURE__ */ React60.createElement(DeleteOutlined, { fontSize: "small" })))));
6048
+ return /* @__PURE__ */ React58.createElement(Paper, { sx, onClick: (ev) => ev.stopPropagation() }, /* @__PURE__ */ React58.createElement(Stack, null, /* @__PURE__ */ React58.createElement(Tooltip, { title: "Move up", placement: "left-start" }, /* @__PURE__ */ React58.createElement(IconButton, { onClick: () => handleMoveClick("up"), sx: { color: "text.primary" } }, /* @__PURE__ */ React58.createElement(ArrowUpwardOutlined, { fontSize: "small" }))), /* @__PURE__ */ React58.createElement(Tooltip, { title: "Move down", placement: "left-start" }, /* @__PURE__ */ React58.createElement(IconButton, { onClick: () => handleMoveClick("down"), sx: { color: "text.primary" } }, /* @__PURE__ */ React58.createElement(ArrowDownwardOutlined, { fontSize: "small" }))), /* @__PURE__ */ React58.createElement(Tooltip, { title: "Copy block", placement: "left-start" }, /* @__PURE__ */ React58.createElement(IconButton, { onClick: handleCopyClick, sx: { color: "text.primary" } }, /* @__PURE__ */ React58.createElement(ContentCopyOutlined, { fontSize: "small" }))), /* @__PURE__ */ React58.createElement(Tooltip, { title: "Delete", placement: "left-start" }, /* @__PURE__ */ React58.createElement(IconButton, { onClick: handleDeleteClick, sx: { color: "text.primary" } }, /* @__PURE__ */ React58.createElement(DeleteOutlined, { fontSize: "small" })))));
5357
6049
  }
5358
6050
 
5359
6051
  // src/editor/blocks/helpers/block-wrappers/editor-block-wrapper.tsx
@@ -5371,9 +6063,9 @@ function EditorBlockWrapper({ children }) {
5371
6063
  if (selectedBlockId !== blockId) {
5372
6064
  return null;
5373
6065
  }
5374
- return /* @__PURE__ */ React60.createElement(TuneMenu, { blockId });
6066
+ return /* @__PURE__ */ React58.createElement(TuneMenu, { blockId });
5375
6067
  };
5376
- return /* @__PURE__ */ React60.createElement(
6068
+ return /* @__PURE__ */ React58.createElement(
5377
6069
  Box,
5378
6070
  {
5379
6071
  sx: {
@@ -5503,19 +6195,203 @@ function ButtonEditor({ style, props }) {
5503
6195
  width: fullWidth ? "100%" : void 0,
5504
6196
  textAlign: "center"
5505
6197
  });
5506
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React60.createElement(
6198
+ const trackFocus = (e) => {
6199
+ var _a2, _b2;
6200
+ const el = e.currentTarget;
6201
+ setLastFocusedEditable({
6202
+ blockId,
6203
+ field: "text",
6204
+ selectionStart: (_a2 = el.selectionStart) != null ? _a2 : el.value.length,
6205
+ selectionEnd: (_b2 = el.selectionEnd) != null ? _b2 : el.value.length
6206
+ });
6207
+ };
6208
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React58.createElement(
5507
6209
  "input",
5508
6210
  {
5509
6211
  type: "text",
5510
6212
  value: localText,
5511
6213
  onChange: handleTextChange,
5512
- style: inputStyle,
5513
- onClick: (e) => e.stopPropagation()
6214
+ onFocus: trackFocus,
6215
+ onSelect: trackFocus,
6216
+ onKeyUp: trackFocus,
6217
+ onClick: (e) => {
6218
+ e.stopPropagation();
6219
+ trackFocus(e);
6220
+ },
6221
+ style: inputStyle
5514
6222
  }
5515
6223
  ));
5516
6224
  }
5517
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React60.createElement("span", { style: linkStyle }, /* @__PURE__ */ React60.createElement("span", null, text)));
6225
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React58.createElement("span", { style: linkStyle }, /* @__PURE__ */ React58.createElement("span", null, text)));
6226
+ }
6227
+ function useMarkdownToolbar({ text, isSelected, commitText, trackSelection }) {
6228
+ const textareaRef = useRef(null);
6229
+ const [selection, setSelection] = useState({ start: 0, end: 0 });
6230
+ const [linkPrompt, setLinkPrompt] = useState(false);
6231
+ const pendingSelectionRef = useRef(null);
6232
+ const textRef = useRef(text);
6233
+ useEffect(() => {
6234
+ textRef.current = text;
6235
+ }, [text]);
6236
+ const syncSelection = useCallback(
6237
+ (start, end) => {
6238
+ const next = { start, end };
6239
+ setSelection(next);
6240
+ trackSelection == null ? void 0 : trackSelection(next);
6241
+ },
6242
+ [trackSelection]
6243
+ );
6244
+ const trackFocus = useCallback(
6245
+ (e) => {
6246
+ var _a, _b;
6247
+ const el = e.currentTarget;
6248
+ const start = (_a = el.selectionStart) != null ? _a : el.value.length;
6249
+ const end = (_b = el.selectionEnd) != null ? _b : el.value.length;
6250
+ syncSelection(start, end);
6251
+ },
6252
+ [syncSelection]
6253
+ );
6254
+ useEffect(() => {
6255
+ const target = pendingSelectionRef.current;
6256
+ if (!target) return;
6257
+ const ta = textareaRef.current;
6258
+ if (!ta) return;
6259
+ ta.focus();
6260
+ ta.setSelectionRange(target.start, target.end);
6261
+ syncSelection(target.start, target.end);
6262
+ pendingSelectionRef.current = null;
6263
+ }, [text, syncSelection]);
6264
+ useEffect(() => {
6265
+ if (!isSelected || selection.start === selection.end) {
6266
+ setLinkPrompt(false);
6267
+ }
6268
+ }, [isSelected, selection.start, selection.end]);
6269
+ const wrapSelection = (prefix, suffix) => {
6270
+ var _a, _b;
6271
+ const ta = textareaRef.current;
6272
+ if (!ta) return;
6273
+ const start = (_a = ta.selectionStart) != null ? _a : selection.start;
6274
+ const end = (_b = ta.selectionEnd) != null ? _b : selection.end;
6275
+ if (start === end) return;
6276
+ const current = textRef.current;
6277
+ const selected = current.slice(start, end);
6278
+ const before = current.slice(0, start);
6279
+ const after = current.slice(end);
6280
+ const wrapped = `${prefix}${selected}${suffix}`;
6281
+ const newText = `${before}${wrapped}${after}`;
6282
+ const newStart = start + prefix.length;
6283
+ const newEnd = newStart + selected.length;
6284
+ pendingSelectionRef.current = { start: newStart, end: newEnd };
6285
+ commitText(newText);
6286
+ };
6287
+ const handleBold = () => wrapSelection("**", "**");
6288
+ const handleItalic = () => wrapSelection("*", "*");
6289
+ const handleLinkRequest = () => {
6290
+ if (selection.start === selection.end) return;
6291
+ setLinkPrompt(true);
6292
+ };
6293
+ const handleLinkSubmit = (url) => {
6294
+ const start = selection.start;
6295
+ const end = selection.end;
6296
+ if (start === end) {
6297
+ setLinkPrompt(false);
6298
+ return;
6299
+ }
6300
+ const current = textRef.current;
6301
+ const selected = current.slice(start, end);
6302
+ const before = current.slice(0, start);
6303
+ const after = current.slice(end);
6304
+ const wrapped = `[${selected}](${url})`;
6305
+ const newText = `${before}${wrapped}${after}`;
6306
+ const newStart = start + wrapped.length;
6307
+ pendingSelectionRef.current = { start: newStart, end: newStart };
6308
+ commitText(newText);
6309
+ setLinkPrompt(false);
6310
+ };
6311
+ const handleLinkCancel = () => {
6312
+ var _a;
6313
+ setLinkPrompt(false);
6314
+ (_a = textareaRef.current) == null ? void 0 : _a.focus();
6315
+ };
6316
+ const handleKeyDown = (e) => {
6317
+ if (!(e.metaKey || e.ctrlKey)) return;
6318
+ const key = e.key.toLowerCase();
6319
+ if (key === "b") {
6320
+ e.preventDefault();
6321
+ handleBold();
6322
+ } else if (key === "i") {
6323
+ e.preventDefault();
6324
+ handleItalic();
6325
+ } else if (key === "k") {
6326
+ e.preventDefault();
6327
+ handleLinkRequest();
6328
+ }
6329
+ };
6330
+ const toolbarVisible = isSelected && (selection.start !== selection.end || linkPrompt);
6331
+ return {
6332
+ textareaRef,
6333
+ selection,
6334
+ trackFocus,
6335
+ handleKeyDown,
6336
+ toolbarProps: {
6337
+ visible: toolbarVisible,
6338
+ linkPrompt,
6339
+ onBold: handleBold,
6340
+ onItalic: handleItalic,
6341
+ onLinkRequest: handleLinkRequest,
6342
+ onLinkSubmit: handleLinkSubmit,
6343
+ onLinkCancel: handleLinkCancel
6344
+ }
6345
+ };
6346
+ }
6347
+ function InlineFormattingToolbar({
6348
+ anchorEl,
6349
+ visible,
6350
+ linkPrompt,
6351
+ onBold,
6352
+ onItalic,
6353
+ onLinkRequest,
6354
+ onLinkSubmit,
6355
+ onLinkCancel
6356
+ }) {
6357
+ const [url, setUrl] = useState("");
6358
+ const inputRef = useRef(null);
6359
+ useEffect(() => {
6360
+ if (linkPrompt) {
6361
+ setUrl("");
6362
+ setTimeout(() => {
6363
+ var _a;
6364
+ return (_a = inputRef.current) == null ? void 0 : _a.focus();
6365
+ }, 0);
6366
+ }
6367
+ }, [linkPrompt]);
6368
+ const preventBlur = (e) => e.preventDefault();
6369
+ return /* @__PURE__ */ React58.createElement(Popper, { open: visible, anchorEl, placement: "top-start", style: { zIndex: 1300 } }, /* @__PURE__ */ React58.createElement(Paper, { elevation: 4, sx: { px: 0.5, py: 0.25, mb: 0.5 }, onMouseDown: preventBlur }, linkPrompt ? /* @__PURE__ */ React58.createElement(Stack, { direction: "row", alignItems: "center", spacing: 0.5, sx: { px: 0.5 } }, /* @__PURE__ */ React58.createElement(
6370
+ TextField,
6371
+ {
6372
+ inputRef,
6373
+ value: url,
6374
+ onChange: (e) => setUrl(e.target.value),
6375
+ placeholder: "https://example.com",
6376
+ variant: "standard",
6377
+ size: "small",
6378
+ onKeyDown: (e) => {
6379
+ if (e.key === "Enter") {
6380
+ e.preventDefault();
6381
+ const trimmed = url.trim();
6382
+ if (trimmed) onLinkSubmit(trimmed);
6383
+ else onLinkCancel();
6384
+ } else if (e.key === "Escape") {
6385
+ e.preventDefault();
6386
+ onLinkCancel();
6387
+ }
6388
+ },
6389
+ sx: { width: 220 }
6390
+ }
6391
+ )) : /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 0.25 }, /* @__PURE__ */ React58.createElement(IconButton, { size: "small", onClick: onBold, title: "Bold (Cmd+B)", "aria-label": "Bold" }, /* @__PURE__ */ React58.createElement(FormatBoldOutlined, { fontSize: "small" })), /* @__PURE__ */ React58.createElement(IconButton, { size: "small", onClick: onItalic, title: "Italic (Cmd+I)", "aria-label": "Italic" }, /* @__PURE__ */ React58.createElement(FormatItalicOutlined, { fontSize: "small" })), /* @__PURE__ */ React58.createElement(IconButton, { size: "small", onClick: onLinkRequest, title: "Link (Cmd+K)", "aria-label": "Link" }, /* @__PURE__ */ React58.createElement(LinkOutlined, { fontSize: "small" })))));
5518
6392
  }
6393
+
6394
+ // src/editor/blocks/heading/heading-editor.tsx
5519
6395
  function getFontFamily9(fontFamily) {
5520
6396
  switch (fontFamily) {
5521
6397
  case "MODERN_SANS":
@@ -5578,7 +6454,7 @@ function getFontSize2(level) {
5578
6454
  }
5579
6455
  }
5580
6456
  function HeadingEditor({ style, props }) {
5581
- var _a, _b, _c, _d, _e, _f;
6457
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
5582
6458
  const blockId = useCurrentBlockId();
5583
6459
  const selectedBlockId = useSelectedBlockId();
5584
6460
  const document2 = useDocument();
@@ -5586,6 +6462,7 @@ function HeadingEditor({ style, props }) {
5586
6462
  const level = (_a = props == null ? void 0 : props.level) != null ? _a : HeadingPropsDefaults.level;
5587
6463
  const textContent = (_b = props == null ? void 0 : props.text) != null ? _b : HeadingPropsDefaults.text;
5588
6464
  const [localText, setLocalText] = useState(textContent);
6465
+ const isMarkdown = (_c = props == null ? void 0 : props.markdown) != null ? _c : false;
5589
6466
  const rootBlock = document2.root;
5590
6467
  const rootFontFamily = rootBlock && rootBlock.type === "EmailLayout" ? getFontFamily9(rootBlock.data.fontFamily) : '"Helvetica Neue", Arial, sans-serif';
5591
6468
  useEffect(() => {
@@ -5593,10 +6470,12 @@ function HeadingEditor({ style, props }) {
5593
6470
  }, [textContent]);
5594
6471
  const fontFamily = getFontFamily9(style == null ? void 0 : style.fontFamily) || rootFontFamily;
5595
6472
  const hStyle = {
5596
- color: (_c = style == null ? void 0 : style.color) != null ? _c : void 0,
5597
- backgroundColor: (_d = style == null ? void 0 : style.backgroundColor) != null ? _d : void 0,
5598
- fontWeight: (_e = style == null ? void 0 : style.fontWeight) != null ? _e : "bold",
5599
- textAlign: (_f = style == null ? void 0 : style.textAlign) != null ? _f : void 0,
6473
+ color: (_d = style == null ? void 0 : style.color) != null ? _d : void 0,
6474
+ backgroundColor: (_e = style == null ? void 0 : style.backgroundColor) != null ? _e : void 0,
6475
+ fontWeight: (_f = style == null ? void 0 : style.fontWeight) != null ? _f : "bold",
6476
+ lineHeight: (_g = style == null ? void 0 : style.lineHeight) != null ? _g : void 0,
6477
+ letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
6478
+ textAlign: (_h = style == null ? void 0 : style.textAlign) != null ? _h : void 0,
5600
6479
  margin: 0,
5601
6480
  fontFamily,
5602
6481
  fontSize: getFontSize2(level),
@@ -5610,53 +6489,79 @@ function HeadingEditor({ style, props }) {
5610
6489
  resize: "none",
5611
6490
  backgroundColor: "transparent",
5612
6491
  overflow: "hidden",
5613
- lineHeight: "inherit",
6492
+ lineHeight: (_i = hStyle.lineHeight) != null ? _i : "inherit",
5614
6493
  margin: 0,
5615
6494
  display: "block",
5616
6495
  width: "100%"
5617
6496
  });
5618
- const handleTextChange = (e) => {
5619
- const newText = e.target.value;
6497
+ const commitText = (newText, opts) => {
5620
6498
  setLocalText(newText);
5621
6499
  setDocument({
5622
6500
  [blockId]: {
5623
6501
  type: "Heading",
5624
6502
  data: {
5625
6503
  style,
5626
- props: __spreadProps(__spreadValues({}, props), {
6504
+ props: __spreadValues(__spreadProps(__spreadValues({}, props), {
5627
6505
  text: newText
5628
- })
6506
+ }), (opts == null ? void 0 : opts.enableMarkdown) ? { markdown: true } : {})
5629
6507
  }
5630
6508
  }
5631
6509
  });
5632
6510
  };
6511
+ const handleTextChange = (e) => {
6512
+ commitText(e.target.value);
6513
+ };
5633
6514
  const adjustTextareaHeight = (element) => {
5634
6515
  if (element) {
5635
6516
  element.style.height = "auto";
5636
6517
  element.style.height = `${element.scrollHeight}px`;
5637
6518
  }
5638
6519
  };
6520
+ const { textareaRef, trackFocus, handleKeyDown, toolbarProps } = useMarkdownToolbar({
6521
+ text: localText,
6522
+ isSelected,
6523
+ commitText: (newText) => commitText(newText, { enableMarkdown: true }),
6524
+ trackSelection: (sel) => {
6525
+ setLastFocusedEditable({
6526
+ blockId,
6527
+ field: "text",
6528
+ selectionStart: sel.start,
6529
+ selectionEnd: sel.end
6530
+ });
6531
+ }
6532
+ });
6533
+ useEffect(() => {
6534
+ if (textareaRef.current) adjustTextareaHeight(textareaRef.current);
6535
+ }, [localText, textareaRef]);
5639
6536
  if (isSelected) {
5640
- return /* @__PURE__ */ React60.createElement(
6537
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
5641
6538
  "textarea",
5642
6539
  {
6540
+ ref: textareaRef,
5643
6541
  value: localText,
5644
6542
  onChange: handleTextChange,
6543
+ onFocus: trackFocus,
6544
+ onSelect: trackFocus,
6545
+ onKeyUp: trackFocus,
6546
+ onKeyDown: handleKeyDown,
6547
+ onClick: (e) => {
6548
+ e.stopPropagation();
6549
+ trackFocus(e);
6550
+ },
5645
6551
  style: textareaStyle,
5646
6552
  rows: 1,
5647
- onInput: (e) => adjustTextareaHeight(e.target),
5648
- ref: (el) => el && adjustTextareaHeight(el),
5649
- onClick: (e) => e.stopPropagation()
6553
+ onInput: (e) => adjustTextareaHeight(e.target)
5650
6554
  }
5651
- );
6555
+ ), /* @__PURE__ */ React58.createElement(InlineFormattingToolbar, __spreadValues({ anchorEl: textareaRef.current }, toolbarProps)));
5652
6556
  }
6557
+ const headingProps = isMarkdown ? { style: hStyle, dangerouslySetInnerHTML: { __html: renderInlineMarkdownString(textContent) } } : { style: hStyle, children: textContent };
5653
6558
  switch (level) {
5654
6559
  case "h1":
5655
- return /* @__PURE__ */ React60.createElement("h1", { style: hStyle }, textContent);
6560
+ return /* @__PURE__ */ React58.createElement("h1", __spreadValues({}, headingProps));
5656
6561
  case "h2":
5657
- return /* @__PURE__ */ React60.createElement("h2", { style: hStyle }, textContent);
6562
+ return /* @__PURE__ */ React58.createElement("h2", __spreadValues({}, headingProps));
5658
6563
  case "h3":
5659
- return /* @__PURE__ */ React60.createElement("h3", { style: hStyle }, textContent);
6564
+ return /* @__PURE__ */ React58.createElement("h3", __spreadValues({}, headingProps));
5660
6565
  }
5661
6566
  }
5662
6567
  function HtmlEditor({ style, props }) {
@@ -5711,23 +6616,39 @@ function HtmlEditor({ style, props }) {
5711
6616
  margin: 0,
5712
6617
  backgroundColor: "transparent"
5713
6618
  });
5714
- return /* @__PURE__ */ React60.createElement("div", { style: cssStyle }, /* @__PURE__ */ React60.createElement(
6619
+ const trackFocus = (e) => {
6620
+ var _a2, _b2;
6621
+ const el = e.currentTarget;
6622
+ setLastFocusedEditable({
6623
+ blockId,
6624
+ field: "contents",
6625
+ selectionStart: (_a2 = el.selectionStart) != null ? _a2 : el.value.length,
6626
+ selectionEnd: (_b2 = el.selectionEnd) != null ? _b2 : el.value.length
6627
+ });
6628
+ };
6629
+ return /* @__PURE__ */ React58.createElement("div", { style: cssStyle }, /* @__PURE__ */ React58.createElement(
5715
6630
  "textarea",
5716
6631
  {
5717
6632
  value: localContents,
5718
6633
  onChange: handleChange,
6634
+ onFocus: trackFocus,
6635
+ onSelect: trackFocus,
6636
+ onKeyUp: trackFocus,
6637
+ onClick: (e) => {
6638
+ e.stopPropagation();
6639
+ trackFocus(e);
6640
+ },
5719
6641
  style: textareaStyle,
5720
6642
  rows: 3,
5721
6643
  onInput: (e) => adjustTextareaHeight(e.target),
5722
- ref: (el) => el && adjustTextareaHeight(el),
5723
- onClick: (e) => e.stopPropagation()
6644
+ ref: (el) => el && adjustTextareaHeight(el)
5724
6645
  }
5725
6646
  ));
5726
6647
  }
5727
6648
  if (!contents) {
5728
- return /* @__PURE__ */ React60.createElement("div", { style: cssStyle });
6649
+ return /* @__PURE__ */ React58.createElement("div", { style: cssStyle });
5729
6650
  }
5730
- return /* @__PURE__ */ React60.createElement("div", { style: cssStyle, dangerouslySetInnerHTML: { __html: contents } });
6651
+ return /* @__PURE__ */ React58.createElement("div", { style: cssStyle, dangerouslySetInnerHTML: { __html: contents } });
5731
6652
  }
5732
6653
  function getImageBorderRadius2(shape, size) {
5733
6654
  switch (shape) {
@@ -5842,7 +6763,7 @@ function SignatureEditor({ style, props }) {
5842
6763
  backgroundColor: (_p = style == null ? void 0 : style.backgroundColor) != null ? _p : void 0,
5843
6764
  padding: (style == null ? void 0 : style.padding) ? `${style.padding.top}px ${style.padding.right}px ${style.padding.bottom}px ${style.padding.left}px` : void 0
5844
6765
  };
5845
- const imageElement = imageUrl ? /* @__PURE__ */ React60.createElement(
6766
+ const imageElement = imageUrl ? /* @__PURE__ */ React58.createElement(
5846
6767
  "img",
5847
6768
  {
5848
6769
  src: imageUrl,
@@ -5860,7 +6781,7 @@ function SignatureEditor({ style, props }) {
5860
6781
  }
5861
6782
  }
5862
6783
  ) : null;
5863
- const greetingElement = isSelected ? /* @__PURE__ */ React60.createElement("div", { onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React60.createElement(
6784
+ const greetingElement = isSelected ? /* @__PURE__ */ React58.createElement("div", { onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React58.createElement(
5864
6785
  "input",
5865
6786
  {
5866
6787
  value: localGreeting,
@@ -5871,8 +6792,8 @@ function SignatureEditor({ style, props }) {
5871
6792
  placeholder: "Greeting (e.g. Best regards,)",
5872
6793
  style: __spreadValues(__spreadValues({}, inputBase), greetingStyle)
5873
6794
  }
5874
- )) : greeting ? /* @__PURE__ */ React60.createElement("p", { style: greetingStyle }, greeting) : null;
5875
- const textContent = isSelected ? /* @__PURE__ */ React60.createElement("div", { onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React60.createElement(
6795
+ )) : greeting ? /* @__PURE__ */ React58.createElement("p", { style: greetingStyle }, greeting) : null;
6796
+ const textContent = isSelected ? /* @__PURE__ */ React58.createElement("div", { onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React58.createElement(
5876
6797
  "input",
5877
6798
  {
5878
6799
  value: localName,
@@ -5883,7 +6804,7 @@ function SignatureEditor({ style, props }) {
5883
6804
  placeholder: "Name",
5884
6805
  style: __spreadValues(__spreadValues({}, inputBase), nameStyle)
5885
6806
  }
5886
- ), /* @__PURE__ */ React60.createElement(
6807
+ ), /* @__PURE__ */ React58.createElement(
5887
6808
  "input",
5888
6809
  {
5889
6810
  value: localTitle,
@@ -5894,7 +6815,7 @@ function SignatureEditor({ style, props }) {
5894
6815
  placeholder: "Title",
5895
6816
  style: __spreadValues(__spreadValues({}, inputBase), detailStyle)
5896
6817
  }
5897
- ), /* @__PURE__ */ React60.createElement(
6818
+ ), /* @__PURE__ */ React58.createElement(
5898
6819
  "input",
5899
6820
  {
5900
6821
  value: localCompany,
@@ -5905,7 +6826,7 @@ function SignatureEditor({ style, props }) {
5905
6826
  placeholder: "Company",
5906
6827
  style: __spreadValues(__spreadValues({}, inputBase), detailStyle)
5907
6828
  }
5908
- ), /* @__PURE__ */ React60.createElement(
6829
+ ), /* @__PURE__ */ React58.createElement(
5909
6830
  "input",
5910
6831
  {
5911
6832
  value: localAddress,
@@ -5916,7 +6837,7 @@ function SignatureEditor({ style, props }) {
5916
6837
  placeholder: "Address",
5917
6838
  style: __spreadValues(__spreadValues({}, inputBase), detailStyle)
5918
6839
  }
5919
- ), /* @__PURE__ */ React60.createElement(
6840
+ ), /* @__PURE__ */ React58.createElement(
5920
6841
  "input",
5921
6842
  {
5922
6843
  value: localEmail,
@@ -5927,7 +6848,7 @@ function SignatureEditor({ style, props }) {
5927
6848
  placeholder: "Email",
5928
6849
  style: __spreadProps(__spreadValues(__spreadValues({}, inputBase), linkStyle), { marginTop: 4, display: "block" })
5929
6850
  }
5930
- ), /* @__PURE__ */ React60.createElement(
6851
+ ), /* @__PURE__ */ React58.createElement(
5931
6852
  "input",
5932
6853
  {
5933
6854
  value: localPhone,
@@ -5938,7 +6859,7 @@ function SignatureEditor({ style, props }) {
5938
6859
  placeholder: "Phone",
5939
6860
  style: __spreadProps(__spreadValues(__spreadValues({}, inputBase), linkStyle), { display: "block" })
5940
6861
  }
5941
- ), /* @__PURE__ */ React60.createElement(
6862
+ ), /* @__PURE__ */ React58.createElement(
5942
6863
  "input",
5943
6864
  {
5944
6865
  value: localWebsite,
@@ -5949,11 +6870,11 @@ function SignatureEditor({ style, props }) {
5949
6870
  placeholder: "Website",
5950
6871
  style: __spreadProps(__spreadValues(__spreadValues({}, inputBase), linkStyle), { display: "block" })
5951
6872
  }
5952
- )) : /* @__PURE__ */ React60.createElement("div", null, name && /* @__PURE__ */ React60.createElement("p", { style: nameStyle }, name), title && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, title), company && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, company), address && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, address), (email || phone || website) && /* @__PURE__ */ React60.createElement("p", { style: __spreadProps(__spreadValues({}, detailStyle), { marginTop: 4 }) }, email && /* @__PURE__ */ React60.createElement("span", { style: linkStyle }, email), email && (phone || website) && /* @__PURE__ */ React60.createElement("span", { style: detailStyle }, " \xB7 "), phone && /* @__PURE__ */ React60.createElement("span", { style: linkStyle }, phone), phone && website && /* @__PURE__ */ React60.createElement("span", { style: detailStyle }, " \xB7 "), website && /* @__PURE__ */ React60.createElement("span", { style: linkStyle }, website)), !name && !title && !company && !email && !phone && !website && /* @__PURE__ */ React60.createElement("p", { style: detailStyle }, "Click to edit signature"));
6873
+ )) : /* @__PURE__ */ React58.createElement("div", null, name && /* @__PURE__ */ React58.createElement("p", { style: nameStyle }, name), title && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, title), company && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, company), address && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, address), (email || phone || website) && /* @__PURE__ */ React58.createElement("p", { style: __spreadProps(__spreadValues({}, detailStyle), { marginTop: 4 }) }, email && /* @__PURE__ */ React58.createElement("span", { style: linkStyle }, email), email && (phone || website) && /* @__PURE__ */ React58.createElement("span", { style: detailStyle }, " \xB7 "), phone && /* @__PURE__ */ React58.createElement("span", { style: linkStyle }, phone), phone && website && /* @__PURE__ */ React58.createElement("span", { style: detailStyle }, " \xB7 "), website && /* @__PURE__ */ React58.createElement("span", { style: linkStyle }, website)), !name && !title && !company && !email && !phone && !website && /* @__PURE__ */ React58.createElement("p", { style: detailStyle }, "Click to edit signature"));
5953
6874
  if (layout === "vertical") {
5954
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, greetingElement, imageElement && /* @__PURE__ */ React60.createElement("div", { style: { marginBottom: 12 } }, imageElement), textContent);
6875
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, greetingElement, imageElement && /* @__PURE__ */ React58.createElement("div", { style: { marginBottom: 12 } }, imageElement), textContent);
5955
6876
  }
5956
- return /* @__PURE__ */ React60.createElement("div", { style: wrapperStyle }, greetingElement, /* @__PURE__ */ React60.createElement("table", { cellPadding: "0", cellSpacing: "0", border: 0, role: "presentation" }, /* @__PURE__ */ React60.createElement("tbody", null, /* @__PURE__ */ React60.createElement("tr", null, imageElement && /* @__PURE__ */ React60.createElement("td", { style: { verticalAlign: "middle", paddingRight: 16 } }, imageElement), /* @__PURE__ */ React60.createElement("td", { style: { verticalAlign: "middle" } }, textContent)))));
6877
+ return /* @__PURE__ */ React58.createElement("div", { style: wrapperStyle }, greetingElement, /* @__PURE__ */ React58.createElement("table", { cellPadding: "0", cellSpacing: "0", border: 0, role: "presentation" }, /* @__PURE__ */ React58.createElement("tbody", null, /* @__PURE__ */ React58.createElement("tr", null, imageElement && /* @__PURE__ */ React58.createElement("td", { style: { verticalAlign: "middle", paddingRight: 16 } }, imageElement), /* @__PURE__ */ React58.createElement("td", { style: { verticalAlign: "middle" } }, textContent)))));
5957
6878
  }
5958
6879
  function getFontFamily10(fontFamily) {
5959
6880
  switch (fontFamily) {
@@ -6007,7 +6928,7 @@ function getPadding13(padding) {
6007
6928
  return void 0;
6008
6929
  }
6009
6930
  function TextEditor({ style, props }) {
6010
- var _a, _b, _c, _d, _e, _f, _g;
6931
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
6011
6932
  const blockId = useCurrentBlockId();
6012
6933
  const selectedBlockId = useSelectedBlockId();
6013
6934
  const document2 = useDocument();
@@ -6027,7 +6948,9 @@ function TextEditor({ style, props }) {
6027
6948
  fontSize: (_e = style == null ? void 0 : style.fontSize) != null ? _e : void 0,
6028
6949
  fontFamily,
6029
6950
  fontWeight: (_f = style == null ? void 0 : style.fontWeight) != null ? _f : void 0,
6030
- textAlign: (_g = style == null ? void 0 : style.textAlign) != null ? _g : void 0,
6951
+ lineHeight: (_g = style == null ? void 0 : style.lineHeight) != null ? _g : void 0,
6952
+ letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
6953
+ textAlign: (_h = style == null ? void 0 : style.textAlign) != null ? _h : void 0,
6031
6954
  padding: getPadding13(style == null ? void 0 : style.padding),
6032
6955
  width: "100%",
6033
6956
  minHeight: "1em"
@@ -6038,7 +6961,7 @@ function TextEditor({ style, props }) {
6038
6961
  resize: "none",
6039
6962
  backgroundColor: "transparent",
6040
6963
  overflow: "hidden",
6041
- lineHeight: "inherit",
6964
+ lineHeight: (_i = wStyle.lineHeight) != null ? _i : "inherit",
6042
6965
  margin: 0,
6043
6966
  display: "block",
6044
6967
  width: "100%",
@@ -6046,72 +6969,97 @@ function TextEditor({ style, props }) {
6046
6969
  fontWeight: wStyle.fontWeight,
6047
6970
  textAlign: wStyle.textAlign
6048
6971
  });
6049
- const handleTextChange = (e) => {
6050
- const newText = e.target.value;
6972
+ const commitText = (newText, opts) => {
6051
6973
  setLocalText(newText);
6052
6974
  setDocument({
6053
6975
  [blockId]: {
6054
6976
  type: "Text",
6055
6977
  data: {
6056
6978
  style,
6057
- props: __spreadProps(__spreadValues({}, props), {
6979
+ props: __spreadValues(__spreadProps(__spreadValues({}, props), {
6058
6980
  text: newText
6059
- })
6981
+ }), (opts == null ? void 0 : opts.enableMarkdown) ? { markdown: true } : {})
6060
6982
  }
6061
6983
  }
6062
6984
  });
6063
6985
  };
6986
+ const handleTextChange = (e) => {
6987
+ commitText(e.target.value);
6988
+ };
6064
6989
  const adjustTextareaHeight = (element) => {
6065
6990
  if (element) {
6066
6991
  element.style.height = "auto";
6067
6992
  element.style.height = `${element.scrollHeight}px`;
6068
6993
  }
6069
6994
  };
6995
+ const { textareaRef, trackFocus, handleKeyDown, toolbarProps } = useMarkdownToolbar({
6996
+ text: localText,
6997
+ isSelected,
6998
+ commitText: (newText) => commitText(newText, { enableMarkdown: true }),
6999
+ trackSelection: (sel) => {
7000
+ setLastFocusedEditable({
7001
+ blockId,
7002
+ field: "text",
7003
+ selectionStart: sel.start,
7004
+ selectionEnd: sel.end
7005
+ });
7006
+ }
7007
+ });
7008
+ useEffect(() => {
7009
+ if (textareaRef.current) adjustTextareaHeight(textareaRef.current);
7010
+ }, [localText, textareaRef]);
6070
7011
  if (isSelected) {
6071
- return /* @__PURE__ */ React60.createElement(
7012
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
6072
7013
  "textarea",
6073
7014
  {
7015
+ ref: textareaRef,
6074
7016
  value: localText,
6075
7017
  onChange: handleTextChange,
7018
+ onFocus: trackFocus,
7019
+ onSelect: trackFocus,
7020
+ onKeyUp: trackFocus,
7021
+ onKeyDown: handleKeyDown,
7022
+ onClick: (e) => {
7023
+ e.stopPropagation();
7024
+ trackFocus(e);
7025
+ },
6076
7026
  style: textareaStyle,
6077
7027
  rows: 1,
6078
- onInput: (e) => adjustTextareaHeight(e.target),
6079
- ref: (el) => el && adjustTextareaHeight(el),
6080
- onClick: (e) => e.stopPropagation()
7028
+ onInput: (e) => adjustTextareaHeight(e.target)
6081
7029
  }
6082
- );
7030
+ ), /* @__PURE__ */ React58.createElement(InlineFormattingToolbar, __spreadValues({ anchorEl: textareaRef.current }, toolbarProps)));
6083
7031
  }
6084
7032
  if (isMarkdown) {
6085
- return /* @__PURE__ */ React60.createElement(EmailMarkdown, { style: wStyle, markdown: textContent });
7033
+ return /* @__PURE__ */ React58.createElement(EmailMarkdown, { style: wStyle, markdown: textContent });
6086
7034
  }
6087
- return /* @__PURE__ */ React60.createElement("div", { style: wStyle }, textContent);
7035
+ return /* @__PURE__ */ React58.createElement("div", { style: wStyle }, textContent);
6088
7036
  }
6089
7037
 
6090
7038
  // src/editor/core.tsx
6091
7039
  var EDITOR_DICTIONARY = buildBlockConfigurationDictionary({
6092
7040
  Avatar: {
6093
7041
  schema: AvatarPropsSchema,
6094
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(avatar_default, __spreadValues({}, props)))
7042
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(avatar_default, __spreadValues({}, props)))
6095
7043
  },
6096
7044
  Button: {
6097
7045
  schema: ButtonPropsSchema,
6098
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(ButtonEditor, __spreadValues({}, props)))
7046
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(ButtonEditor, __spreadValues({}, props)))
6099
7047
  },
6100
7048
  Container: {
6101
7049
  schema: container_props_schema_default,
6102
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(ContainerEditor, __spreadValues({}, props)))
7050
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(ContainerEditor, __spreadValues({}, props)))
6103
7051
  },
6104
7052
  ColumnsContainer: {
6105
7053
  schema: columns_container_props_schema_default2,
6106
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(ColumnsContainerEditor, __spreadValues({}, props)))
7054
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(ColumnsContainerEditor, __spreadValues({}, props)))
6107
7055
  },
6108
7056
  Heading: {
6109
7057
  schema: HeadingPropsSchema,
6110
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(HeadingEditor, __spreadValues({}, props)))
7058
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(HeadingEditor, __spreadValues({}, props)))
6111
7059
  },
6112
7060
  Html: {
6113
7061
  schema: HtmlPropsSchema,
6114
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(HtmlEditor, __spreadValues({}, props)))
7062
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(HtmlEditor, __spreadValues({}, props)))
6115
7063
  },
6116
7064
  Image: {
6117
7065
  schema: ImagePropsSchema,
@@ -6123,28 +7071,28 @@ var EDITOR_DICTIONARY = buildBlockConfigurationDictionary({
6123
7071
  linkHref: null
6124
7072
  })
6125
7073
  });
6126
- return /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(image_default, __spreadValues({}, props)));
7074
+ return /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(image_default, __spreadValues({}, props)));
6127
7075
  }
6128
7076
  },
6129
7077
  Text: {
6130
7078
  schema: TextPropsSchema,
6131
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(TextEditor, __spreadValues({}, props)))
7079
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(TextEditor, __spreadValues({}, props)))
6132
7080
  },
6133
7081
  EmailLayout: {
6134
7082
  schema: email_layout_props_schema_default,
6135
- Component: (p) => /* @__PURE__ */ React60.createElement(EmailLayoutEditor, __spreadValues({}, p))
7083
+ Component: (p) => /* @__PURE__ */ React58.createElement(EmailLayoutEditor, __spreadValues({}, p))
6136
7084
  },
6137
7085
  Spacer: {
6138
7086
  schema: SpacerPropsSchema,
6139
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(spacer_default, __spreadValues({}, props)))
7087
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(spacer_default, __spreadValues({}, props)))
6140
7088
  },
6141
7089
  Divider: {
6142
7090
  schema: DividerPropsSchema,
6143
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(divider_default, __spreadValues({}, props)))
7091
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(divider_default, __spreadValues({}, props)))
6144
7092
  },
6145
7093
  Signature: {
6146
7094
  schema: SignaturePropsSchema,
6147
- Component: (props) => /* @__PURE__ */ React60.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React60.createElement(SignatureEditor, __spreadValues({}, props)))
7095
+ Component: (props) => /* @__PURE__ */ React58.createElement(EditorBlockWrapper, null, /* @__PURE__ */ React58.createElement(SignatureEditor, __spreadValues({}, props)))
6148
7096
  }
6149
7097
  });
6150
7098
  var EditorBlock2 = buildBlockComponent(EDITOR_DICTIONARY);
@@ -6160,7 +7108,7 @@ function EditorBlock({ id }) {
6160
7108
  if (!block) {
6161
7109
  throw new Error("Could not find block");
6162
7110
  }
6163
- return /* @__PURE__ */ React60.createElement(EditorBlockContext.Provider, { value: id }, /* @__PURE__ */ React60.createElement(EditorBlock2, __spreadValues({}, block)));
7111
+ return /* @__PURE__ */ React58.createElement(EditorBlockContext.Provider, { value: id }, /* @__PURE__ */ React58.createElement(EditorBlock2, __spreadValues({}, block)));
6164
7112
  }
6165
7113
  function ToggleInspectorPanelButton() {
6166
7114
  const inspectorDrawerOpen = useInspectorDrawerOpen();
@@ -6168,20 +7116,20 @@ function ToggleInspectorPanelButton() {
6168
7116
  toggleInspectorDrawerOpen();
6169
7117
  };
6170
7118
  if (inspectorDrawerOpen) {
6171
- return /* @__PURE__ */ React60.createElement(IconButton, { onClick: handleClick }, /* @__PURE__ */ React60.createElement(LastPageOutlined, { fontSize: "small" }));
7119
+ return /* @__PURE__ */ React58.createElement(IconButton, { onClick: handleClick }, /* @__PURE__ */ React58.createElement(LastPageOutlined, { fontSize: "small" }));
6172
7120
  }
6173
- return /* @__PURE__ */ React60.createElement(IconButton, { onClick: handleClick }, /* @__PURE__ */ React60.createElement(AppRegistrationOutlined, { fontSize: "small" }));
7121
+ return /* @__PURE__ */ React58.createElement(IconButton, { onClick: handleClick }, /* @__PURE__ */ React58.createElement(AppRegistrationOutlined, { fontSize: "small" }));
6174
7122
  }
6175
7123
  function useIcon() {
6176
7124
  const samplesDrawerOpen = useSamplesDrawerOpen();
6177
7125
  if (samplesDrawerOpen) {
6178
- return /* @__PURE__ */ React60.createElement(FirstPageOutlined, { fontSize: "small" });
7126
+ return /* @__PURE__ */ React58.createElement(FirstPageOutlined, { fontSize: "small" });
6179
7127
  }
6180
- return /* @__PURE__ */ React60.createElement(MenuOutlined, { fontSize: "small" });
7128
+ return /* @__PURE__ */ React58.createElement(MenuOutlined, { fontSize: "small" });
6181
7129
  }
6182
7130
  function ToggleSamplesPanelButton() {
6183
7131
  const icon = useIcon();
6184
- return /* @__PURE__ */ React60.createElement(IconButton, { onClick: toggleSamplesDrawerOpen }, icon);
7132
+ return /* @__PURE__ */ React58.createElement(IconButton, { onClick: toggleSamplesDrawerOpen }, icon);
6185
7133
  }
6186
7134
  function formatHtml(html2, spaces = 2) {
6187
7135
  try {
@@ -6243,7 +7191,7 @@ function HighlightedCodePanel({ type, value }) {
6243
7191
  if (code === null) {
6244
7192
  return null;
6245
7193
  }
6246
- return /* @__PURE__ */ React60.createElement(
7194
+ return /* @__PURE__ */ React58.createElement(
6247
7195
  "pre",
6248
7196
  {
6249
7197
  style: {
@@ -6269,17 +7217,17 @@ function HighlightedCodePanel({ type, value }) {
6269
7217
  function HtmlPanel() {
6270
7218
  const document2 = useDocument();
6271
7219
  const code = useMemo(() => renderToStaticMarkup(document2, { rootBlockId: "root" }), [document2]);
6272
- return /* @__PURE__ */ React60.createElement(HighlightedCodePanel, { type: "html", value: code });
7220
+ return /* @__PURE__ */ React58.createElement(HighlightedCodePanel, { type: "html", value: code });
6273
7221
  }
6274
7222
  function JsonPanel() {
6275
7223
  const document2 = useDocument();
6276
7224
  const code = useMemo(() => JSON.stringify(document2, null, " "), [document2]);
6277
- return /* @__PURE__ */ React60.createElement(HighlightedCodePanel, { type: "json", value: code });
7225
+ return /* @__PURE__ */ React58.createElement(HighlightedCodePanel, { type: "json", value: code });
6278
7226
  }
6279
7227
  function TextPanel() {
6280
7228
  const document2 = useDocument();
6281
7229
  const text = useMemo(() => renderToText(document2, { rootBlockId: "root" }), [document2]);
6282
- return /* @__PURE__ */ React60.createElement(
7230
+ return /* @__PURE__ */ React58.createElement(
6283
7231
  "pre",
6284
7232
  {
6285
7233
  style: {
@@ -6315,35 +7263,35 @@ function MainTabsGroup() {
6315
7263
  setSelectedMainTab("editor");
6316
7264
  }
6317
7265
  };
6318
- return /* @__PURE__ */ React60.createElement(Tabs, { value: selectedMainTab, onChange: handleChange }, /* @__PURE__ */ React60.createElement(
7266
+ return /* @__PURE__ */ React58.createElement(Tabs, { value: selectedMainTab, onChange: handleChange }, /* @__PURE__ */ React58.createElement(
6319
7267
  Tab,
6320
7268
  {
6321
7269
  value: "editor",
6322
- label: /* @__PURE__ */ React60.createElement(Tooltip, { title: "Edit" }, /* @__PURE__ */ React60.createElement(EditOutlined, { fontSize: "small" }))
7270
+ label: /* @__PURE__ */ React58.createElement(Tooltip, { title: "Edit" }, /* @__PURE__ */ React58.createElement(EditOutlined, { fontSize: "small" }))
6323
7271
  }
6324
- ), /* @__PURE__ */ React60.createElement(
7272
+ ), /* @__PURE__ */ React58.createElement(
6325
7273
  Tab,
6326
7274
  {
6327
7275
  value: "preview",
6328
- label: /* @__PURE__ */ React60.createElement(Tooltip, { title: "Preview" }, /* @__PURE__ */ React60.createElement(PreviewOutlined, { fontSize: "small" }))
7276
+ label: /* @__PURE__ */ React58.createElement(Tooltip, { title: "Preview" }, /* @__PURE__ */ React58.createElement(PreviewOutlined, { fontSize: "small" }))
6329
7277
  }
6330
- ), /* @__PURE__ */ React60.createElement(
7278
+ ), /* @__PURE__ */ React58.createElement(
6331
7279
  Tab,
6332
7280
  {
6333
7281
  value: "html",
6334
- label: /* @__PURE__ */ React60.createElement(Tooltip, { title: "HTML output" }, /* @__PURE__ */ React60.createElement(CodeOutlined, { fontSize: "small" }))
7282
+ label: /* @__PURE__ */ React58.createElement(Tooltip, { title: "HTML output" }, /* @__PURE__ */ React58.createElement(CodeOutlined, { fontSize: "small" }))
6335
7283
  }
6336
- ), /* @__PURE__ */ React60.createElement(
7284
+ ), /* @__PURE__ */ React58.createElement(
6337
7285
  Tab,
6338
7286
  {
6339
7287
  value: "text",
6340
- label: /* @__PURE__ */ React60.createElement(Tooltip, { title: "Plain text output" }, /* @__PURE__ */ React60.createElement(SubjectOutlined, { fontSize: "small" }))
7288
+ label: /* @__PURE__ */ React58.createElement(Tooltip, { title: "Plain text output" }, /* @__PURE__ */ React58.createElement(SubjectOutlined, { fontSize: "small" }))
6341
7289
  }
6342
- ), /* @__PURE__ */ React60.createElement(
7290
+ ), /* @__PURE__ */ React58.createElement(
6343
7291
  Tab,
6344
7292
  {
6345
7293
  value: "json",
6346
- label: /* @__PURE__ */ React60.createElement(Tooltip, { title: "JSON output" }, /* @__PURE__ */ React60.createElement(DataObjectOutlined, { fontSize: "small" }))
7294
+ label: /* @__PURE__ */ React58.createElement(Tooltip, { title: "JSON output" }, /* @__PURE__ */ React58.createElement(DataObjectOutlined, { fontSize: "small" }))
6347
7295
  }
6348
7296
  ));
6349
7297
  }
@@ -6389,7 +7337,7 @@ function SaveButton({ loadTemplates, saveAs }) {
6389
7337
  return false;
6390
7338
  }
6391
7339
  });
6392
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
7340
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
6393
7341
  IconButton,
6394
7342
  {
6395
7343
  onClick: handleSave,
@@ -6400,8 +7348,8 @@ function SaveButton({ loadTemplates, saveAs }) {
6400
7348
  }
6401
7349
  }
6402
7350
  },
6403
- /* @__PURE__ */ React60.createElement(Tooltip, { title: isSample ? "Save as new template" : "Save template" }, /* @__PURE__ */ React60.createElement(SaveOutlined, { fontSize: "small" }))
6404
- ), /* @__PURE__ */ React60.createElement(
7351
+ /* @__PURE__ */ React58.createElement(Tooltip, { title: isSample ? "Save as new template" : "Save template" }, /* @__PURE__ */ React58.createElement(SaveOutlined, { fontSize: "small" }))
7352
+ ), /* @__PURE__ */ React58.createElement(
6405
7353
  SaveTemplateDialog,
6406
7354
  {
6407
7355
  open: saveDialogOpen,
@@ -6471,7 +7419,7 @@ function NewTemplateButton({ loadTemplates, saveAs }) {
6471
7419
  }
6472
7420
  return false;
6473
7421
  });
6474
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
7422
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
6475
7423
  IconButton,
6476
7424
  {
6477
7425
  onClick: handleNewTemplate,
@@ -6482,8 +7430,8 @@ function NewTemplateButton({ loadTemplates, saveAs }) {
6482
7430
  }
6483
7431
  }
6484
7432
  },
6485
- /* @__PURE__ */ React60.createElement(Tooltip, { title: "New template" }, /* @__PURE__ */ React60.createElement(Add, { fontSize: "small" }))
6486
- ), /* @__PURE__ */ React60.createElement(
7433
+ /* @__PURE__ */ React58.createElement(Tooltip, { title: "New template" }, /* @__PURE__ */ React58.createElement(Add, { fontSize: "small" }))
7434
+ ), /* @__PURE__ */ React58.createElement(
6487
7435
  SaveTemplateDialog,
6488
7436
  {
6489
7437
  open: saveDialogOpen,
@@ -6510,7 +7458,18 @@ function SubjectInput() {
6510
7458
  root: __spreadProps(__spreadValues({}, root), { data: __spreadProps(__spreadValues({}, data), { subject: value }) })
6511
7459
  });
6512
7460
  };
6513
- return /* @__PURE__ */ React60.createElement(
7461
+ const trackFocus = (e) => {
7462
+ var _a2, _b;
7463
+ const target = e.target;
7464
+ if (!target || typeof target.value !== "string") return;
7465
+ setLastFocusedEditable({
7466
+ blockId: "subject",
7467
+ field: "subject",
7468
+ selectionStart: (_a2 = target.selectionStart) != null ? _a2 : target.value.length,
7469
+ selectionEnd: (_b = target.selectionEnd) != null ? _b : target.value.length
7470
+ });
7471
+ };
7472
+ return /* @__PURE__ */ React58.createElement(
6514
7473
  Box,
6515
7474
  {
6516
7475
  sx: {
@@ -6527,19 +7486,191 @@ function SubjectInput() {
6527
7486
  gap: 1.5
6528
7487
  }
6529
7488
  },
6530
- /* @__PURE__ */ React60.createElement(Box, { sx: { color: "text.secondary", fontSize: 13, fontWeight: 600, minWidth: 56 } }, "Subject"),
6531
- /* @__PURE__ */ React60.createElement(
7489
+ /* @__PURE__ */ React58.createElement(Box, { sx: { color: "text.secondary", fontSize: 13, fontWeight: 600, minWidth: 56 } }, "Subject"),
7490
+ /* @__PURE__ */ React58.createElement(
6532
7491
  InputBase,
6533
7492
  {
6534
7493
  fullWidth: true,
6535
7494
  placeholder: "Email subject \u2014 supports {{variables}}",
6536
7495
  value: subject,
6537
7496
  onChange: (e) => handleChange(e.target.value),
7497
+ onFocus: trackFocus,
7498
+ onSelect: trackFocus,
7499
+ onKeyUp: trackFocus,
7500
+ onClick: trackFocus,
6538
7501
  sx: { fontSize: 14 }
6539
7502
  }
6540
7503
  )
6541
7504
  );
6542
7505
  }
7506
+ function SubjectPreview() {
7507
+ var _a, _b;
7508
+ const document2 = useDocument();
7509
+ const root = document2.root;
7510
+ if (!root || root.type !== "EmailLayout") return null;
7511
+ const data = root.data;
7512
+ const subject = (_a = data.subject) != null ? _a : "";
7513
+ if (!subject) return null;
7514
+ const samples = buildSampleValueMap((_b = data.variables) != null ? _b : []);
7515
+ const rendered = substituteSampleValues(subject, samples);
7516
+ return /* @__PURE__ */ React58.createElement(
7517
+ Box,
7518
+ {
7519
+ sx: {
7520
+ px: 3,
7521
+ py: 1.25,
7522
+ borderBottom: 1,
7523
+ borderColor: "divider",
7524
+ backgroundColor: "white",
7525
+ position: "sticky",
7526
+ top: 49,
7527
+ zIndex: "appBar",
7528
+ display: "flex",
7529
+ alignItems: "center",
7530
+ gap: 1.5
7531
+ }
7532
+ },
7533
+ /* @__PURE__ */ React58.createElement(Box, { sx: { color: "text.secondary", fontSize: 13, fontWeight: 600, minWidth: 56 } }, "Subject"),
7534
+ /* @__PURE__ */ React58.createElement(Box, { sx: { fontSize: 14 } }, rendered)
7535
+ );
7536
+ }
7537
+ function generateId3() {
7538
+ return `block-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
7539
+ }
7540
+ function buildImageBlock(uploaded) {
7541
+ var _a, _b, _c;
7542
+ return {
7543
+ type: "Image",
7544
+ data: {
7545
+ props: {
7546
+ url: uploaded.url,
7547
+ width: (_a = uploaded.width) != null ? _a : null,
7548
+ height: (_b = uploaded.height) != null ? _b : null,
7549
+ alt: (_c = uploaded.alt) != null ? _c : "",
7550
+ contentAlignment: "middle"
7551
+ },
7552
+ style: { padding: { top: 16, bottom: 16, left: 24, right: 24 } }
7553
+ }
7554
+ };
7555
+ }
7556
+ function appendImageBlock(uploaded) {
7557
+ var _a;
7558
+ const doc = getDocument();
7559
+ const root = doc.root;
7560
+ if (!root || root.type !== "EmailLayout") return;
7561
+ const id = generateId3();
7562
+ const childrenIds = [...(_a = root.data.childrenIds) != null ? _a : [], id];
7563
+ setDocument({
7564
+ [id]: buildImageBlock(uploaded),
7565
+ root: __spreadProps(__spreadValues({}, root), { data: __spreadProps(__spreadValues({}, root.data), { childrenIds }) })
7566
+ });
7567
+ setSelectedBlockId(id);
7568
+ }
7569
+ function findImageFile(items) {
7570
+ var _a;
7571
+ if (!items) return null;
7572
+ const fileList = items instanceof FileList ? Array.from(items) : Array.from(items);
7573
+ for (const item of fileList) {
7574
+ const file = item instanceof File ? item : (_a = item.getAsFile) == null ? void 0 : _a.call(item);
7575
+ if (file && file.type.startsWith("image/")) return file;
7576
+ }
7577
+ return null;
7578
+ }
7579
+ function ImageDropPasteHandler({ enabled, children }) {
7580
+ const { uploadImage } = useImageCallbacks();
7581
+ const wrapperRef = useRef(null);
7582
+ const dragDepth = useRef(0);
7583
+ const [dragging, setDragging] = useState(false);
7584
+ const [uploading, setUploading] = useState(false);
7585
+ const active = enabled && Boolean(uploadImage);
7586
+ useEffect(() => {
7587
+ if (!active || !uploadImage) return;
7588
+ const handlePaste = (e) => __async(null, null, function* () {
7589
+ var _a;
7590
+ const target = e.target;
7591
+ if ((target == null ? void 0 : target.tagName) === "INPUT" || (target == null ? void 0 : target.tagName) === "TEXTAREA" || (target == null ? void 0 : target.isContentEditable)) return;
7592
+ const file = findImageFile((_a = e.clipboardData) == null ? void 0 : _a.files);
7593
+ if (!file) return;
7594
+ e.preventDefault();
7595
+ setUploading(true);
7596
+ try {
7597
+ const uploaded = yield uploadImage(file);
7598
+ appendImageBlock(uploaded);
7599
+ } catch (e2) {
7600
+ } finally {
7601
+ setUploading(false);
7602
+ }
7603
+ });
7604
+ window.addEventListener("paste", handlePaste);
7605
+ return () => window.removeEventListener("paste", handlePaste);
7606
+ }, [active, uploadImage]);
7607
+ if (!active) return /* @__PURE__ */ React58.createElement(React58.Fragment, null, children);
7608
+ const onDragEnter = (e) => {
7609
+ var _a, _b;
7610
+ if (!Array.from((_b = (_a = e.dataTransfer) == null ? void 0 : _a.items) != null ? _b : []).some((i) => i.kind === "file")) return;
7611
+ dragDepth.current += 1;
7612
+ setDragging(true);
7613
+ };
7614
+ const onDragLeave = () => {
7615
+ dragDepth.current = Math.max(0, dragDepth.current - 1);
7616
+ if (dragDepth.current === 0) setDragging(false);
7617
+ };
7618
+ const onDragOver = (e) => {
7619
+ var _a, _b;
7620
+ if (!Array.from((_b = (_a = e.dataTransfer) == null ? void 0 : _a.items) != null ? _b : []).some((i) => i.kind === "file")) return;
7621
+ e.preventDefault();
7622
+ e.dataTransfer.dropEffect = "copy";
7623
+ };
7624
+ const onDrop = (e) => __async(null, null, function* () {
7625
+ var _a;
7626
+ dragDepth.current = 0;
7627
+ setDragging(false);
7628
+ const file = findImageFile((_a = e.dataTransfer) == null ? void 0 : _a.files);
7629
+ if (!file || !uploadImage) return;
7630
+ e.preventDefault();
7631
+ setUploading(true);
7632
+ try {
7633
+ const uploaded = yield uploadImage(file);
7634
+ appendImageBlock(uploaded);
7635
+ } catch (e2) {
7636
+ } finally {
7637
+ setUploading(false);
7638
+ }
7639
+ });
7640
+ return /* @__PURE__ */ React58.createElement(
7641
+ Box,
7642
+ {
7643
+ ref: wrapperRef,
7644
+ onDragEnter,
7645
+ onDragLeave,
7646
+ onDragOver,
7647
+ onDrop,
7648
+ sx: { position: "relative" }
7649
+ },
7650
+ children,
7651
+ (dragging || uploading) && /* @__PURE__ */ React58.createElement(
7652
+ Box,
7653
+ {
7654
+ sx: {
7655
+ position: "absolute",
7656
+ inset: 0,
7657
+ backgroundColor: "rgba(33, 150, 243, 0.06)",
7658
+ border: "2px dashed",
7659
+ borderColor: "primary.main",
7660
+ borderRadius: 1,
7661
+ display: "flex",
7662
+ alignItems: "flex-start",
7663
+ justifyContent: "center",
7664
+ paddingTop: 12,
7665
+ color: "primary.dark",
7666
+ pointerEvents: "none",
7667
+ zIndex: 10
7668
+ }
7669
+ },
7670
+ /* @__PURE__ */ React58.createElement(Box, { sx: { display: "flex", alignItems: "center", gap: 1, fontWeight: 600, fontSize: 14 } }, /* @__PURE__ */ React58.createElement(CloudUploadOutlined, null), uploading ? "Uploading\u2026" : "Drop image to insert")
7671
+ )
7672
+ );
7673
+ }
6543
7674
 
6544
7675
  // src/app/email-canvas/index.tsx
6545
7676
  function TemplatePanel2({ loadTemplates, saveAs, samplesDrawerEnabled = true }) {
@@ -6570,21 +7701,29 @@ function TemplatePanel2({ loadTemplates, saveAs, samplesDrawerEnabled = true })
6570
7701
  }
6571
7702
  };
6572
7703
  const renderMainPanel = () => {
7704
+ var _a;
6573
7705
  switch (selectedMainTab) {
6574
7706
  case "editor":
6575
- return /* @__PURE__ */ React60.createElement(Box, { sx: mainBoxSx }, /* @__PURE__ */ React60.createElement(EditorBlock, { id: "root" }));
6576
- case "preview":
6577
- return /* @__PURE__ */ React60.createElement(Box, { sx: mainBoxSx }, /* @__PURE__ */ React60.createElement(Reader, { document: document2, rootBlockId: "root" }));
7707
+ return /* @__PURE__ */ React58.createElement(Box, { sx: mainBoxSx }, /* @__PURE__ */ React58.createElement(EditorBlock, { id: "root" }));
7708
+ case "preview": {
7709
+ const rootBlock = document2.root;
7710
+ const layoutData = rootBlock && rootBlock.type === "EmailLayout" ? rootBlock.data : void 0;
7711
+ const samples = buildSampleValueMap(
7712
+ (_a = layoutData == null ? void 0 : layoutData.variables) != null ? _a : []
7713
+ );
7714
+ const previewDoc = applySampleValuesToDocument(document2, samples);
7715
+ return /* @__PURE__ */ React58.createElement(Box, { sx: mainBoxSx }, /* @__PURE__ */ React58.createElement(Reader, { document: previewDoc, rootBlockId: "root" }));
7716
+ }
6578
7717
  case "html":
6579
- return /* @__PURE__ */ React60.createElement(HtmlPanel, null);
7718
+ return /* @__PURE__ */ React58.createElement(HtmlPanel, null);
6580
7719
  case "text":
6581
- return /* @__PURE__ */ React60.createElement(TextPanel, null);
7720
+ return /* @__PURE__ */ React58.createElement(TextPanel, null);
6582
7721
  case "json":
6583
- return /* @__PURE__ */ React60.createElement(JsonPanel, null);
7722
+ return /* @__PURE__ */ React58.createElement(JsonPanel, null);
6584
7723
  }
6585
7724
  };
6586
7725
  const showSaveButtons = persistenceEnabled;
6587
- return /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(
7726
+ return /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(
6588
7727
  Stack,
6589
7728
  {
6590
7729
  sx: {
@@ -6601,13 +7740,13 @@ function TemplatePanel2({ loadTemplates, saveAs, samplesDrawerEnabled = true })
6601
7740
  justifyContent: "space-between",
6602
7741
  alignItems: "center"
6603
7742
  },
6604
- samplesDrawerEnabled && /* @__PURE__ */ React60.createElement(ToggleSamplesPanelButton, null),
6605
- /* @__PURE__ */ React60.createElement(Stack, { px: 2, direction: "row", gap: 2, width: "100%", justifyContent: "space-between", alignItems: "center" }, /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ React60.createElement(MainTabsGroup, null)), /* @__PURE__ */ React60.createElement(Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ React60.createElement(ToggleButtonGroup, { value: selectedScreenSize, exclusive: true, size: "small", onChange: handleScreenSizeChange }, /* @__PURE__ */ React60.createElement(ToggleButton, { value: "desktop" }, /* @__PURE__ */ React60.createElement(Tooltip, { title: "Desktop view" }, /* @__PURE__ */ React60.createElement(MonitorOutlined, { fontSize: "small" }))), /* @__PURE__ */ React60.createElement(ToggleButton, { value: "mobile" }, /* @__PURE__ */ React60.createElement(Tooltip, { title: "Mobile view" }, /* @__PURE__ */ React60.createElement(PhoneIphoneOutlined, { fontSize: "small" })))), showSaveButtons && /* @__PURE__ */ React60.createElement(React60.Fragment, null, /* @__PURE__ */ React60.createElement(NewTemplateButton, { loadTemplates, saveAs }), /* @__PURE__ */ React60.createElement(SaveButton, { loadTemplates, saveAs })))),
6606
- /* @__PURE__ */ React60.createElement(ToggleInspectorPanelButton, null)
6607
- ), selectedMainTab === "editor" && /* @__PURE__ */ React60.createElement(SubjectInput, null), /* @__PURE__ */ React60.createElement(Box, { sx: {
7743
+ samplesDrawerEnabled && /* @__PURE__ */ React58.createElement(ToggleSamplesPanelButton, null),
7744
+ /* @__PURE__ */ React58.createElement(Stack, { px: 2, direction: "row", gap: 2, width: "100%", justifyContent: "space-between", alignItems: "center" }, /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ React58.createElement(MainTabsGroup, null)), /* @__PURE__ */ React58.createElement(Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ React58.createElement(ToggleButtonGroup, { value: selectedScreenSize, exclusive: true, size: "small", onChange: handleScreenSizeChange }, /* @__PURE__ */ React58.createElement(ToggleButton, { value: "desktop" }, /* @__PURE__ */ React58.createElement(Tooltip, { title: "Desktop view" }, /* @__PURE__ */ React58.createElement(MonitorOutlined, { fontSize: "small" }))), /* @__PURE__ */ React58.createElement(ToggleButton, { value: "mobile" }, /* @__PURE__ */ React58.createElement(Tooltip, { title: "Mobile view" }, /* @__PURE__ */ React58.createElement(PhoneIphoneOutlined, { fontSize: "small" })))), showSaveButtons && /* @__PURE__ */ React58.createElement(React58.Fragment, null, /* @__PURE__ */ React58.createElement(NewTemplateButton, { loadTemplates, saveAs }), /* @__PURE__ */ React58.createElement(SaveButton, { loadTemplates, saveAs })))),
7745
+ /* @__PURE__ */ React58.createElement(ToggleInspectorPanelButton, null)
7746
+ ), selectedMainTab === "editor" && /* @__PURE__ */ React58.createElement(SubjectInput, null), selectedMainTab === "preview" && /* @__PURE__ */ React58.createElement(SubjectPreview, null), /* @__PURE__ */ React58.createElement(ImageDropPasteHandler, { enabled: selectedMainTab === "editor" }, /* @__PURE__ */ React58.createElement(Box, { sx: {
6608
7747
  paddingBottom: "50px",
6609
7748
  minWidth: 370
6610
- } }, renderMainPanel()));
7749
+ } }, renderMainPanel())));
6611
7750
  }
6612
7751
 
6613
7752
  // src/app/index.tsx
@@ -6688,7 +7827,7 @@ var EmailEditorInternal = forwardRef((props, ref) => {
6688
7827
  return getDocument();
6689
7828
  }
6690
7829
  }));
6691
- return /* @__PURE__ */ React60.createElement(Stack, { position: "relative", id: "drawer-container", sx: { minHeight } }, /* @__PURE__ */ React60.createElement(
7830
+ return /* @__PURE__ */ React58.createElement(Stack, { position: "relative", id: "drawer-container", sx: { minHeight } }, /* @__PURE__ */ React58.createElement(
6692
7831
  InspectorDrawer,
6693
7832
  {
6694
7833
  enterDuration: drawerEnterDuration,
@@ -6696,7 +7835,7 @@ var EmailEditorInternal = forwardRef((props, ref) => {
6696
7835
  deleteTemplate,
6697
7836
  copyTemplate
6698
7837
  }
6699
- ), /* @__PURE__ */ React60.createElement(
7838
+ ), /* @__PURE__ */ React58.createElement(
6700
7839
  SamplesDrawer,
6701
7840
  {
6702
7841
  enterDuration: drawerEnterDuration,
@@ -6712,7 +7851,7 @@ var EmailEditorInternal = forwardRef((props, ref) => {
6712
7851
  setTemplateKind,
6713
7852
  saveAs
6714
7853
  }
6715
- ), /* @__PURE__ */ React60.createElement(
7854
+ ), /* @__PURE__ */ React58.createElement(
6716
7855
  Stack,
6717
7856
  {
6718
7857
  sx: {
@@ -6721,7 +7860,7 @@ var EmailEditorInternal = forwardRef((props, ref) => {
6721
7860
  transition: [marginLeftTransition, marginRightTransition].join(", ")
6722
7861
  }
6723
7862
  },
6724
- /* @__PURE__ */ React60.createElement(TemplatePanel2, { loadTemplates, saveAs, samplesDrawerEnabled })
7863
+ /* @__PURE__ */ React58.createElement(TemplatePanel2, { loadTemplates, saveAs, samplesDrawerEnabled })
6725
7864
  ));
6726
7865
  });
6727
7866
  var EmailEditor = forwardRef((props, ref) => {
@@ -6744,6 +7883,9 @@ var EmailEditor = forwardRef((props, ref) => {
6744
7883
  renameTemplate,
6745
7884
  setTemplateKind,
6746
7885
  saveAs,
7886
+ uploadImage,
7887
+ loadImages,
7888
+ deleteImage,
6747
7889
  theme
6748
7890
  } = props;
6749
7891
  const resolvedTemplate = useMemo(
@@ -6758,7 +7900,11 @@ var EmailEditor = forwardRef((props, ref) => {
6758
7900
  useEffect(() => {
6759
7901
  setPersistenceEnabled(persistenceEnabled);
6760
7902
  }, [persistenceEnabled]);
6761
- return /* @__PURE__ */ React60.createElement(ThemeProvider, { theme: theme || theme_default }, /* @__PURE__ */ React60.createElement(CssBaseline, null), /* @__PURE__ */ React60.createElement("div", { style: { height: "100%", overflow: "auto" } }, /* @__PURE__ */ React60.createElement(SnackbarProvider, null, /* @__PURE__ */ React60.createElement(
7903
+ const imageCallbacks = useMemo(
7904
+ () => ({ uploadImage, loadImages, deleteImage }),
7905
+ [uploadImage, loadImages, deleteImage]
7906
+ );
7907
+ return /* @__PURE__ */ React58.createElement(ThemeProvider, { theme: theme || theme_default }, /* @__PURE__ */ React58.createElement(CssBaseline, null), /* @__PURE__ */ React58.createElement("div", { style: { height: "100%", overflow: "auto" } }, /* @__PURE__ */ React58.createElement(SnackbarProvider, null, /* @__PURE__ */ React58.createElement(ImageCallbacksProvider, { callbacks: imageCallbacks }, /* @__PURE__ */ React58.createElement(
6762
7908
  EmailEditorProvider,
6763
7909
  {
6764
7910
  initialTemplate: resolvedTemplate,
@@ -6767,7 +7913,7 @@ var EmailEditor = forwardRef((props, ref) => {
6767
7913
  onSave,
6768
7914
  onChange
6769
7915
  },
6770
- /* @__PURE__ */ React60.createElement(
7916
+ /* @__PURE__ */ React58.createElement(
6771
7917
  EmailEditorInternal,
6772
7918
  {
6773
7919
  ref,
@@ -6786,7 +7932,7 @@ var EmailEditor = forwardRef((props, ref) => {
6786
7932
  onChange
6787
7933
  }
6788
7934
  )
6789
- ))));
7935
+ )))));
6790
7936
  });
6791
7937
  EmailEditor.displayName = "EmailEditor";
6792
7938
  EmailEditorInternal.displayName = "EmailEditorInternal";