@mjml-agent-editor/editor 0.1.5 → 0.1.7

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.cjs CHANGED
@@ -33,24 +33,101 @@ var index_exports = {};
33
33
  __export(index_exports, {
34
34
  CanvasComments: () => CanvasComments,
35
35
  ChatPanel: () => ChatPanel,
36
+ DEFAULT_LABELS: () => DEFAULT_LABELS,
36
37
  EditorHeader: () => EditorHeader,
37
38
  EditorStoreProvider: () => EditorStoreProvider,
38
39
  Markdown: () => Markdown,
39
40
  STARTER_MJML: () => import_core.STARTER_MJML,
41
+ mergeLabels: () => mergeLabels,
40
42
  useCommentStore: () => useCommentStore,
41
- useDocumentStore: () => useDocumentStore
43
+ useDocumentStore: () => useDocumentStore,
44
+ useLabels: () => useLabels
42
45
  });
43
46
  module.exports = __toCommonJS(index_exports);
44
47
 
45
48
  // src/stores.tsx
46
49
  var import_react = require("react");
50
+
51
+ // src/labels.ts
52
+ var DEFAULT_LABELS = {
53
+ appName: "MJML Editor",
54
+ emailNameAria: "Email name",
55
+ renameFailed: "Failed to rename.",
56
+ saving: "Saving\u2026",
57
+ saved: "Saved",
58
+ saveFailed: "Save failed",
59
+ undo: "Undo",
60
+ redo: "Redo",
61
+ contentWidth: "Content width",
62
+ preview: "Preview",
63
+ closePreview: "Close preview",
64
+ previewFrameTitle: "Email preview",
65
+ sourceCode: "Source code",
66
+ exportHtml: "Export HTML",
67
+ exportMjml: "Export MJML",
68
+ copied: (kind) => `${kind} copied.`,
69
+ searchBlocks: "Search blocks\u2026",
70
+ expandAll: "Expand all",
71
+ selectAnElement: "Select an element\u2026",
72
+ attributes: "Attributes",
73
+ style: "Style",
74
+ rteFont: "Font",
75
+ rteSize: "Size",
76
+ rteTextColor: "Text color",
77
+ rteBackgroundColor: "Background color",
78
+ documentLoadFailed: "Failed to load the document.",
79
+ documentSaveFailed: "Failed to save changes.",
80
+ commentOnSection: "Comment on the whole section",
81
+ closeComments: "Close",
82
+ noCommentsYet: "No comments yet \u2014 add the first one.",
83
+ resolveComment: "Resolve",
84
+ addComment: "Add",
85
+ addCommentPlaceholder: "Add a comment\u2026 (\u2318/Ctrl+Enter to send)",
86
+ chatEmptyTitle: "Start a conversation with the agent",
87
+ chatEmptyDescription: "Describe the email (goal, tone, content) and paste your data \u2014 the agent will design the sections and images.",
88
+ agentWorking: "Agent is working\u2026",
89
+ reasoning: "Reasoning",
90
+ completedSteps: (count, failed) => failed > 0 ? `Completed steps (${count}, ${failed} failed)` : `Completed steps (${count})`,
91
+ applyComments: "Apply changes from comments",
92
+ chatPlaceholder: "Describe what you want to change\u2026 (Enter = send, Shift+Enter = new line)",
93
+ stop: "Stop",
94
+ send: "Send",
95
+ chatError: "Agent chat error.",
96
+ toolLabels: {
97
+ get_document: "Reading document",
98
+ get_section: "Reading section",
99
+ set_document: "Saving whole email",
100
+ set_section: "Replacing section",
101
+ insert_section: "Adding section",
102
+ remove_section: "Removing section",
103
+ generate_image: "Generating image",
104
+ list_open_comments: "Reading comments",
105
+ resolve_comment: "Resolving comment"
106
+ }
107
+ };
108
+ function mergeLabels(overrides) {
109
+ if (!overrides) return DEFAULT_LABELS;
110
+ return {
111
+ ...DEFAULT_LABELS,
112
+ ...overrides,
113
+ toolLabels: { ...DEFAULT_LABELS.toolLabels, ...overrides.toolLabels }
114
+ };
115
+ }
116
+
117
+ // src/stores.tsx
47
118
  var import_jsx_runtime = require("react/jsx-runtime");
48
119
  var StoreContext = (0, import_react.createContext)(null);
120
+ var LabelContext = (0, import_react.createContext)(null);
49
121
  function EditorStoreProvider({
50
122
  stores,
123
+ labels,
51
124
  children
52
125
  }) {
53
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StoreContext.Provider, { value: stores, children });
126
+ const merged = (0, import_react.useMemo)(() => mergeLabels(labels), [labels]);
127
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StoreContext.Provider, { value: stores, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LabelContext.Provider, { value: merged, children }) });
128
+ }
129
+ function useLabels() {
130
+ return (0, import_react.useContext)(LabelContext) ?? mergeLabels();
54
131
  }
55
132
  function useStores() {
56
133
  const stores = (0, import_react.useContext)(StoreContext);
@@ -553,29 +630,24 @@ function DialogTitle({ className, ...props }) {
553
630
 
554
631
  // src/components/editor/EditorHeader.tsx
555
632
  var import_jsx_runtime13 = require("react/jsx-runtime");
556
- var SAVE_LABEL = {
557
- idle: "",
558
- saving: "Saving\u2026",
559
- saved: "Saved",
560
- error: "Save failed"
561
- };
562
633
  var WIDTHS = ["600px", "640px", "680px", "720px"];
563
634
  var DEVICE_ICON = {
564
635
  Desktop: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Monitor, { className: "size-3.5" }),
565
636
  Mobile: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Smartphone, { className: "size-3.5" })
566
637
  };
567
638
  function SaveBadge({ status }) {
639
+ const labels = useLabels();
568
640
  if (status === "idle") return null;
569
641
  if (status === "saving")
570
642
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1 text-xs text-panel-muted-fg", children: [
571
643
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Spinner, { className: "size-3" }),
572
644
  " ",
573
- SAVE_LABEL.saving
645
+ labels.saving
574
646
  ] });
575
- if (status === "error") return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "destructive", children: SAVE_LABEL.error });
647
+ if (status === "error") return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "destructive", children: labels.saveFailed });
576
648
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-xs text-emerald-400", children: [
577
649
  "\u2713 ",
578
- SAVE_LABEL.saved
650
+ labels.saved
579
651
  ] });
580
652
  }
581
653
  function slugify(name) {
@@ -595,9 +667,11 @@ function EditorHeader({
595
667
  docId,
596
668
  api,
597
669
  openCount,
598
- homeLink
670
+ homeLink,
671
+ logo
599
672
  }) {
600
673
  const documents = useDocumentStore();
674
+ const labels = useLabels();
601
675
  const [name, setName] = (0, import_react2.useState)("");
602
676
  const [state, setState] = (0, import_react2.useState)({
603
677
  device: "Desktop",
@@ -623,15 +697,15 @@ function EditorHeader({
623
697
  try {
624
698
  await documents.save(docId, { name: n });
625
699
  } catch {
626
- import_sonner.toast.error("Failed to rename.");
700
+ import_sonner.toast.error(labels.renameFailed);
627
701
  }
628
702
  };
629
703
  const devices = api?.getDevices() ?? [];
630
704
  const base = slugify(name);
631
705
  const openCode = () => setCode({ mjml: api?.getMjml() ?? "", html: api?.getCompiledHtml() ?? "" });
632
706
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b border-panel-border bg-panel px-3 text-panel-fg", children: [
633
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-brand to-indigo-400 text-brand-fg shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Mail, { className: "size-4" }) }),
634
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "hidden text-sm font-semibold sm:inline", children: "MJML Editor" }),
707
+ logo ?? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-brand to-indigo-400 text-brand-fg shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Mail, { className: "size-4" }) }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "hidden text-sm font-semibold sm:inline", children: labels.appName }),
635
709
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border" }),
636
710
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
637
711
  Input,
@@ -641,7 +715,7 @@ function EditorHeader({
641
715
  onBlur: () => void commitName(),
642
716
  onKeyDown: (e) => e.key === "Enter" && e.currentTarget.blur(),
643
717
  className: "h-8 w-44 border-transparent bg-transparent text-sm font-medium text-panel-fg hover:border-panel-border focus-visible:border-panel-border",
644
- "aria-label": "Email name"
718
+ "aria-label": labels.emailNameAria
645
719
  }
646
720
  ),
647
721
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border" }),
@@ -679,7 +753,7 @@ function EditorHeader({
679
753
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Undo2, {})
680
754
  }
681
755
  ) }),
682
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: "Undo" })
756
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: labels.undo })
683
757
  ] }),
684
758
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tooltip, { children: [
685
759
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
@@ -693,7 +767,7 @@ function EditorHeader({
693
767
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Redo2, {})
694
768
  }
695
769
  ) }),
696
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: "Redo" })
770
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: labels.redo })
697
771
  ] }),
698
772
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border max-xl:hidden" }),
699
773
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Popover, { children: [
@@ -704,7 +778,7 @@ function EditorHeader({
704
778
  size: "sm",
705
779
  className: cn(darkGhost, "gap-1.5 rounded-md border border-panel-border max-xl:hidden"),
706
780
  children: [
707
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-panel-muted-fg", children: "Content width" }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-panel-muted-fg", children: labels.contentWidth }),
708
782
  state.contentWidth,
709
783
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.ChevronDown, { className: "size-3.5" })
710
784
  ]
@@ -766,7 +840,8 @@ function EditorHeader({
766
840
  onClick: () => setPreview(api?.getCompiledHtml() ?? ""),
767
841
  children: [
768
842
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Eye, {}),
769
- " Preview"
843
+ " ",
844
+ labels.preview
770
845
  ]
771
846
  }
772
847
  ) }),
@@ -778,7 +853,8 @@ function EditorHeader({
778
853
  children: [
779
854
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex h-12 shrink-0 items-center justify-between border-b bg-white px-4", children: [
780
855
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogTitle, { className: "text-sm", children: [
781
- "Preview \u2014 ",
856
+ labels.preview,
857
+ " \u2014 ",
782
858
  name
783
859
  ] }),
784
860
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -805,13 +881,13 @@ function EditorHeader({
805
881
  ]
806
882
  }
807
883
  ),
808
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Button, { variant: "ghost", size: "icon", "aria-label": "Close preview", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.X, {}) }) })
884
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Button, { variant: "ghost", size: "icon", "aria-label": labels.closePreview, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.X, {}) }) })
809
885
  ] })
810
886
  ] }),
811
887
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-h-0 flex-1 overflow-auto p-6", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
812
888
  "iframe",
813
889
  {
814
- title: "Email preview",
890
+ title: labels.previewFrameTitle,
815
891
  srcDoc: preview,
816
892
  className: cn(
817
893
  "mx-auto block h-full min-h-[80vh] rounded-md border bg-white shadow-sm",
@@ -838,7 +914,7 @@ function EditorHeader({
838
914
  }
839
915
  ) }),
840
916
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogContent, { className: "flex !max-w-4xl flex-col", children: [
841
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogTitle, { children: "Source code" }) }),
917
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogTitle, { children: labels.sourceCode }) }),
842
918
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tabs, { defaultValue: "mjml", className: "min-h-0 flex-1", children: [
843
919
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(TabsList, { children: [
844
920
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TabsTrigger, { value: "mjml", children: "MJML" }),
@@ -871,7 +947,7 @@ function EditorHeader({
871
947
  size: "sm",
872
948
  onClick: () => {
873
949
  void navigator.clipboard?.writeText(code[kind]);
874
- import_sonner.toast.success(`${kind.toUpperCase()} copied.`);
950
+ import_sonner.toast.success(labels.copied(kind.toUpperCase()));
875
951
  },
876
952
  children: [
877
953
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Copy, {}),
@@ -897,7 +973,7 @@ function EditorHeader({
897
973
  onClick: () => download(`${base}.html`, api?.getCompiledHtml() ?? "", "text/html"),
898
974
  className: "flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted",
899
975
  children: [
900
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: "Export HTML" }),
976
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: labels.exportHtml }),
901
977
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
902
978
  base,
903
979
  ".html"
@@ -911,7 +987,7 @@ function EditorHeader({
911
987
  onClick: () => download(`${base}.mjml`, api?.getMjml() ?? "", "text/plain"),
912
988
  className: "flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted",
913
989
  children: [
914
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: "Export MJML" }),
990
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: labels.exportMjml }),
915
991
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
916
992
  base,
917
993
  ".mjml"
@@ -1365,17 +1441,6 @@ function MessageScrollerButton({
1365
1441
 
1366
1442
  // src/components/chat/ChatPanel.tsx
1367
1443
  var import_jsx_runtime22 = require("react/jsx-runtime");
1368
- var TOOL_LABELS = {
1369
- get_document: "Reading document",
1370
- get_section: "Reading section",
1371
- set_document: "Saving whole email",
1372
- set_section: "Replacing section",
1373
- insert_section: "Adding section",
1374
- remove_section: "Removing section",
1375
- generate_image: "Generating image",
1376
- list_open_comments: "Reading comments",
1377
- resolve_comment: "Resolving comment"
1378
- };
1379
1444
  var APPLY_COMMENTS_PROMPT = "Apply changes based on all open section comments. After each successful change mark the comment as resolved and summarize what you changed.";
1380
1445
  var MUTATING_TOOLS = /* @__PURE__ */ new Set([
1381
1446
  "set_document",
@@ -1423,24 +1488,27 @@ function toBlocks(parts) {
1423
1488
  return blocks;
1424
1489
  }
1425
1490
  function ToolMarker({ tool }) {
1491
+ const labels = useLabels();
1426
1492
  const name = tool.type.slice(5);
1427
1493
  const done = tool.state === "output-available";
1428
1494
  const failed = tool.state === "output-error";
1429
1495
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Marker, { className: cn(failed ? "text-destructive" : "text-panel-fg"), children: [
1430
1496
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MarkerIcon, { children: failed ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.TriangleAlert, {}) : done ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Check, { className: "text-emerald-400" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Loader2, { className: "animate-spin" }) }),
1431
1497
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(MarkerContent, { children: [
1432
- TOOL_LABELS[name] ?? name,
1498
+ labels.toolLabels[name] ?? name,
1433
1499
  failed && tool.errorText ? `: ${tool.errorText}` : ""
1434
1500
  ] })
1435
1501
  ] });
1436
1502
  }
1437
1503
  function BusyMarker() {
1504
+ const labels = useLabels();
1438
1505
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Marker, { className: "text-panel-fg", children: [
1439
1506
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MarkerIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Loader2, { className: "animate-spin" }) }),
1440
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MarkerContent, { children: "Agent is working\u2026" })
1507
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MarkerContent, { children: labels.agentWorking })
1441
1508
  ] });
1442
1509
  }
1443
1510
  function ToolActivity({ tools }) {
1511
+ const labels = useLabels();
1444
1512
  const running = tools.filter((t) => t.state !== "output-available" && t.state !== "output-error");
1445
1513
  const finished = tools.filter(
1446
1514
  (t) => t.state === "output-available" || t.state === "output-error"
@@ -1450,7 +1518,7 @@ function ToolActivity({ tools }) {
1450
1518
  finished.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Collapsible, { children: [
1451
1519
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CollapsibleTrigger, { className: "group/col flex w-full items-center gap-1.5 text-left text-xs font-medium text-panel-fg hover:text-panel-fg", children: [
1452
1520
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.ChevronRight, { className: "size-3.5 shrink-0 transition-transform group-data-[state=open]/col:rotate-90" }),
1453
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: failedCount > 0 ? `Completed steps (${finished.length}, ${failedCount} failed)` : `Completed steps (${finished.length})` })
1521
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: labels.completedSteps(finished.length, failedCount) })
1454
1522
  ] }),
1455
1523
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CollapsibleContent, { className: "mt-1 space-y-0.5 pl-1", children: finished.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolMarker, { tool: t }, `f${i}`)) })
1456
1524
  ] }),
@@ -1458,11 +1526,12 @@ function ToolActivity({ tools }) {
1458
1526
  ] });
1459
1527
  }
1460
1528
  function ReasoningBlock({ text }) {
1529
+ const labels = useLabels();
1461
1530
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "rounded-lg border border-panel-border bg-panel-elevated/60 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Collapsible, { children: [
1462
1531
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CollapsibleTrigger, { className: "group/col flex w-full items-center gap-1.5 text-left text-xs font-medium text-panel-muted-fg hover:text-panel-fg", children: [
1463
1532
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.ChevronRight, { className: "size-3.5 shrink-0 transition-transform group-data-[state=open]/col:rotate-90" }),
1464
1533
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Brain, { className: "size-3.5 shrink-0" }),
1465
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: "Reasoning" })
1534
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: labels.reasoning })
1466
1535
  ] }),
1467
1536
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CollapsibleContent, { className: "mt-1.5 pl-1 text-xs whitespace-pre-wrap text-panel-muted-fg", children: text })
1468
1537
  ] }) });
@@ -1477,6 +1546,7 @@ function ChatPanel({
1477
1546
  onSectionEditStart,
1478
1547
  onSectionEditEnd
1479
1548
  }) {
1549
+ const labels = useLabels();
1480
1550
  const [input, setInput] = (0, import_react5.useState)("");
1481
1551
  const taRef = (0, import_react5.useRef)(null);
1482
1552
  const times = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
@@ -1499,7 +1569,7 @@ function ChatPanel({
1499
1569
  onFinish: onAgentFinish,
1500
1570
  onError: (e) => {
1501
1571
  console.error("chat error:", e);
1502
- import_sonner2.toast.error("Agent chat error.");
1572
+ import_sonner2.toast.error(labels.chatError);
1503
1573
  }
1504
1574
  });
1505
1575
  const firedTools = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
@@ -1561,8 +1631,8 @@ function ChatPanel({
1561
1631
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MessageScrollerViewport, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(MessageScrollerContent, { className: "p-3", children: [
1562
1632
  messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Empty, { className: "h-full", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(EmptyHeader, { children: [
1563
1633
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyMedia, { variant: "icon", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.MessageSquare, {}) }),
1564
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyTitle, { children: "Start a conversation with the agent" }),
1565
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyDescription, { children: "Describe the email (goal, tone, content) and paste your data \u2014 the agent will design the sections and images." })
1634
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyTitle, { children: labels.chatEmptyTitle }),
1635
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyDescription, { children: labels.chatEmptyDescription })
1566
1636
  ] }) }) : messages.map((message, mi) => {
1567
1637
  const isUser = message.role === "user";
1568
1638
  const isLast = mi === messages.length - 1;
@@ -1637,7 +1707,8 @@ function ChatPanel({
1637
1707
  onClick: () => void send(APPLY_COMMENTS_PROMPT),
1638
1708
  children: [
1639
1709
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Sparkles, {}),
1640
- " Apply changes from comments"
1710
+ " ",
1711
+ labels.applyComments
1641
1712
  ]
1642
1713
  }
1643
1714
  ),
@@ -1656,7 +1727,7 @@ function ChatPanel({
1656
1727
  ref: taRef,
1657
1728
  rows: 2,
1658
1729
  className: "max-h-40 min-h-14 resize-none border-0 bg-transparent px-3 pt-2.5 text-panel-fg shadow-none placeholder:text-panel-muted-fg focus-visible:ring-0",
1659
- placeholder: "Describe what you want to change\u2026 (Enter = send, Shift+Enter = new line)",
1730
+ placeholder: labels.chatPlaceholder,
1660
1731
  value: input,
1661
1732
  onChange: (e) => {
1662
1733
  setInput(e.target.value);
@@ -1681,7 +1752,8 @@ function ChatPanel({
1681
1752
  onClick: () => void stop(),
1682
1753
  children: [
1683
1754
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Square, {}),
1684
- " Stop"
1755
+ " ",
1756
+ labels.stop
1685
1757
  ]
1686
1758
  }
1687
1759
  ),
@@ -1694,7 +1766,8 @@ function ChatPanel({
1694
1766
  className: "bg-brand text-brand-fg hover:bg-brand/90",
1695
1767
  children: [
1696
1768
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Send, {}),
1697
- " Send"
1769
+ " ",
1770
+ labels.send
1698
1771
  ]
1699
1772
  }
1700
1773
  )
@@ -1721,6 +1794,7 @@ function CanvasComments({
1721
1794
  onOpenCountChange
1722
1795
  }) {
1723
1796
  const commentStore = useCommentStore();
1797
+ const labels = useLabels();
1724
1798
  const editor = (0, import_react6.useEditorMaybe)();
1725
1799
  const containerRef = (0, import_react7.useRef)(null);
1726
1800
  const [comments, setComments] = (0, import_react7.useState)([]);
@@ -1909,7 +1983,7 @@ function CanvasComments({
1909
1983
  " ",
1910
1984
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-medium text-foreground", children: activeTarget.objectLabel })
1911
1985
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1912
- "Comment on the whole section",
1986
+ labels.commentOnSection,
1913
1987
  " ",
1914
1988
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("code", { className: "font-mono", children: activeTarget?.sectionId })
1915
1989
  ] }) }),
@@ -1918,14 +1992,14 @@ function CanvasComments({
1918
1992
  {
1919
1993
  type: "button",
1920
1994
  onClick: closePopover,
1921
- "aria-label": "Close",
1995
+ "aria-label": labels.closeComments,
1922
1996
  className: "-mr-1 -mt-0.5 shrink-0 rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
1923
1997
  children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.X, { className: "size-4" })
1924
1998
  }
1925
1999
  )
1926
2000
  ] }),
1927
2001
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "max-h-64 space-y-2 overflow-y-auto p-3", children: [
1928
- activeComments.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-xs text-muted-foreground", children: "No comments yet \u2014 add the first one." }),
2002
+ activeComments.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-xs text-muted-foreground", children: labels.noCommentsYet }),
1929
2003
  activeComments.map((c) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "rounded-md border bg-muted/40 p-2 text-sm", children: [
1930
2004
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "whitespace-pre-wrap", children: c.body }),
1931
2005
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
@@ -1935,7 +2009,8 @@ function CanvasComments({
1935
2009
  className: "mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground",
1936
2010
  children: [
1937
2011
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.Check, { className: "size-3" }),
1938
- " Resolve"
2012
+ " ",
2013
+ labels.resolveComment
1939
2014
  ]
1940
2015
  }
1941
2016
  )
@@ -1948,7 +2023,7 @@ function CanvasComments({
1948
2023
  autoFocus: true,
1949
2024
  value: body,
1950
2025
  onChange: (e) => setBody(e.target.value),
1951
- placeholder: "Add a comment\u2026 (\u2318/Ctrl+Enter to send)",
2026
+ placeholder: labels.addCommentPlaceholder,
1952
2027
  className: "min-h-14 resize-none text-sm",
1953
2028
  onKeyDown: (e) => {
1954
2029
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
@@ -1960,7 +2035,8 @@ function CanvasComments({
1960
2035
  ),
1961
2036
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Button, { size: "sm", disabled: !body.trim(), onClick: () => void submit(), children: [
1962
2037
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.MessageSquarePlus, {}),
1963
- " Add"
2038
+ " ",
2039
+ labels.addComment
1964
2040
  ] }) })
1965
2041
  ] })
1966
2042
  ]
@@ -1973,11 +2049,14 @@ function CanvasComments({
1973
2049
  0 && (module.exports = {
1974
2050
  CanvasComments,
1975
2051
  ChatPanel,
2052
+ DEFAULT_LABELS,
1976
2053
  EditorHeader,
1977
2054
  EditorStoreProvider,
1978
2055
  Markdown,
1979
2056
  STARTER_MJML,
2057
+ mergeLabels,
1980
2058
  useCommentStore,
1981
- useDocumentStore
2059
+ useDocumentStore,
2060
+ useLabels
1982
2061
  });
1983
2062
  //# sourceMappingURL=index.cjs.map