@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.
@@ -18,14 +18,88 @@ import {
18
18
  } from "./chunk-V6RR4VRD.js";
19
19
 
20
20
  // src/stores.tsx
21
- import { createContext, useContext } from "react";
21
+ import { createContext, useContext, useMemo } from "react";
22
+
23
+ // src/labels.ts
24
+ var DEFAULT_LABELS = {
25
+ appName: "MJML Editor",
26
+ emailNameAria: "Email name",
27
+ renameFailed: "Failed to rename.",
28
+ saving: "Saving\u2026",
29
+ saved: "Saved",
30
+ saveFailed: "Save failed",
31
+ undo: "Undo",
32
+ redo: "Redo",
33
+ contentWidth: "Content width",
34
+ preview: "Preview",
35
+ closePreview: "Close preview",
36
+ previewFrameTitle: "Email preview",
37
+ sourceCode: "Source code",
38
+ exportHtml: "Export HTML",
39
+ exportMjml: "Export MJML",
40
+ copied: (kind) => `${kind} copied.`,
41
+ searchBlocks: "Search blocks\u2026",
42
+ expandAll: "Expand all",
43
+ selectAnElement: "Select an element\u2026",
44
+ attributes: "Attributes",
45
+ style: "Style",
46
+ rteFont: "Font",
47
+ rteSize: "Size",
48
+ rteTextColor: "Text color",
49
+ rteBackgroundColor: "Background color",
50
+ documentLoadFailed: "Failed to load the document.",
51
+ documentSaveFailed: "Failed to save changes.",
52
+ commentOnSection: "Comment on the whole section",
53
+ closeComments: "Close",
54
+ noCommentsYet: "No comments yet \u2014 add the first one.",
55
+ resolveComment: "Resolve",
56
+ addComment: "Add",
57
+ addCommentPlaceholder: "Add a comment\u2026 (\u2318/Ctrl+Enter to send)",
58
+ chatEmptyTitle: "Start a conversation with the agent",
59
+ chatEmptyDescription: "Describe the email (goal, tone, content) and paste your data \u2014 the agent will design the sections and images.",
60
+ agentWorking: "Agent is working\u2026",
61
+ reasoning: "Reasoning",
62
+ completedSteps: (count, failed) => failed > 0 ? `Completed steps (${count}, ${failed} failed)` : `Completed steps (${count})`,
63
+ applyComments: "Apply changes from comments",
64
+ chatPlaceholder: "Describe what you want to change\u2026 (Enter = send, Shift+Enter = new line)",
65
+ stop: "Stop",
66
+ send: "Send",
67
+ chatError: "Agent chat error.",
68
+ toolLabels: {
69
+ get_document: "Reading document",
70
+ get_section: "Reading section",
71
+ set_document: "Saving whole email",
72
+ set_section: "Replacing section",
73
+ insert_section: "Adding section",
74
+ remove_section: "Removing section",
75
+ generate_image: "Generating image",
76
+ list_open_comments: "Reading comments",
77
+ resolve_comment: "Resolving comment"
78
+ }
79
+ };
80
+ function mergeLabels(overrides) {
81
+ if (!overrides) return DEFAULT_LABELS;
82
+ return {
83
+ ...DEFAULT_LABELS,
84
+ ...overrides,
85
+ toolLabels: { ...DEFAULT_LABELS.toolLabels, ...overrides.toolLabels }
86
+ };
87
+ }
88
+
89
+ // src/stores.tsx
22
90
  import { jsx } from "react/jsx-runtime";
23
91
  var StoreContext = createContext(null);
92
+ var LabelContext = createContext(null);
24
93
  function EditorStoreProvider({
25
94
  stores,
95
+ labels,
26
96
  children
27
97
  }) {
28
- return /* @__PURE__ */ jsx(StoreContext.Provider, { value: stores, children });
98
+ const merged = useMemo(() => mergeLabels(labels), [labels]);
99
+ return /* @__PURE__ */ jsx(StoreContext.Provider, { value: stores, children: /* @__PURE__ */ jsx(LabelContext.Provider, { value: merged, children }) });
100
+ }
101
+ function useLabels() {
102
+ return useContext(LabelContext) ?? mergeLabels();
29
103
  }
30
104
  function useStores() {
31
105
  const stores = useContext(StoreContext);
@@ -349,29 +423,24 @@ function DialogTitle({ className, ...props }) {
349
423
 
350
424
  // src/components/editor/EditorHeader.tsx
351
425
  import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
352
- var SAVE_LABEL = {
353
- idle: "",
354
- saving: "Saving\u2026",
355
- saved: "Saved",
356
- error: "Save failed"
357
- };
358
426
  var WIDTHS = ["600px", "640px", "680px", "720px"];
359
427
  var DEVICE_ICON = {
360
428
  Desktop: /* @__PURE__ */ jsx7(Monitor, { className: "size-3.5" }),
361
429
  Mobile: /* @__PURE__ */ jsx7(Smartphone, { className: "size-3.5" })
362
430
  };
363
431
  function SaveBadge({ status }) {
432
+ const labels = useLabels();
364
433
  if (status === "idle") return null;
365
434
  if (status === "saving")
366
435
  return /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1 text-xs text-panel-muted-fg", children: [
367
436
  /* @__PURE__ */ jsx7(Spinner, { className: "size-3" }),
368
437
  " ",
369
- SAVE_LABEL.saving
438
+ labels.saving
370
439
  ] });
371
- if (status === "error") return /* @__PURE__ */ jsx7(Badge, { variant: "destructive", children: SAVE_LABEL.error });
440
+ if (status === "error") return /* @__PURE__ */ jsx7(Badge, { variant: "destructive", children: labels.saveFailed });
372
441
  return /* @__PURE__ */ jsxs2("span", { className: "text-xs text-emerald-400", children: [
373
442
  "\u2713 ",
374
- SAVE_LABEL.saved
443
+ labels.saved
375
444
  ] });
376
445
  }
377
446
  function slugify(name) {
@@ -391,9 +460,11 @@ function EditorHeader({
391
460
  docId,
392
461
  api,
393
462
  openCount,
394
- homeLink
463
+ homeLink,
464
+ logo
395
465
  }) {
396
466
  const documents = useDocumentStore();
467
+ const labels = useLabels();
397
468
  const [name, setName] = useState("");
398
469
  const [state, setState] = useState({
399
470
  device: "Desktop",
@@ -419,15 +490,15 @@ function EditorHeader({
419
490
  try {
420
491
  await documents.save(docId, { name: n });
421
492
  } catch {
422
- toast.error("Failed to rename.");
493
+ toast.error(labels.renameFailed);
423
494
  }
424
495
  };
425
496
  const devices = api?.getDevices() ?? [];
426
497
  const base = slugify(name);
427
498
  const openCode = () => setCode({ mjml: api?.getMjml() ?? "", html: api?.getCompiledHtml() ?? "" });
428
499
  return /* @__PURE__ */ jsxs2("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b border-panel-border bg-panel px-3 text-panel-fg", children: [
429
- /* @__PURE__ */ jsx7("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__ */ jsx7(Mail, { className: "size-4" }) }),
430
- /* @__PURE__ */ jsx7("span", { className: "hidden text-sm font-semibold sm:inline", children: "MJML Editor" }),
500
+ logo ?? /* @__PURE__ */ jsx7("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__ */ jsx7(Mail, { className: "size-4" }) }),
501
+ /* @__PURE__ */ jsx7("span", { className: "hidden text-sm font-semibold sm:inline", children: labels.appName }),
431
502
  /* @__PURE__ */ jsx7(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border" }),
432
503
  /* @__PURE__ */ jsx7(
433
504
  Input,
@@ -437,7 +508,7 @@ function EditorHeader({
437
508
  onBlur: () => void commitName(),
438
509
  onKeyDown: (e) => e.key === "Enter" && e.currentTarget.blur(),
439
510
  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",
440
- "aria-label": "Email name"
511
+ "aria-label": labels.emailNameAria
441
512
  }
442
513
  ),
443
514
  /* @__PURE__ */ jsx7(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border" }),
@@ -475,7 +546,7 @@ function EditorHeader({
475
546
  children: /* @__PURE__ */ jsx7(Undo2, {})
476
547
  }
477
548
  ) }),
478
- /* @__PURE__ */ jsx7(TooltipContent, { children: "Undo" })
549
+ /* @__PURE__ */ jsx7(TooltipContent, { children: labels.undo })
479
550
  ] }),
480
551
  /* @__PURE__ */ jsxs2(Tooltip, { children: [
481
552
  /* @__PURE__ */ jsx7(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx7(
@@ -489,7 +560,7 @@ function EditorHeader({
489
560
  children: /* @__PURE__ */ jsx7(Redo2, {})
490
561
  }
491
562
  ) }),
492
- /* @__PURE__ */ jsx7(TooltipContent, { children: "Redo" })
563
+ /* @__PURE__ */ jsx7(TooltipContent, { children: labels.redo })
493
564
  ] }),
494
565
  /* @__PURE__ */ jsx7(Separator, { orientation: "vertical", className: "mx-1 !h-5 bg-panel-border max-xl:hidden" }),
495
566
  /* @__PURE__ */ jsxs2(Popover, { children: [
@@ -500,7 +571,7 @@ function EditorHeader({
500
571
  size: "sm",
501
572
  className: cn(darkGhost, "gap-1.5 rounded-md border border-panel-border max-xl:hidden"),
502
573
  children: [
503
- /* @__PURE__ */ jsx7("span", { className: "text-panel-muted-fg", children: "Content width" }),
574
+ /* @__PURE__ */ jsx7("span", { className: "text-panel-muted-fg", children: labels.contentWidth }),
504
575
  state.contentWidth,
505
576
  /* @__PURE__ */ jsx7(ChevronDown, { className: "size-3.5" })
506
577
  ]
@@ -562,7 +633,8 @@ function EditorHeader({
562
633
  onClick: () => setPreview(api?.getCompiledHtml() ?? ""),
563
634
  children: [
564
635
  /* @__PURE__ */ jsx7(Eye, {}),
565
- " Preview"
636
+ " ",
637
+ labels.preview
566
638
  ]
567
639
  }
568
640
  ) }),
@@ -574,7 +646,8 @@ function EditorHeader({
574
646
  children: [
575
647
  /* @__PURE__ */ jsxs2("div", { className: "flex h-12 shrink-0 items-center justify-between border-b bg-white px-4", children: [
576
648
  /* @__PURE__ */ jsxs2(DialogTitle, { className: "text-sm", children: [
577
- "Preview \u2014 ",
649
+ labels.preview,
650
+ " \u2014 ",
578
651
  name
579
652
  ] }),
580
653
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
@@ -601,13 +674,13 @@ function EditorHeader({
601
674
  ]
602
675
  }
603
676
  ),
604
- /* @__PURE__ */ jsx7(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx7(Button, { variant: "ghost", size: "icon", "aria-label": "Close preview", children: /* @__PURE__ */ jsx7(X, {}) }) })
677
+ /* @__PURE__ */ jsx7(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx7(Button, { variant: "ghost", size: "icon", "aria-label": labels.closePreview, children: /* @__PURE__ */ jsx7(X, {}) }) })
605
678
  ] })
606
679
  ] }),
607
680
  /* @__PURE__ */ jsx7("div", { className: "min-h-0 flex-1 overflow-auto p-6", children: /* @__PURE__ */ jsx7(
608
681
  "iframe",
609
682
  {
610
- title: "Email preview",
683
+ title: labels.previewFrameTitle,
611
684
  srcDoc: preview,
612
685
  className: cn(
613
686
  "mx-auto block h-full min-h-[80vh] rounded-md border bg-white shadow-sm",
@@ -634,7 +707,7 @@ function EditorHeader({
634
707
  }
635
708
  ) }),
636
709
  /* @__PURE__ */ jsxs2(DialogContent, { className: "flex !max-w-4xl flex-col", children: [
637
- /* @__PURE__ */ jsx7(DialogHeader, { children: /* @__PURE__ */ jsx7(DialogTitle, { children: "Source code" }) }),
710
+ /* @__PURE__ */ jsx7(DialogHeader, { children: /* @__PURE__ */ jsx7(DialogTitle, { children: labels.sourceCode }) }),
638
711
  /* @__PURE__ */ jsxs2(Tabs, { defaultValue: "mjml", className: "min-h-0 flex-1", children: [
639
712
  /* @__PURE__ */ jsxs2(TabsList, { children: [
640
713
  /* @__PURE__ */ jsx7(TabsTrigger, { value: "mjml", children: "MJML" }),
@@ -667,7 +740,7 @@ function EditorHeader({
667
740
  size: "sm",
668
741
  onClick: () => {
669
742
  void navigator.clipboard?.writeText(code[kind]);
670
- toast.success(`${kind.toUpperCase()} copied.`);
743
+ toast.success(labels.copied(kind.toUpperCase()));
671
744
  },
672
745
  children: [
673
746
  /* @__PURE__ */ jsx7(Copy, {}),
@@ -693,7 +766,7 @@ function EditorHeader({
693
766
  onClick: () => download(`${base}.html`, api?.getCompiledHtml() ?? "", "text/html"),
694
767
  className: "flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted",
695
768
  children: [
696
- /* @__PURE__ */ jsx7("span", { className: "font-medium", children: "Export HTML" }),
769
+ /* @__PURE__ */ jsx7("span", { className: "font-medium", children: labels.exportHtml }),
697
770
  /* @__PURE__ */ jsxs2("span", { className: "text-xs text-muted-foreground", children: [
698
771
  base,
699
772
  ".html"
@@ -707,7 +780,7 @@ function EditorHeader({
707
780
  onClick: () => download(`${base}.mjml`, api?.getMjml() ?? "", "text/plain"),
708
781
  className: "flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted",
709
782
  children: [
710
- /* @__PURE__ */ jsx7("span", { className: "font-medium", children: "Export MJML" }),
783
+ /* @__PURE__ */ jsx7("span", { className: "font-medium", children: labels.exportMjml }),
711
784
  /* @__PURE__ */ jsxs2("span", { className: "text-xs text-muted-foreground", children: [
712
785
  base,
713
786
  ".mjml"
@@ -1080,17 +1153,6 @@ function MessageScrollerButton({
1080
1153
 
1081
1154
  // src/components/chat/ChatPanel.tsx
1082
1155
  import { jsx as jsx14, jsxs as jsxs4 } from "react/jsx-runtime";
1083
- var TOOL_LABELS = {
1084
- get_document: "Reading document",
1085
- get_section: "Reading section",
1086
- set_document: "Saving whole email",
1087
- set_section: "Replacing section",
1088
- insert_section: "Adding section",
1089
- remove_section: "Removing section",
1090
- generate_image: "Generating image",
1091
- list_open_comments: "Reading comments",
1092
- resolve_comment: "Resolving comment"
1093
- };
1094
1156
  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.";
1095
1157
  var MUTATING_TOOLS = /* @__PURE__ */ new Set([
1096
1158
  "set_document",
@@ -1138,24 +1200,27 @@ function toBlocks(parts) {
1138
1200
  return blocks;
1139
1201
  }
1140
1202
  function ToolMarker({ tool }) {
1203
+ const labels = useLabels();
1141
1204
  const name = tool.type.slice(5);
1142
1205
  const done = tool.state === "output-available";
1143
1206
  const failed = tool.state === "output-error";
1144
1207
  return /* @__PURE__ */ jsxs4(Marker, { className: cn(failed ? "text-destructive" : "text-panel-fg"), children: [
1145
1208
  /* @__PURE__ */ jsx14(MarkerIcon, { children: failed ? /* @__PURE__ */ jsx14(TriangleAlert, {}) : done ? /* @__PURE__ */ jsx14(Check, { className: "text-emerald-400" }) : /* @__PURE__ */ jsx14(Loader2, { className: "animate-spin" }) }),
1146
1209
  /* @__PURE__ */ jsxs4(MarkerContent, { children: [
1147
- TOOL_LABELS[name] ?? name,
1210
+ labels.toolLabels[name] ?? name,
1148
1211
  failed && tool.errorText ? `: ${tool.errorText}` : ""
1149
1212
  ] })
1150
1213
  ] });
1151
1214
  }
1152
1215
  function BusyMarker() {
1216
+ const labels = useLabels();
1153
1217
  return /* @__PURE__ */ jsxs4(Marker, { className: "text-panel-fg", children: [
1154
1218
  /* @__PURE__ */ jsx14(MarkerIcon, { children: /* @__PURE__ */ jsx14(Loader2, { className: "animate-spin" }) }),
1155
- /* @__PURE__ */ jsx14(MarkerContent, { children: "Agent is working\u2026" })
1219
+ /* @__PURE__ */ jsx14(MarkerContent, { children: labels.agentWorking })
1156
1220
  ] });
1157
1221
  }
1158
1222
  function ToolActivity({ tools }) {
1223
+ const labels = useLabels();
1159
1224
  const running = tools.filter((t) => t.state !== "output-available" && t.state !== "output-error");
1160
1225
  const finished = tools.filter(
1161
1226
  (t) => t.state === "output-available" || t.state === "output-error"
@@ -1165,7 +1230,7 @@ function ToolActivity({ tools }) {
1165
1230
  finished.length > 0 && /* @__PURE__ */ jsxs4(Collapsible, { children: [
1166
1231
  /* @__PURE__ */ jsxs4(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: [
1167
1232
  /* @__PURE__ */ jsx14(ChevronRight, { className: "size-3.5 shrink-0 transition-transform group-data-[state=open]/col:rotate-90" }),
1168
- /* @__PURE__ */ jsx14("span", { children: failedCount > 0 ? `Completed steps (${finished.length}, ${failedCount} failed)` : `Completed steps (${finished.length})` })
1233
+ /* @__PURE__ */ jsx14("span", { children: labels.completedSteps(finished.length, failedCount) })
1169
1234
  ] }),
1170
1235
  /* @__PURE__ */ jsx14(CollapsibleContent, { className: "mt-1 space-y-0.5 pl-1", children: finished.map((t, i) => /* @__PURE__ */ jsx14(ToolMarker, { tool: t }, `f${i}`)) })
1171
1236
  ] }),
@@ -1173,11 +1238,12 @@ function ToolActivity({ tools }) {
1173
1238
  ] });
1174
1239
  }
1175
1240
  function ReasoningBlock({ text }) {
1241
+ const labels = useLabels();
1176
1242
  return /* @__PURE__ */ jsx14("div", { className: "rounded-lg border border-panel-border bg-panel-elevated/60 p-2", children: /* @__PURE__ */ jsxs4(Collapsible, { children: [
1177
1243
  /* @__PURE__ */ jsxs4(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: [
1178
1244
  /* @__PURE__ */ jsx14(ChevronRight, { className: "size-3.5 shrink-0 transition-transform group-data-[state=open]/col:rotate-90" }),
1179
1245
  /* @__PURE__ */ jsx14(Brain, { className: "size-3.5 shrink-0" }),
1180
- /* @__PURE__ */ jsx14("span", { children: "Reasoning" })
1246
+ /* @__PURE__ */ jsx14("span", { children: labels.reasoning })
1181
1247
  ] }),
1182
1248
  /* @__PURE__ */ jsx14(CollapsibleContent, { className: "mt-1.5 pl-1 text-xs whitespace-pre-wrap text-panel-muted-fg", children: text })
1183
1249
  ] }) });
@@ -1192,6 +1258,7 @@ function ChatPanel({
1192
1258
  onSectionEditStart,
1193
1259
  onSectionEditEnd
1194
1260
  }) {
1261
+ const labels = useLabels();
1195
1262
  const [input, setInput] = useState2("");
1196
1263
  const taRef = useRef(null);
1197
1264
  const times = useRef(/* @__PURE__ */ new Map());
@@ -1214,7 +1281,7 @@ function ChatPanel({
1214
1281
  onFinish: onAgentFinish,
1215
1282
  onError: (e) => {
1216
1283
  console.error("chat error:", e);
1217
- toast2.error("Agent chat error.");
1284
+ toast2.error(labels.chatError);
1218
1285
  }
1219
1286
  });
1220
1287
  const firedTools = useRef(/* @__PURE__ */ new Set());
@@ -1276,8 +1343,8 @@ function ChatPanel({
1276
1343
  /* @__PURE__ */ jsx14(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs4(MessageScrollerContent, { className: "p-3", children: [
1277
1344
  messages.length === 0 ? /* @__PURE__ */ jsx14(Empty, { className: "h-full", children: /* @__PURE__ */ jsxs4(EmptyHeader, { children: [
1278
1345
  /* @__PURE__ */ jsx14(EmptyMedia, { variant: "icon", children: /* @__PURE__ */ jsx14(MessageSquare2, {}) }),
1279
- /* @__PURE__ */ jsx14(EmptyTitle, { children: "Start a conversation with the agent" }),
1280
- /* @__PURE__ */ jsx14(EmptyDescription, { children: "Describe the email (goal, tone, content) and paste your data \u2014 the agent will design the sections and images." })
1346
+ /* @__PURE__ */ jsx14(EmptyTitle, { children: labels.chatEmptyTitle }),
1347
+ /* @__PURE__ */ jsx14(EmptyDescription, { children: labels.chatEmptyDescription })
1281
1348
  ] }) }) : messages.map((message, mi) => {
1282
1349
  const isUser = message.role === "user";
1283
1350
  const isLast = mi === messages.length - 1;
@@ -1352,7 +1419,8 @@ function ChatPanel({
1352
1419
  onClick: () => void send(APPLY_COMMENTS_PROMPT),
1353
1420
  children: [
1354
1421
  /* @__PURE__ */ jsx14(Sparkles, {}),
1355
- " Apply changes from comments"
1422
+ " ",
1423
+ labels.applyComments
1356
1424
  ]
1357
1425
  }
1358
1426
  ),
@@ -1371,7 +1439,7 @@ function ChatPanel({
1371
1439
  ref: taRef,
1372
1440
  rows: 2,
1373
1441
  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",
1374
- placeholder: "Describe what you want to change\u2026 (Enter = send, Shift+Enter = new line)",
1442
+ placeholder: labels.chatPlaceholder,
1375
1443
  value: input,
1376
1444
  onChange: (e) => {
1377
1445
  setInput(e.target.value);
@@ -1396,7 +1464,8 @@ function ChatPanel({
1396
1464
  onClick: () => void stop(),
1397
1465
  children: [
1398
1466
  /* @__PURE__ */ jsx14(Square, {}),
1399
- " Stop"
1467
+ " ",
1468
+ labels.stop
1400
1469
  ]
1401
1470
  }
1402
1471
  ),
@@ -1409,7 +1478,8 @@ function ChatPanel({
1409
1478
  className: "bg-brand text-brand-fg hover:bg-brand/90",
1410
1479
  children: [
1411
1480
  /* @__PURE__ */ jsx14(Send, {}),
1412
- " Send"
1481
+ " ",
1482
+ labels.send
1413
1483
  ]
1414
1484
  }
1415
1485
  )
@@ -1423,7 +1493,7 @@ function ChatPanel({
1423
1493
 
1424
1494
  // src/components/comments/CanvasComments.tsx
1425
1495
  import { useEditorMaybe } from "@grapesjs/react";
1426
- import { useCallback, useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
1496
+ import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
1427
1497
  import { Check as Check2, MessageSquarePlus, X as X2 } from "lucide-react";
1428
1498
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs5 } from "react/jsx-runtime";
1429
1499
  var keyOf = (c) => c.objectId ? `obj-${c.objectId}` : `sec-${c.sectionId}`;
@@ -1436,6 +1506,7 @@ function CanvasComments({
1436
1506
  onOpenCountChange
1437
1507
  }) {
1438
1508
  const commentStore = useCommentStore();
1509
+ const labels = useLabels();
1439
1510
  const editor = useEditorMaybe();
1440
1511
  const containerRef = useRef2(null);
1441
1512
  const [comments, setComments] = useState3([]);
@@ -1449,11 +1520,11 @@ function CanvasComments({
1449
1520
  useEffect3(() => {
1450
1521
  reload();
1451
1522
  }, [reload, refreshSignal]);
1452
- const open = useMemo(() => comments.filter((c) => c.status === "open"), [comments]);
1523
+ const open = useMemo2(() => comments.filter((c) => c.status === "open"), [comments]);
1453
1524
  useEffect3(() => {
1454
1525
  onOpenCountChange(open.length);
1455
1526
  }, [open.length, onOpenCountChange]);
1456
- const pins = useMemo(() => {
1527
+ const pins = useMemo2(() => {
1457
1528
  const map = /* @__PURE__ */ new Map();
1458
1529
  for (const c of open) {
1459
1530
  const k = keyOf(c);
@@ -1624,7 +1695,7 @@ function CanvasComments({
1624
1695
  " ",
1625
1696
  /* @__PURE__ */ jsx15("span", { className: "font-medium text-foreground", children: activeTarget.objectLabel })
1626
1697
  ] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
1627
- "Comment on the whole section",
1698
+ labels.commentOnSection,
1628
1699
  " ",
1629
1700
  /* @__PURE__ */ jsx15("code", { className: "font-mono", children: activeTarget?.sectionId })
1630
1701
  ] }) }),
@@ -1633,14 +1704,14 @@ function CanvasComments({
1633
1704
  {
1634
1705
  type: "button",
1635
1706
  onClick: closePopover,
1636
- "aria-label": "Close",
1707
+ "aria-label": labels.closeComments,
1637
1708
  className: "-mr-1 -mt-0.5 shrink-0 rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground",
1638
1709
  children: /* @__PURE__ */ jsx15(X2, { className: "size-4" })
1639
1710
  }
1640
1711
  )
1641
1712
  ] }),
1642
1713
  /* @__PURE__ */ jsxs5("div", { className: "max-h-64 space-y-2 overflow-y-auto p-3", children: [
1643
- activeComments.length === 0 && /* @__PURE__ */ jsx15("p", { className: "text-xs text-muted-foreground", children: "No comments yet \u2014 add the first one." }),
1714
+ activeComments.length === 0 && /* @__PURE__ */ jsx15("p", { className: "text-xs text-muted-foreground", children: labels.noCommentsYet }),
1644
1715
  activeComments.map((c) => /* @__PURE__ */ jsxs5("div", { className: "rounded-md border bg-muted/40 p-2 text-sm", children: [
1645
1716
  /* @__PURE__ */ jsx15("p", { className: "whitespace-pre-wrap", children: c.body }),
1646
1717
  /* @__PURE__ */ jsxs5(
@@ -1650,7 +1721,8 @@ function CanvasComments({
1650
1721
  className: "mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground",
1651
1722
  children: [
1652
1723
  /* @__PURE__ */ jsx15(Check2, { className: "size-3" }),
1653
- " Resolve"
1724
+ " ",
1725
+ labels.resolveComment
1654
1726
  ]
1655
1727
  }
1656
1728
  )
@@ -1663,7 +1735,7 @@ function CanvasComments({
1663
1735
  autoFocus: true,
1664
1736
  value: body,
1665
1737
  onChange: (e) => setBody(e.target.value),
1666
- placeholder: "Add a comment\u2026 (\u2318/Ctrl+Enter to send)",
1738
+ placeholder: labels.addCommentPlaceholder,
1667
1739
  className: "min-h-14 resize-none text-sm",
1668
1740
  onKeyDown: (e) => {
1669
1741
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
@@ -1675,7 +1747,8 @@ function CanvasComments({
1675
1747
  ),
1676
1748
  /* @__PURE__ */ jsx15("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ jsxs5(Button, { size: "sm", disabled: !body.trim(), onClick: () => void submit(), children: [
1677
1749
  /* @__PURE__ */ jsx15(MessageSquarePlus, {}),
1678
- " Add"
1750
+ " ",
1751
+ labels.addComment
1679
1752
  ] }) })
1680
1753
  ] })
1681
1754
  ]
@@ -1686,7 +1759,10 @@ function CanvasComments({
1686
1759
  }
1687
1760
 
1688
1761
  export {
1762
+ DEFAULT_LABELS,
1763
+ mergeLabels,
1689
1764
  EditorStoreProvider,
1765
+ useLabels,
1690
1766
  useDocumentStore,
1691
1767
  useCommentStore,
1692
1768
  EditorHeader,
@@ -1695,4 +1771,4 @@ export {
1695
1771
  CanvasComments,
1696
1772
  STARTER_MJML
1697
1773
  };
1698
- //# sourceMappingURL=chunk-2SXJHEF5.js.map
1774
+ //# sourceMappingURL=chunk-LWYM4ANK.js.map