@mjml-agent-editor/editor 0.1.5 → 0.1.6

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) {
@@ -598,6 +670,7 @@ function EditorHeader({
598
670
  homeLink
599
671
  }) {
600
672
  const documents = useDocumentStore();
673
+ const labels = useLabels();
601
674
  const [name, setName] = (0, import_react2.useState)("");
602
675
  const [state, setState] = (0, import_react2.useState)({
603
676
  device: "Desktop",
@@ -623,7 +696,7 @@ function EditorHeader({
623
696
  try {
624
697
  await documents.save(docId, { name: n });
625
698
  } catch {
626
- import_sonner.toast.error("Failed to rename.");
699
+ import_sonner.toast.error(labels.renameFailed);
627
700
  }
628
701
  };
629
702
  const devices = api?.getDevices() ?? [];
@@ -631,7 +704,7 @@ function EditorHeader({
631
704
  const openCode = () => setCode({ mjml: api?.getMjml() ?? "", html: api?.getCompiledHtml() ?? "" });
632
705
  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
706
  /* @__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
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "hidden text-sm font-semibold sm:inline", children: labels.appName }),
635
708
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border" }),
636
709
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
637
710
  Input,
@@ -641,7 +714,7 @@ function EditorHeader({
641
714
  onBlur: () => void commitName(),
642
715
  onKeyDown: (e) => e.key === "Enter" && e.currentTarget.blur(),
643
716
  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"
717
+ "aria-label": labels.emailNameAria
645
718
  }
646
719
  ),
647
720
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border" }),
@@ -679,7 +752,7 @@ function EditorHeader({
679
752
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Undo2, {})
680
753
  }
681
754
  ) }),
682
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: "Undo" })
755
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: labels.undo })
683
756
  ] }),
684
757
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tooltip, { children: [
685
758
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
@@ -693,7 +766,7 @@ function EditorHeader({
693
766
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Redo2, {})
694
767
  }
695
768
  ) }),
696
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: "Redo" })
769
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: labels.redo })
697
770
  ] }),
698
771
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border max-xl:hidden" }),
699
772
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Popover, { children: [
@@ -704,7 +777,7 @@ function EditorHeader({
704
777
  size: "sm",
705
778
  className: cn(darkGhost, "gap-1.5 rounded-md border border-panel-border max-xl:hidden"),
706
779
  children: [
707
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-panel-muted-fg", children: "Content width" }),
780
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-panel-muted-fg", children: labels.contentWidth }),
708
781
  state.contentWidth,
709
782
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.ChevronDown, { className: "size-3.5" })
710
783
  ]
@@ -766,7 +839,8 @@ function EditorHeader({
766
839
  onClick: () => setPreview(api?.getCompiledHtml() ?? ""),
767
840
  children: [
768
841
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Eye, {}),
769
- " Preview"
842
+ " ",
843
+ labels.preview
770
844
  ]
771
845
  }
772
846
  ) }),
@@ -778,7 +852,8 @@ function EditorHeader({
778
852
  children: [
779
853
  /* @__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
854
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogTitle, { className: "text-sm", children: [
781
- "Preview \u2014 ",
855
+ labels.preview,
856
+ " \u2014 ",
782
857
  name
783
858
  ] }),
784
859
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -805,13 +880,13 @@ function EditorHeader({
805
880
  ]
806
881
  }
807
882
  ),
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, {}) }) })
883
+ /* @__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
884
  ] })
810
885
  ] }),
811
886
  /* @__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
887
  "iframe",
813
888
  {
814
- title: "Email preview",
889
+ title: labels.previewFrameTitle,
815
890
  srcDoc: preview,
816
891
  className: cn(
817
892
  "mx-auto block h-full min-h-[80vh] rounded-md border bg-white shadow-sm",
@@ -838,7 +913,7 @@ function EditorHeader({
838
913
  }
839
914
  ) }),
840
915
  /* @__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" }) }),
916
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogTitle, { children: labels.sourceCode }) }),
842
917
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tabs, { defaultValue: "mjml", className: "min-h-0 flex-1", children: [
843
918
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(TabsList, { children: [
844
919
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TabsTrigger, { value: "mjml", children: "MJML" }),
@@ -871,7 +946,7 @@ function EditorHeader({
871
946
  size: "sm",
872
947
  onClick: () => {
873
948
  void navigator.clipboard?.writeText(code[kind]);
874
- import_sonner.toast.success(`${kind.toUpperCase()} copied.`);
949
+ import_sonner.toast.success(labels.copied(kind.toUpperCase()));
875
950
  },
876
951
  children: [
877
952
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.Copy, {}),
@@ -897,7 +972,7 @@ function EditorHeader({
897
972
  onClick: () => download(`${base}.html`, api?.getCompiledHtml() ?? "", "text/html"),
898
973
  className: "flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted",
899
974
  children: [
900
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: "Export HTML" }),
975
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: labels.exportHtml }),
901
976
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
902
977
  base,
903
978
  ".html"
@@ -911,7 +986,7 @@ function EditorHeader({
911
986
  onClick: () => download(`${base}.mjml`, api?.getMjml() ?? "", "text/plain"),
912
987
  className: "flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted",
913
988
  children: [
914
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: "Export MJML" }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: labels.exportMjml }),
915
990
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
916
991
  base,
917
992
  ".mjml"
@@ -1365,17 +1440,6 @@ function MessageScrollerButton({
1365
1440
 
1366
1441
  // src/components/chat/ChatPanel.tsx
1367
1442
  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
1443
  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
1444
  var MUTATING_TOOLS = /* @__PURE__ */ new Set([
1381
1445
  "set_document",
@@ -1423,24 +1487,27 @@ function toBlocks(parts) {
1423
1487
  return blocks;
1424
1488
  }
1425
1489
  function ToolMarker({ tool }) {
1490
+ const labels = useLabels();
1426
1491
  const name = tool.type.slice(5);
1427
1492
  const done = tool.state === "output-available";
1428
1493
  const failed = tool.state === "output-error";
1429
1494
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Marker, { className: cn(failed ? "text-destructive" : "text-panel-fg"), children: [
1430
1495
  /* @__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
1496
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(MarkerContent, { children: [
1432
- TOOL_LABELS[name] ?? name,
1497
+ labels.toolLabels[name] ?? name,
1433
1498
  failed && tool.errorText ? `: ${tool.errorText}` : ""
1434
1499
  ] })
1435
1500
  ] });
1436
1501
  }
1437
1502
  function BusyMarker() {
1503
+ const labels = useLabels();
1438
1504
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Marker, { className: "text-panel-fg", children: [
1439
1505
  /* @__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" })
1506
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MarkerContent, { children: labels.agentWorking })
1441
1507
  ] });
1442
1508
  }
1443
1509
  function ToolActivity({ tools }) {
1510
+ const labels = useLabels();
1444
1511
  const running = tools.filter((t) => t.state !== "output-available" && t.state !== "output-error");
1445
1512
  const finished = tools.filter(
1446
1513
  (t) => t.state === "output-available" || t.state === "output-error"
@@ -1450,7 +1517,7 @@ function ToolActivity({ tools }) {
1450
1517
  finished.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Collapsible, { children: [
1451
1518
  /* @__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
1519
  /* @__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})` })
1520
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: labels.completedSteps(finished.length, failedCount) })
1454
1521
  ] }),
1455
1522
  /* @__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
1523
  ] }),
@@ -1458,11 +1525,12 @@ function ToolActivity({ tools }) {
1458
1525
  ] });
1459
1526
  }
1460
1527
  function ReasoningBlock({ text }) {
1528
+ const labels = useLabels();
1461
1529
  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
1530
  /* @__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
1531
  /* @__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
1532
  /* @__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" })
1533
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: labels.reasoning })
1466
1534
  ] }),
1467
1535
  /* @__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
1536
  ] }) });
@@ -1477,6 +1545,7 @@ function ChatPanel({
1477
1545
  onSectionEditStart,
1478
1546
  onSectionEditEnd
1479
1547
  }) {
1548
+ const labels = useLabels();
1480
1549
  const [input, setInput] = (0, import_react5.useState)("");
1481
1550
  const taRef = (0, import_react5.useRef)(null);
1482
1551
  const times = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
@@ -1499,7 +1568,7 @@ function ChatPanel({
1499
1568
  onFinish: onAgentFinish,
1500
1569
  onError: (e) => {
1501
1570
  console.error("chat error:", e);
1502
- import_sonner2.toast.error("Agent chat error.");
1571
+ import_sonner2.toast.error(labels.chatError);
1503
1572
  }
1504
1573
  });
1505
1574
  const firedTools = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
@@ -1561,8 +1630,8 @@ function ChatPanel({
1561
1630
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MessageScrollerViewport, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(MessageScrollerContent, { className: "p-3", children: [
1562
1631
  messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Empty, { className: "h-full", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(EmptyHeader, { children: [
1563
1632
  /* @__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." })
1633
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyTitle, { children: labels.chatEmptyTitle }),
1634
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmptyDescription, { children: labels.chatEmptyDescription })
1566
1635
  ] }) }) : messages.map((message, mi) => {
1567
1636
  const isUser = message.role === "user";
1568
1637
  const isLast = mi === messages.length - 1;
@@ -1637,7 +1706,8 @@ function ChatPanel({
1637
1706
  onClick: () => void send(APPLY_COMMENTS_PROMPT),
1638
1707
  children: [
1639
1708
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Sparkles, {}),
1640
- " Apply changes from comments"
1709
+ " ",
1710
+ labels.applyComments
1641
1711
  ]
1642
1712
  }
1643
1713
  ),
@@ -1656,7 +1726,7 @@ function ChatPanel({
1656
1726
  ref: taRef,
1657
1727
  rows: 2,
1658
1728
  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)",
1729
+ placeholder: labels.chatPlaceholder,
1660
1730
  value: input,
1661
1731
  onChange: (e) => {
1662
1732
  setInput(e.target.value);
@@ -1681,7 +1751,8 @@ function ChatPanel({
1681
1751
  onClick: () => void stop(),
1682
1752
  children: [
1683
1753
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Square, {}),
1684
- " Stop"
1754
+ " ",
1755
+ labels.stop
1685
1756
  ]
1686
1757
  }
1687
1758
  ),
@@ -1694,7 +1765,8 @@ function ChatPanel({
1694
1765
  className: "bg-brand text-brand-fg hover:bg-brand/90",
1695
1766
  children: [
1696
1767
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.Send, {}),
1697
- " Send"
1768
+ " ",
1769
+ labels.send
1698
1770
  ]
1699
1771
  }
1700
1772
  )
@@ -1721,6 +1793,7 @@ function CanvasComments({
1721
1793
  onOpenCountChange
1722
1794
  }) {
1723
1795
  const commentStore = useCommentStore();
1796
+ const labels = useLabels();
1724
1797
  const editor = (0, import_react6.useEditorMaybe)();
1725
1798
  const containerRef = (0, import_react7.useRef)(null);
1726
1799
  const [comments, setComments] = (0, import_react7.useState)([]);
@@ -1909,7 +1982,7 @@ function CanvasComments({
1909
1982
  " ",
1910
1983
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "font-medium text-foreground", children: activeTarget.objectLabel })
1911
1984
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
1912
- "Comment on the whole section",
1985
+ labels.commentOnSection,
1913
1986
  " ",
1914
1987
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("code", { className: "font-mono", children: activeTarget?.sectionId })
1915
1988
  ] }) }),
@@ -1918,14 +1991,14 @@ function CanvasComments({
1918
1991
  {
1919
1992
  type: "button",
1920
1993
  onClick: closePopover,
1921
- "aria-label": "Close",
1994
+ "aria-label": labels.closeComments,
1922
1995
  className: "-mr-1 -mt-0.5 shrink-0 rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
1923
1996
  children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.X, { className: "size-4" })
1924
1997
  }
1925
1998
  )
1926
1999
  ] }),
1927
2000
  /* @__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." }),
2001
+ activeComments.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-xs text-muted-foreground", children: labels.noCommentsYet }),
1929
2002
  activeComments.map((c) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "rounded-md border bg-muted/40 p-2 text-sm", children: [
1930
2003
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "whitespace-pre-wrap", children: c.body }),
1931
2004
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
@@ -1935,7 +2008,8 @@ function CanvasComments({
1935
2008
  className: "mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground",
1936
2009
  children: [
1937
2010
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.Check, { className: "size-3" }),
1938
- " Resolve"
2011
+ " ",
2012
+ labels.resolveComment
1939
2013
  ]
1940
2014
  }
1941
2015
  )
@@ -1948,7 +2022,7 @@ function CanvasComments({
1948
2022
  autoFocus: true,
1949
2023
  value: body,
1950
2024
  onChange: (e) => setBody(e.target.value),
1951
- placeholder: "Add a comment\u2026 (\u2318/Ctrl+Enter to send)",
2025
+ placeholder: labels.addCommentPlaceholder,
1952
2026
  className: "min-h-14 resize-none text-sm",
1953
2027
  onKeyDown: (e) => {
1954
2028
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
@@ -1960,7 +2034,8 @@ function CanvasComments({
1960
2034
  ),
1961
2035
  /* @__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
2036
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.MessageSquarePlus, {}),
1963
- " Add"
2037
+ " ",
2038
+ labels.addComment
1964
2039
  ] }) })
1965
2040
  ] })
1966
2041
  ]
@@ -1973,11 +2048,14 @@ function CanvasComments({
1973
2048
  0 && (module.exports = {
1974
2049
  CanvasComments,
1975
2050
  ChatPanel,
2051
+ DEFAULT_LABELS,
1976
2052
  EditorHeader,
1977
2053
  EditorStoreProvider,
1978
2054
  Markdown,
1979
2055
  STARTER_MJML,
2056
+ mergeLabels,
1980
2057
  useCommentStore,
1981
- useDocumentStore
2058
+ useDocumentStore,
2059
+ useLabels
1982
2060
  });
1983
2061
  //# sourceMappingURL=index.cjs.map