@crystallize/design-system 1.9.0 → 1.11.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.
Files changed (30) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/index.css +15 -17
  3. package/dist/index.d.ts +10 -3
  4. package/dist/index.js +528 -470
  5. package/dist/index.mjs +477 -423
  6. package/package.json +1 -1
  7. package/src/rich-text-editor/i18n/i18n.test.ts +14 -0
  8. package/src/rich-text-editor/i18n/index.tsx +64 -0
  9. package/src/rich-text-editor/i18n/translations/en.ts +66 -0
  10. package/src/rich-text-editor/i18n/types.ts +62 -0
  11. package/src/rich-text-editor/model/crystallize-to-lexical.ts +29 -1
  12. package/src/rich-text-editor/model/lexical-to-crystallize.ts +54 -29
  13. package/src/rich-text-editor/plugins/ActionsPlugin/index.tsx +5 -22
  14. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +4 -1
  15. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +11 -1
  16. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx +2 -1
  17. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx +23 -5
  18. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +21 -10
  19. package/src/rich-text-editor/plugins/TabFocusPlugin/index.tsx +4 -12
  20. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx +23 -14
  21. package/src/rich-text-editor/plugins/ToolbarPlugin/index.tsx +33 -33
  22. package/src/rich-text-editor/plugins/ToolbarPlugin/insert-table.tsx +6 -4
  23. package/src/rich-text-editor/rich-text-editor.css +6 -0
  24. package/src/rich-text-editor/rich-text-editor.stories.tsx +38 -0
  25. package/src/rich-text-editor/rich-text-editor.tsx +15 -9
  26. package/src/rich-text-editor/tests/rich-text-editor-model-conversions.test.tsx +23 -1
  27. package/src/rich-text-editor/types/crystallize-rich-text-types/index.ts +2 -4
  28. package/src/rich-text-editor/ui/LinkPreview.tsx +3 -1
  29. package/src/rich-text-editor/ui/ContentEditable.css +0 -13
  30. package/src/rich-text-editor/ui/ContentEditable.tsx +0 -15
package/dist/index.mjs CHANGED
@@ -3541,7 +3541,7 @@ function Tag({ children, className, variant, ...delegated }) {
3541
3541
  }
3542
3542
 
3543
3543
  // src/rich-text-editor/rich-text-editor.tsx
3544
- import { useEffect as useEffect11, useRef as useRef5, useState as useState10 } from "react";
3544
+ import { useEffect as useEffect12, useRef as useRef5, useState as useState11 } from "react";
3545
3545
  import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
3546
3546
  import { ClearEditorPlugin } from "@lexical/react/LexicalClearEditorPlugin";
3547
3547
  import { LexicalComposer } from "@lexical/react/LexicalComposer";
@@ -3554,6 +3554,7 @@ import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
3554
3554
  import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
3555
3555
  import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
3556
3556
  import { useLexicalComposerContext as useLexicalComposerContext12 } from "@lexical/react/LexicalComposerContext";
3557
+ import { ContentEditable } from "@lexical/react/LexicalContentEditable";
3557
3558
 
3558
3559
  // src/rich-text-editor/context/SharedHistoryContext.tsx
3559
3560
  import { createContext, useContext, useMemo } from "react";
@@ -3571,12 +3572,61 @@ var useSharedHistoryContext = () => {
3571
3572
  return useContext(Context);
3572
3573
  };
3573
3574
 
3575
+ // src/rich-text-editor/i18n/index.tsx
3576
+ import { createContext as createContext2, useContext as useContext2, useEffect, useState } from "react";
3577
+ import { jsx as jsx77 } from "react/jsx-runtime";
3578
+ var I18nContext = createContext2(null);
3579
+ function I18nProvider({
3580
+ language,
3581
+ labelTranslations,
3582
+ children
3583
+ }) {
3584
+ const [translations, setTranslations] = useState(labelTranslations || null);
3585
+ useEffect(() => {
3586
+ let unmounted = false;
3587
+ (async function load() {
3588
+ if (!labelTranslations) {
3589
+ const resource = await import(`./translations/${language}.ts`);
3590
+ if (!unmounted) {
3591
+ setTranslations(resource.default);
3592
+ }
3593
+ }
3594
+ })();
3595
+ return () => {
3596
+ unmounted = true;
3597
+ };
3598
+ }, [language, labelTranslations]);
3599
+ return /* @__PURE__ */ jsx77(I18nContext.Provider, {
3600
+ value: translations,
3601
+ children
3602
+ });
3603
+ }
3604
+ function replaceI18nVariablesInString(str, replaceWith) {
3605
+ return str.replace(/({{[^}]+}})/g, replaceWith);
3606
+ }
3607
+ function useTr() {
3608
+ const context = useContext2(I18nContext);
3609
+ return (key, units) => {
3610
+ const thereAreUnits = typeof units === "number";
3611
+ const keyToUse = thereAreUnits && units > 1 ? `${key}_plural` : key;
3612
+ if (context && keyToUse in context) {
3613
+ const tr = context[keyToUse];
3614
+ if (thereAreUnits) {
3615
+ return replaceI18nVariablesInString(tr, units.toString());
3616
+ }
3617
+ return tr;
3618
+ }
3619
+ return "";
3620
+ };
3621
+ }
3622
+
3574
3623
  // src/rich-text-editor/model/crystallize-to-lexical.ts
3575
3624
  import {
3576
3625
  $createLineBreakNode,
3577
3626
  $createParagraphNode,
3578
3627
  $createTextNode,
3579
- $getRoot
3628
+ $getRoot,
3629
+ $isTextNode
3580
3630
  } from "lexical";
3581
3631
  import { $createCodeHighlightNode, $createCodeNode } from "@lexical/code";
3582
3632
  import { $createLinkNode } from "@lexical/link";
@@ -3706,7 +3756,25 @@ function composeInitialState({ richText }) {
3706
3756
  }
3707
3757
  if (lexicalNode) {
3708
3758
  if (Array.isArray(children)) {
3709
- children.forEach((n) => handleNode({ crystallizeContentNode: n, lexicalParent: lexicalNode }));
3759
+ if ($isTextNode(lexicalNode)) {
3760
+ const handleInlineTextChild = (child) => {
3761
+ if ($isTextNode(lexicalNode)) {
3762
+ const textFormat = getLexicalTextFormat(child);
3763
+ if (textFormat && !lexicalNode.hasFormat(textFormat)) {
3764
+ lexicalNode.toggleFormat(textFormat);
3765
+ }
3766
+ if (child.textContent) {
3767
+ lexicalNode.setTextContent(child.textContent);
3768
+ }
3769
+ }
3770
+ if ("children" in child) {
3771
+ child.children?.forEach(handleInlineTextChild);
3772
+ }
3773
+ };
3774
+ children.forEach(handleInlineTextChild);
3775
+ } else {
3776
+ children.forEach((n) => handleNode({ crystallizeContentNode: n, lexicalParent: lexicalNode }));
3777
+ }
3710
3778
  }
3711
3779
  lexicalParent.append(lexicalNode);
3712
3780
  }
@@ -3744,7 +3812,7 @@ import {
3744
3812
  $isElementNode,
3745
3813
  $isLineBreakNode,
3746
3814
  $isParagraphNode,
3747
- $isTextNode
3815
+ $isTextNode as $isTextNode2
3748
3816
  } from "lexical";
3749
3817
  import { $isCodeNode } from "@lexical/code";
3750
3818
  import { $isLinkNode } from "@lexical/link";
@@ -3857,7 +3925,7 @@ function lexicalToCrystallizeRichText({
3857
3925
  if (crystallizeNode) {
3858
3926
  if (children.length === 1 && parent) {
3859
3927
  const [first] = children;
3860
- if ($isTextNode(first)) {
3928
+ if ($isTextNode2(first)) {
3861
3929
  const childTextNode = getTextChild(first);
3862
3930
  if (!childTextNode.type) {
3863
3931
  crystallizeNode.textContent = childTextNode.textContent;
@@ -3879,10 +3947,8 @@ function lexicalToCrystallizeRichText({
3879
3947
  kind: "block",
3880
3948
  type: "horizontal-line"
3881
3949
  });
3882
- } else {
3883
- if ($isTextNode(childNode)) {
3884
- parentChildrenToUse.push(getTextChild(childNode));
3885
- }
3950
+ } else if ($isTextNode2(childNode)) {
3951
+ parentChildrenToUse.push(getTextChild(childNode));
3886
3952
  }
3887
3953
  });
3888
3954
  }
@@ -3892,32 +3958,47 @@ function lexicalToCrystallizeRichText({
3892
3958
  });
3893
3959
  return crystallizeRichText;
3894
3960
  }
3961
+ var lexicalFormatToCrystallizeType = {
3962
+ bold: "strong",
3963
+ italic: "emphasized",
3964
+ underline: "underlined",
3965
+ strikethrough: "deleted",
3966
+ subscript: "subscripted",
3967
+ superscript: "superscripted",
3968
+ highlight: "emphasized",
3969
+ code: "code"
3970
+ };
3895
3971
  function getTextChild(n) {
3896
- const textContent = n.getTextContent();
3897
- if (n.hasFormat("code")) {
3898
- return {
3899
- type: "code",
3900
- kind: "inline",
3901
- textContent
3902
- };
3903
- }
3904
- const textChild = {
3905
- kind: "inline",
3906
- textContent
3972
+ let currentChild = {
3973
+ kind: "inline"
3907
3974
  };
3908
- if (n.hasFormat("bold")) {
3909
- textChild.type = "strong";
3910
- } else if (n.hasFormat("italic")) {
3911
- textChild.type = "emphasized";
3912
- } else if (n.hasFormat("underline")) {
3913
- textChild.type = "underlined";
3914
- } else if (n.hasFormat("strikethrough")) {
3915
- textChild.type = "deleted";
3916
- } else if (n.hasFormat("subscript")) {
3917
- textChild.type = "subscripted";
3918
- } else if (n.hasFormat("superscript")) {
3919
- textChild.type = "superscripted";
3975
+ let textChild = null;
3976
+ function checkFormat(format) {
3977
+ const type = lexicalFormatToCrystallizeType[format];
3978
+ if (n.hasFormat(format) && type) {
3979
+ if (!textChild) {
3980
+ currentChild = textChild = {
3981
+ kind: "inline",
3982
+ type
3983
+ };
3984
+ } else {
3985
+ currentChild.children = [
3986
+ {
3987
+ kind: "inline",
3988
+ type
3989
+ }
3990
+ ];
3991
+ currentChild = currentChild.children[0];
3992
+ }
3993
+ }
3920
3994
  }
3995
+ Object.keys(lexicalFormatToCrystallizeType).forEach(checkFormat);
3996
+ if (!textChild) {
3997
+ currentChild = textChild = {
3998
+ kind: "inline"
3999
+ };
4000
+ }
4001
+ currentChild.textContent = n.getTextContent();
3921
4002
  return textChild;
3922
4003
  }
3923
4004
 
@@ -3952,7 +4033,7 @@ var BaseNodes = [
3952
4033
  // src/rich-text-editor/plugins/AutoLinkPlugin/index.tsx
3953
4034
  import { AutoLinkPlugin } from "@lexical/react/LexicalAutoLinkPlugin";
3954
4035
  import "react";
3955
- import { jsx as jsx77 } from "react/jsx-runtime";
4036
+ import { jsx as jsx78 } from "react/jsx-runtime";
3956
4037
  var URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
3957
4038
  var EMAIL_MATCHER = /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
3958
4039
  var MATCHERS = [
@@ -3980,13 +4061,13 @@ var MATCHERS = [
3980
4061
  }
3981
4062
  ];
3982
4063
  function LexicalAutoLinkPlugin() {
3983
- return /* @__PURE__ */ jsx77(AutoLinkPlugin, {
4064
+ return /* @__PURE__ */ jsx78(AutoLinkPlugin, {
3984
4065
  matchers: MATCHERS
3985
4066
  });
3986
4067
  }
3987
4068
 
3988
4069
  // src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx
3989
- import { useEffect, useRef, useState as useState3 } from "react";
4070
+ import { useEffect as useEffect2, useRef, useState as useState4 } from "react";
3990
4071
  import { $getNearestNodeFromDOMNode as $getNearestNodeFromDOMNode3 } from "lexical";
3991
4072
  import { createPortal } from "react-dom";
3992
4073
  import { useDebouncedCallback as useDebouncedCallback2 } from "use-debounce";
@@ -3995,13 +4076,14 @@ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext
3995
4076
 
3996
4077
  // src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx
3997
4078
  import "react";
3998
- import { useState } from "react";
4079
+ import { useState as useState2 } from "react";
3999
4080
  import { $getNearestNodeFromDOMNode, $getSelection, $setSelection } from "lexical";
4000
4081
  import { useDebouncedCallback } from "use-debounce";
4001
4082
  import { $isCodeNode as $isCodeNode2 } from "@lexical/code";
4002
- import { jsx as jsx78 } from "react/jsx-runtime";
4083
+ import { jsx as jsx79 } from "react/jsx-runtime";
4003
4084
  function CopyButton({ editor, getCodeDOMNode }) {
4004
- const [isCopyCompleted, setCopyCompleted] = useState(false);
4085
+ const [isCopyCompleted, setCopyCompleted] = useState2(false);
4086
+ const tr = useTr();
4005
4087
  const removeSuccessIcon = useDebouncedCallback(() => {
4006
4088
  setCopyCompleted(false);
4007
4089
  }, 1e3);
@@ -4027,13 +4109,13 @@ function CopyButton({ editor, getCodeDOMNode }) {
4027
4109
  console.error("Failed to copy: ", err);
4028
4110
  }
4029
4111
  }
4030
- return /* @__PURE__ */ jsx78("button", {
4112
+ return /* @__PURE__ */ jsx79("button", {
4031
4113
  className: "menu-item",
4032
4114
  onClick: handleClick,
4033
- "aria-label": "copy",
4034
- children: isCopyCompleted ? /* @__PURE__ */ jsx78("i", {
4115
+ "aria-label": tr("actionCopyCode"),
4116
+ children: isCopyCompleted ? /* @__PURE__ */ jsx79("i", {
4035
4117
  className: "format success"
4036
- }) : /* @__PURE__ */ jsx78("i", {
4118
+ }) : /* @__PURE__ */ jsx79("i", {
4037
4119
  className: "format copy"
4038
4120
  })
4039
4121
  });
@@ -4041,10 +4123,10 @@ function CopyButton({ editor, getCodeDOMNode }) {
4041
4123
 
4042
4124
  // src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx
4043
4125
  import "react";
4044
- import { useState as useState2 } from "react";
4126
+ import { useState as useState3 } from "react";
4045
4127
  import { $getNearestNodeFromDOMNode as $getNearestNodeFromDOMNode2 } from "lexical";
4046
4128
  import { $isCodeNode as $isCodeNode3 } from "@lexical/code";
4047
- import { jsx as jsx79, jsxs as jsxs58 } from "react/jsx-runtime";
4129
+ import { jsx as jsx80, jsxs as jsxs58 } from "react/jsx-runtime";
4048
4130
  var PRETTIER_PARSER_MODULES = {
4049
4131
  css: () => import("prettier/parser-postcss"),
4050
4132
  html: () => import("prettier/parser-html"),
@@ -4084,8 +4166,9 @@ function getPrettierOptions(lang) {
4084
4166
  return options;
4085
4167
  }
4086
4168
  function PrettierButton({ lang, editor, getCodeDOMNode }) {
4087
- const [syntaxError, setSyntaxError] = useState2("");
4088
- const [tipsVisible, setTipsVisible] = useState2(false);
4169
+ const [syntaxError, setSyntaxError] = useState3("");
4170
+ const [tipsVisible, setTipsVisible] = useState3(false);
4171
+ const tr = useTr();
4089
4172
  async function handleClick() {
4090
4173
  const codeDOMNode = getCodeDOMNode();
4091
4174
  try {
@@ -4101,6 +4184,7 @@ function PrettierButton({ lang, editor, getCodeDOMNode }) {
4101
4184
  const content = codeNode.getTextContent();
4102
4185
  let parsed = "";
4103
4186
  parsed = format(content, options);
4187
+ parsed = parsed.replace(/[\r\n]+$/, "");
4104
4188
  if (parsed !== "") {
4105
4189
  const selection = codeNode.select(0);
4106
4190
  selection.insertText(parsed);
@@ -4131,19 +4215,19 @@ function PrettierButton({ lang, editor, getCodeDOMNode }) {
4131
4215
  return /* @__PURE__ */ jsxs58("div", {
4132
4216
  className: "prettier-wrapper",
4133
4217
  children: [
4134
- /* @__PURE__ */ jsx79("button", {
4218
+ /* @__PURE__ */ jsx80("button", {
4135
4219
  className: "menu-item",
4136
4220
  onClick: handleClick,
4137
4221
  onMouseEnter: handleMouseEnter,
4138
4222
  onMouseLeave: handleMouseLeave,
4139
- "aria-label": "prettier",
4140
- children: syntaxError ? /* @__PURE__ */ jsx79("i", {
4223
+ "aria-label": tr("actionFormatCode"),
4224
+ children: syntaxError ? /* @__PURE__ */ jsx80("i", {
4141
4225
  className: "format prettier-error"
4142
- }) : /* @__PURE__ */ jsx79("i", {
4226
+ }) : /* @__PURE__ */ jsx80("i", {
4143
4227
  className: "format prettier"
4144
4228
  })
4145
4229
  }),
4146
- tipsVisible ? /* @__PURE__ */ jsx79("pre", {
4230
+ tipsVisible ? /* @__PURE__ */ jsx80("pre", {
4147
4231
  className: "code-error-tips",
4148
4232
  children: syntaxError
4149
4233
  }) : null
@@ -4152,14 +4236,14 @@ function PrettierButton({ lang, editor, getCodeDOMNode }) {
4152
4236
  }
4153
4237
 
4154
4238
  // src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx
4155
- import { Fragment as Fragment2, jsx as jsx80, jsxs as jsxs59 } from "react/jsx-runtime";
4239
+ import { Fragment as Fragment2, jsx as jsx81, jsxs as jsxs59 } from "react/jsx-runtime";
4156
4240
  var CODE_PADDING = 8;
4157
4241
  function CodeActionMenuContainer({ anchorElem }) {
4158
4242
  const [editor] = useLexicalComposerContext();
4159
- const [lang, setLang] = useState3("");
4160
- const [isShown, setShown] = useState3(false);
4161
- const [shouldListenMouseMove, setShouldListenMouseMove] = useState3(false);
4162
- const [position, setPosition] = useState3({
4243
+ const [lang, setLang] = useState4("");
4244
+ const [isShown, setShown] = useState4(false);
4245
+ const [shouldListenMouseMove, setShouldListenMouseMove] = useState4(true);
4246
+ const [position, setPosition] = useState4({
4163
4247
  right: "0",
4164
4248
  top: "0"
4165
4249
  });
@@ -4198,7 +4282,7 @@ function CodeActionMenuContainer({ anchorElem }) {
4198
4282
  });
4199
4283
  }
4200
4284
  }, 50);
4201
- useEffect(() => {
4285
+ useEffect2(() => {
4202
4286
  if (!shouldListenMouseMove) {
4203
4287
  return;
4204
4288
  }
@@ -4229,20 +4313,20 @@ function CodeActionMenuContainer({ anchorElem }) {
4229
4313
  });
4230
4314
  const normalizedLang = normalizeCodeLang(lang);
4231
4315
  const codeFriendlyName = getLanguageFriendlyName(lang);
4232
- return /* @__PURE__ */ jsx80(Fragment2, {
4316
+ return /* @__PURE__ */ jsx81(Fragment2, {
4233
4317
  children: isShown ? /* @__PURE__ */ jsxs59("div", {
4234
4318
  className: "code-action-menu-container",
4235
4319
  style: { ...position },
4236
4320
  children: [
4237
- /* @__PURE__ */ jsx80("div", {
4321
+ /* @__PURE__ */ jsx81("div", {
4238
4322
  className: "code-highlight-language",
4239
4323
  children: codeFriendlyName
4240
4324
  }),
4241
- /* @__PURE__ */ jsx80(CopyButton, {
4325
+ /* @__PURE__ */ jsx81(CopyButton, {
4242
4326
  editor,
4243
4327
  getCodeDOMNode
4244
4328
  }),
4245
- canBePrettier(normalizedLang) ? /* @__PURE__ */ jsx80(PrettierButton, {
4329
+ canBePrettier(normalizedLang) ? /* @__PURE__ */ jsx81(PrettierButton, {
4246
4330
  editor,
4247
4331
  getCodeDOMNode,
4248
4332
  lang: normalizedLang
@@ -4264,25 +4348,25 @@ function getMouseInfo(event) {
4264
4348
  function CodeActionMenuPlugin({
4265
4349
  anchorElem = document.body
4266
4350
  }) {
4267
- return createPortal(/* @__PURE__ */ jsx80(CodeActionMenuContainer, {
4351
+ return createPortal(/* @__PURE__ */ jsx81(CodeActionMenuContainer, {
4268
4352
  anchorElem
4269
4353
  }), anchorElem);
4270
4354
  }
4271
4355
 
4272
4356
  // src/rich-text-editor/plugins/CodeHighlightPlugin/index.ts
4273
- import { useEffect as useEffect2 } from "react";
4357
+ import { useEffect as useEffect3 } from "react";
4274
4358
  import { registerCodeHighlighting } from "@lexical/code";
4275
4359
  import { useLexicalComposerContext as useLexicalComposerContext2 } from "@lexical/react/LexicalComposerContext";
4276
4360
  function CodeHighlightPlugin() {
4277
4361
  const [editor] = useLexicalComposerContext2();
4278
- useEffect2(() => {
4362
+ useEffect3(() => {
4279
4363
  return registerCodeHighlighting(editor);
4280
4364
  }, [editor]);
4281
4365
  return null;
4282
4366
  }
4283
4367
 
4284
4368
  // src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx
4285
- import { useCallback, useEffect as useEffect4, useRef as useRef2, useState as useState5 } from "react";
4369
+ import { useCallback, useEffect as useEffect5, useRef as useRef2, useState as useState6 } from "react";
4286
4370
  import "react";
4287
4371
  import {
4288
4372
  $getSelection as $getSelection3,
@@ -4299,10 +4383,10 @@ import { useLexicalComposerContext as useLexicalComposerContext4 } from "@lexica
4299
4383
  import { $findMatchingParent, mergeRegister } from "@lexical/utils";
4300
4384
 
4301
4385
  // src/rich-text-editor/ui/LinkPreview.tsx
4302
- import { Suspense, useEffect as useEffect3, useState as useState4 } from "react";
4303
- import { $getSelection as $getSelection2, $isTextNode as $isTextNode2 } from "lexical";
4386
+ import { Suspense, useEffect as useEffect4, useState as useState5 } from "react";
4387
+ import { $getSelection as $getSelection2, $isTextNode as $isTextNode3 } from "lexical";
4304
4388
  import { useLexicalComposerContext as useLexicalComposerContext3 } from "@lexical/react/LexicalComposerContext";
4305
- import { Fragment as Fragment3, jsx as jsx81, jsxs as jsxs60 } from "react/jsx-runtime";
4389
+ import { Fragment as Fragment3, jsx as jsx82, jsxs as jsxs60 } from "react/jsx-runtime";
4306
4390
  var PREVIEW_CACHE = {};
4307
4391
  var URL_MATCHER2 = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
4308
4392
  function useSuspenseRequest(url) {
@@ -4326,17 +4410,18 @@ function useSuspenseRequest(url) {
4326
4410
  function LinkPreviewContent({
4327
4411
  url
4328
4412
  }) {
4329
- const [textContent, setTextContent] = useState4("");
4413
+ const [textContent, setTextContent] = useState5("");
4330
4414
  const { preview } = useSuspenseRequest(url);
4331
4415
  const [editor] = useLexicalComposerContext3();
4416
+ const tr = useTr();
4332
4417
  const hasPreview = preview !== null && preview.google?.title;
4333
- useEffect3(() => {
4418
+ useEffect4(() => {
4334
4419
  editor.update(() => {
4335
4420
  const sel = $getSelection2();
4336
4421
  const nodes = sel?.getNodes();
4337
4422
  if (hasPreview && nodes?.length === 1) {
4338
4423
  const [firstNode] = nodes;
4339
- if ($isTextNode2(firstNode)) {
4424
+ if ($isTextNode3(firstNode)) {
4340
4425
  setTextContent(firstNode.getTextContent());
4341
4426
  }
4342
4427
  }
@@ -4348,7 +4433,7 @@ function LinkPreviewContent({
4348
4433
  const nodes = sel?.getNodes();
4349
4434
  if (hasPreview && nodes?.length === 1) {
4350
4435
  const [firstNode] = nodes;
4351
- if ($isTextNode2(firstNode)) {
4436
+ if ($isTextNode3(firstNode)) {
4352
4437
  firstNode.setTextContent(preview.google.title);
4353
4438
  setTextContent(preview.google.title);
4354
4439
  }
@@ -4361,32 +4446,32 @@ function LinkPreviewContent({
4361
4446
  return /* @__PURE__ */ jsxs60("div", {
4362
4447
  className: "LinkPreview__container",
4363
4448
  children: [
4364
- preview.google.image && /* @__PURE__ */ jsx81("div", {
4449
+ preview.google.image && /* @__PURE__ */ jsx82("div", {
4365
4450
  className: "LinkPreview__imageWrapper bg-purple-50-900",
4366
- children: /* @__PURE__ */ jsx81("img", {
4451
+ children: /* @__PURE__ */ jsx82("img", {
4367
4452
  src: preview.google.image,
4368
4453
  alt: preview.google.title,
4369
4454
  className: "LinkPreview__image"
4370
4455
  })
4371
4456
  }),
4372
- preview.google.title && /* @__PURE__ */ jsx81("div", {
4457
+ preview.google.title && /* @__PURE__ */ jsx82("div", {
4373
4458
  className: "LinkPreview__title",
4374
4459
  children: preview.google.title
4375
4460
  }),
4376
- preview.google.description && /* @__PURE__ */ jsx81("div", {
4461
+ preview.google.description && /* @__PURE__ */ jsx82("div", {
4377
4462
  className: "LinkPreview__description",
4378
4463
  children: preview.google.description
4379
4464
  }),
4380
- textContent && textContent !== preview.google.title ? /* @__PURE__ */ jsx81(Button, {
4465
+ textContent && textContent !== preview.google.title ? /* @__PURE__ */ jsx82(Button, {
4381
4466
  className: "mb-4 ml-5",
4382
4467
  onClick: useTitleForText,
4383
- children: "Replace link text with its title"
4468
+ children: tr("linkPreviewReplaceTextWithTitle")
4384
4469
  }) : null
4385
4470
  ]
4386
4471
  });
4387
4472
  }
4388
4473
  function Glimmer(props) {
4389
- return /* @__PURE__ */ jsx81("div", {
4474
+ return /* @__PURE__ */ jsx82("div", {
4390
4475
  className: "LinkPreview__glimmer",
4391
4476
  ...props,
4392
4477
  style: {
@@ -4398,24 +4483,24 @@ function Glimmer(props) {
4398
4483
  function LinkPreview({
4399
4484
  url
4400
4485
  }) {
4401
- return /* @__PURE__ */ jsx81(Suspense, {
4486
+ return /* @__PURE__ */ jsx82(Suspense, {
4402
4487
  fallback: /* @__PURE__ */ jsxs60(Fragment3, {
4403
4488
  children: [
4404
- /* @__PURE__ */ jsx81(Glimmer, {
4489
+ /* @__PURE__ */ jsx82(Glimmer, {
4405
4490
  style: { height: "80px" },
4406
4491
  index: 0
4407
4492
  }),
4408
- /* @__PURE__ */ jsx81(Glimmer, {
4493
+ /* @__PURE__ */ jsx82(Glimmer, {
4409
4494
  style: { width: "60%" },
4410
4495
  index: 1
4411
4496
  }),
4412
- /* @__PURE__ */ jsx81(Glimmer, {
4497
+ /* @__PURE__ */ jsx82(Glimmer, {
4413
4498
  style: { width: "80%" },
4414
4499
  index: 2
4415
4500
  })
4416
4501
  ]
4417
4502
  }),
4418
- children: /* @__PURE__ */ jsx81(LinkPreviewContent, {
4503
+ children: /* @__PURE__ */ jsx82(LinkPreviewContent, {
4419
4504
  url
4420
4505
  })
4421
4506
  });
@@ -4484,7 +4569,7 @@ function validateUrl(url) {
4484
4569
  }
4485
4570
 
4486
4571
  // src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx
4487
- import { Fragment as Fragment4, jsx as jsx82, jsxs as jsxs61 } from "react/jsx-runtime";
4572
+ import { Fragment as Fragment4, jsx as jsx83, jsxs as jsxs61 } from "react/jsx-runtime";
4488
4573
  function FloatingLinkEditor({
4489
4574
  editor,
4490
4575
  isLink,
@@ -4493,11 +4578,12 @@ function FloatingLinkEditor({
4493
4578
  }) {
4494
4579
  const editorRef = useRef2(null);
4495
4580
  const inputRef = useRef2(null);
4496
- const [linkUrl, setLinkUrl] = useState5("");
4497
- const [rel, setRel] = useState5(null);
4498
- const [target, setTarget] = useState5(null);
4499
- const [isEditMode, setEditMode] = useState5(false);
4500
- const [lastSelection, setLastSelection] = useState5(null);
4581
+ const [linkUrl, setLinkUrl] = useState6("");
4582
+ const [rel, setRel] = useState6(null);
4583
+ const [target, setTarget] = useState6(null);
4584
+ const [isEditMode, setEditMode] = useState6(false);
4585
+ const [lastSelection, setLastSelection] = useState6(null);
4586
+ const tr = useTr();
4501
4587
  const updateLinkEditor = useCallback(() => {
4502
4588
  const selection = $getSelection3();
4503
4589
  if ($isRangeSelection(selection)) {
@@ -4548,7 +4634,7 @@ function FloatingLinkEditor({
4548
4634
  }
4549
4635
  return true;
4550
4636
  }, [anchorElem, editor]);
4551
- useEffect4(() => {
4637
+ useEffect5(() => {
4552
4638
  const scrollerElem = anchorElem.parentElement;
4553
4639
  const update = () => {
4554
4640
  editor.getEditorState().read(() => {
@@ -4566,7 +4652,7 @@ function FloatingLinkEditor({
4566
4652
  }
4567
4653
  };
4568
4654
  }, [anchorElem.parentElement, editor, updateLinkEditor]);
4569
- useEffect4(() => {
4655
+ useEffect5(() => {
4570
4656
  return mergeRegister(
4571
4657
  editor.registerUpdateListener(({ editorState }) => {
4572
4658
  editorState.read(() => {
@@ -4594,51 +4680,51 @@ function FloatingLinkEditor({
4594
4680
  )
4595
4681
  );
4596
4682
  }, [editor, updateLinkEditor, setIsLink, isLink]);
4597
- useEffect4(() => {
4683
+ useEffect5(() => {
4598
4684
  editor.getEditorState().read(() => {
4599
4685
  updateLinkEditor();
4600
4686
  });
4601
4687
  }, [editor, updateLinkEditor]);
4602
- useEffect4(() => {
4688
+ useEffect5(() => {
4603
4689
  if (isEditMode && inputRef.current) {
4604
4690
  inputRef.current.focus();
4605
4691
  }
4606
4692
  }, [isEditMode]);
4607
- return /* @__PURE__ */ jsx82("div", {
4693
+ return /* @__PURE__ */ jsx83("div", {
4608
4694
  ref: editorRef,
4609
4695
  className: "link-editor",
4610
4696
  children: isEditMode ? /* @__PURE__ */ jsxs61("div", {
4611
4697
  children: [
4612
- /* @__PURE__ */ jsx82("div", {
4698
+ /* @__PURE__ */ jsx83("div", {
4613
4699
  className: "border-0 border-b border-gray-100-800 border-solid px-3",
4614
- children: /* @__PURE__ */ jsx82(InputWithLabel, {
4615
- label: "Link",
4700
+ children: /* @__PURE__ */ jsx83(InputWithLabel, {
4701
+ label: tr("linkEditorLink"),
4616
4702
  type: "text",
4617
4703
  value: linkUrl,
4618
4704
  onChange: (e) => setLinkUrl(e.target.value)
4619
4705
  })
4620
4706
  }),
4621
- /* @__PURE__ */ jsx82("div", {
4707
+ /* @__PURE__ */ jsx83("div", {
4622
4708
  className: "border-0 border-b border-gray-100-800 border-solid px-3",
4623
- children: /* @__PURE__ */ jsx82(InputWithLabel, {
4624
- label: "Rel",
4709
+ children: /* @__PURE__ */ jsx83(InputWithLabel, {
4710
+ label: tr("linkEditorRel"),
4625
4711
  type: "text",
4626
4712
  value: rel ?? "",
4627
4713
  onChange: (e) => setRel(e.target.value)
4628
4714
  })
4629
4715
  }),
4630
- /* @__PURE__ */ jsx82("div", {
4716
+ /* @__PURE__ */ jsx83("div", {
4631
4717
  className: "border-0 border-b border-gray-100-800 border-solid px-3",
4632
- children: /* @__PURE__ */ jsx82(InputWithLabel, {
4633
- label: "Target",
4718
+ children: /* @__PURE__ */ jsx83(InputWithLabel, {
4719
+ label: tr("linkEditorTarget"),
4634
4720
  type: "text",
4635
4721
  value: target ?? "",
4636
4722
  onChange: (e) => setTarget(e.target.value)
4637
4723
  })
4638
4724
  }),
4639
- /* @__PURE__ */ jsx82("div", {
4725
+ /* @__PURE__ */ jsx83("div", {
4640
4726
  className: "flex px-6 py-2 justify-end",
4641
- children: /* @__PURE__ */ jsx82(Button, {
4727
+ children: /* @__PURE__ */ jsx83(Button, {
4642
4728
  onClick: () => {
4643
4729
  if (lastSelection !== null) {
4644
4730
  if (linkUrl !== "") {
@@ -4651,7 +4737,7 @@ function FloatingLinkEditor({
4651
4737
  setEditMode(false);
4652
4738
  }
4653
4739
  },
4654
- children: "Done"
4740
+ children: tr("linkEditorCommit")
4655
4741
  })
4656
4742
  })
4657
4743
  ]
@@ -4661,9 +4747,9 @@ function FloatingLinkEditor({
4661
4747
  className: "link-input !flex flex-nowrap justify-between items-center max-w-full ",
4662
4748
  children: [
4663
4749
  /* @__PURE__ */ jsxs61("div", {
4664
- className: " grid",
4750
+ className: "grid",
4665
4751
  children: [
4666
- /* @__PURE__ */ jsx82("a", {
4752
+ /* @__PURE__ */ jsx83("a", {
4667
4753
  href: linkUrl,
4668
4754
  target: "_blank",
4669
4755
  rel: "noopener noreferrer",
@@ -4672,11 +4758,11 @@ function FloatingLinkEditor({
4672
4758
  rel || target ? /* @__PURE__ */ jsxs61("div", {
4673
4759
  className: "flex mt-1 gap-1",
4674
4760
  children: [
4675
- rel && /* @__PURE__ */ jsx82("div", {
4761
+ rel && /* @__PURE__ */ jsx83("div", {
4676
4762
  className: "text-[10px] text-gray-600-300 px-1 bg-purple-50-900 rounded-md py-0.5",
4677
4763
  children: rel
4678
4764
  }),
4679
- target && /* @__PURE__ */ jsx82("div", {
4765
+ target && /* @__PURE__ */ jsx83("div", {
4680
4766
  className: "text-[10px] text-gray-600-300 px-1 bg-purple-50-900 rounded-md py-0.5",
4681
4767
  children: target
4682
4768
  })
@@ -4684,19 +4770,20 @@ function FloatingLinkEditor({
4684
4770
  }) : null
4685
4771
  ]
4686
4772
  }),
4687
- /* @__PURE__ */ jsx82("div", {
4688
- children: /* @__PURE__ */ jsx82(IconButton, {
4773
+ /* @__PURE__ */ jsx83("div", {
4774
+ children: /* @__PURE__ */ jsx83(IconButton, {
4689
4775
  size: "sm",
4690
4776
  tabIndex: 0,
4691
4777
  onMouseDown: (event) => event.preventDefault(),
4692
4778
  onClick: () => setEditMode(true),
4693
- children: /* @__PURE__ */ jsx82(Icon.Edit, {})
4779
+ "aria-label": tr("linkEditorEdit"),
4780
+ children: /* @__PURE__ */ jsx83(Icon.Edit, {})
4694
4781
  })
4695
4782
  })
4696
4783
  ]
4697
4784
  }),
4698
- /* @__PURE__ */ jsx82("div", {
4699
- children: /* @__PURE__ */ jsx82(LinkPreview, {
4785
+ /* @__PURE__ */ jsx83("div", {
4786
+ children: /* @__PURE__ */ jsx83(LinkPreview, {
4700
4787
  url: linkUrl
4701
4788
  })
4702
4789
  })
@@ -4705,8 +4792,8 @@ function FloatingLinkEditor({
4705
4792
  });
4706
4793
  }
4707
4794
  function useFloatingLinkEditorToolbar(editor, anchorElem) {
4708
- const [activeEditor, setActiveEditor] = useState5(editor);
4709
- const [isLink, setIsLink] = useState5(false);
4795
+ const [activeEditor, setActiveEditor] = useState6(editor);
4796
+ const [isLink, setIsLink] = useState6(false);
4710
4797
  const updateToolbar = useCallback(() => {
4711
4798
  const selection = $getSelection3();
4712
4799
  if ($isRangeSelection(selection)) {
@@ -4720,7 +4807,7 @@ function useFloatingLinkEditorToolbar(editor, anchorElem) {
4720
4807
  }
4721
4808
  }
4722
4809
  }, []);
4723
- useEffect4(() => {
4810
+ useEffect5(() => {
4724
4811
  return editor.registerCommand(
4725
4812
  SELECTION_CHANGE_COMMAND,
4726
4813
  (_payload, newEditor) => {
@@ -4732,7 +4819,7 @@ function useFloatingLinkEditorToolbar(editor, anchorElem) {
4732
4819
  );
4733
4820
  }, [editor, updateToolbar]);
4734
4821
  return isLink ? createPortal2(
4735
- /* @__PURE__ */ jsx82(FloatingLinkEditor, {
4822
+ /* @__PURE__ */ jsx83(FloatingLinkEditor, {
4736
4823
  editor: activeEditor,
4737
4824
  isLink,
4738
4825
  anchorElem,
@@ -4749,12 +4836,12 @@ function FloatingLinkEditorPlugin({
4749
4836
  }
4750
4837
 
4751
4838
  // src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx
4752
- import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef3, useState as useState6 } from "react";
4839
+ import { useCallback as useCallback2, useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
4753
4840
  import "react";
4754
4841
  import {
4755
4842
  $getSelection as $getSelection4,
4756
4843
  $isRangeSelection as $isRangeSelection2,
4757
- $isTextNode as $isTextNode3,
4844
+ $isTextNode as $isTextNode4,
4758
4845
  COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW2,
4759
4846
  FORMAT_TEXT_COMMAND,
4760
4847
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND2
@@ -4765,6 +4852,9 @@ import { $isLinkNode as $isLinkNode3, TOGGLE_LINK_COMMAND as TOGGLE_LINK_COMMAND
4765
4852
  import { useLexicalComposerContext as useLexicalComposerContext5 } from "@lexical/react/LexicalComposerContext";
4766
4853
  import { mergeRegister as mergeRegister2 } from "@lexical/utils";
4767
4854
 
4855
+ // src/rich-text-editor/utils/environment.ts
4856
+ var IS_APPLE = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
4857
+
4768
4858
  // src/rich-text-editor/utils/getDOMRangeRect.ts
4769
4859
  function getDOMRangeRect(nativeSelection, rootElement) {
4770
4860
  const domRange = nativeSelection.getRangeAt(0);
@@ -4795,7 +4885,7 @@ function getDOMRangeRect(nativeSelection, rootElement) {
4795
4885
  }
4796
4886
 
4797
4887
  // src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx
4798
- import { Fragment as Fragment5, jsx as jsx83, jsxs as jsxs62 } from "react/jsx-runtime";
4888
+ import { Fragment as Fragment5, jsx as jsx84, jsxs as jsxs62 } from "react/jsx-runtime";
4799
4889
  function TextFormatFloatingToolbar({
4800
4890
  editor,
4801
4891
  anchorElem,
@@ -4809,6 +4899,7 @@ function TextFormatFloatingToolbar({
4809
4899
  isSuperscript
4810
4900
  }) {
4811
4901
  const popupCharStylesEditorRef = useRef3(null);
4902
+ const tr = useTr();
4812
4903
  const insertLink = useCallback2(() => {
4813
4904
  if (!isLink) {
4814
4905
  editor.dispatchCommand(TOGGLE_LINK_COMMAND2, "https://");
@@ -4829,7 +4920,7 @@ function TextFormatFloatingToolbar({
4829
4920
  setFloatingElemPosition(rangeRect, popupCharStylesEditorElem, anchorElem);
4830
4921
  }
4831
4922
  }, [editor, anchorElem]);
4832
- useEffect5(() => {
4923
+ useEffect6(() => {
4833
4924
  const scrollerElem = anchorElem.parentElement;
4834
4925
  const update = () => {
4835
4926
  editor.getEditorState().read(() => {
@@ -4847,7 +4938,7 @@ function TextFormatFloatingToolbar({
4847
4938
  }
4848
4939
  };
4849
4940
  }, [editor, updateTextFormatFloatingToolbar, anchorElem]);
4850
- useEffect5(() => {
4941
+ useEffect6(() => {
4851
4942
  editor.getEditorState().read(() => {
4852
4943
  updateTextFormatFloatingToolbar();
4853
4944
  });
@@ -4867,88 +4958,92 @@ function TextFormatFloatingToolbar({
4867
4958
  )
4868
4959
  );
4869
4960
  }, [editor, updateTextFormatFloatingToolbar]);
4870
- return /* @__PURE__ */ jsx83("div", {
4961
+ return /* @__PURE__ */ jsx84("div", {
4871
4962
  ref: popupCharStylesEditorRef,
4872
4963
  className: "c-floating-text-format-popup gap-0.5",
4873
4964
  children: editor.isEditable() && /* @__PURE__ */ jsxs62(Fragment5, {
4874
4965
  children: [
4875
- /* @__PURE__ */ jsx83(IconButton, {
4966
+ /* @__PURE__ */ jsx84(IconButton, {
4876
4967
  onClick: () => {
4877
4968
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
4878
4969
  },
4879
4970
  style: { padding: 0, overflow: "hidden" },
4880
- "aria-label": "Format text as bold",
4881
- children: /* @__PURE__ */ jsx83("i", {
4971
+ title: tr(IS_APPLE ? "actionFormatAsStrongTitleApple" : "actionFormatAsStrongTitle"),
4972
+ "aria-label": tr("actionFormatAsStrongLabel"),
4973
+ children: /* @__PURE__ */ jsx84("i", {
4882
4974
  className: `format bold w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isBold ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4883
4975
  })
4884
4976
  }),
4885
- /* @__PURE__ */ jsx83(IconButton, {
4977
+ /* @__PURE__ */ jsx84(IconButton, {
4886
4978
  style: { padding: 0, overflow: "hidden" },
4887
4979
  onClick: () => {
4888
4980
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
4889
4981
  },
4890
- "aria-label": "Format text as italics",
4891
- children: /* @__PURE__ */ jsx83("i", {
4982
+ title: tr("actionFormatAsEmphasizedTitle"),
4983
+ "aria-label": tr("actionFormatAsEmphasizedLabel"),
4984
+ children: /* @__PURE__ */ jsx84("i", {
4892
4985
  className: `format italic w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isItalic ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4893
4986
  })
4894
4987
  }),
4895
- /* @__PURE__ */ jsx83(IconButton, {
4988
+ /* @__PURE__ */ jsx84(IconButton, {
4896
4989
  style: { padding: 0, overflow: "hidden" },
4897
4990
  onClick: () => {
4898
4991
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "underline");
4899
4992
  },
4900
- "aria-label": "Format text to underlined",
4901
- children: /* @__PURE__ */ jsx83("i", {
4993
+ title: tr("actionFormatAsUnderlinedTitle"),
4994
+ "aria-label": tr("actionFormatAsUnderlinedLabel"),
4995
+ children: /* @__PURE__ */ jsx84("i", {
4902
4996
  className: `format underline w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isUnderline ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4903
4997
  })
4904
4998
  }),
4905
- /* @__PURE__ */ jsx83(IconButton, {
4999
+ /* @__PURE__ */ jsx84(IconButton, {
4906
5000
  style: { padding: 0, overflow: "hidden" },
4907
5001
  onClick: () => {
4908
5002
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "strikethrough");
4909
5003
  },
4910
- "aria-label": "Format text with a strikethrough",
4911
- children: /* @__PURE__ */ jsx83("i", {
5004
+ title: tr("actionFormatWithStrikethroughTitle"),
5005
+ "aria-label": tr("actionFormatWithStrikethroughLabel"),
5006
+ children: /* @__PURE__ */ jsx84("i", {
4912
5007
  className: `format strikethrough w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isStrikethrough ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4913
5008
  })
4914
5009
  }),
4915
- /* @__PURE__ */ jsx83(IconButton, {
5010
+ /* @__PURE__ */ jsx84(IconButton, {
4916
5011
  style: { padding: 0, overflow: "hidden" },
4917
5012
  onClick: () => {
4918
5013
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "subscript");
4919
5014
  },
4920
- title: "Subscript",
4921
- "aria-label": "Format Subscript",
4922
- children: /* @__PURE__ */ jsx83("i", {
5015
+ title: tr("actionFormatWithSubscriptTitle"),
5016
+ "aria-label": tr("actionFormatWithSubscriptLabel"),
5017
+ children: /* @__PURE__ */ jsx84("i", {
4923
5018
  className: `format subscript w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isSubscript ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4924
5019
  })
4925
5020
  }),
4926
- /* @__PURE__ */ jsx83(IconButton, {
5021
+ /* @__PURE__ */ jsx84(IconButton, {
4927
5022
  style: { padding: 0, overflow: "hidden" },
4928
5023
  onClick: () => {
4929
5024
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "superscript");
4930
5025
  },
4931
- title: "Superscript",
4932
- "aria-label": "Format Superscript",
4933
- children: /* @__PURE__ */ jsx83("i", {
5026
+ title: tr("actionFormatWithSuperscriptTitle"),
5027
+ "aria-label": tr("actionFormatWithSuperscriptLabel"),
5028
+ children: /* @__PURE__ */ jsx84("i", {
4934
5029
  className: `format superscript w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isSuperscript ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4935
5030
  })
4936
5031
  }),
4937
- /* @__PURE__ */ jsx83(IconButton, {
5032
+ /* @__PURE__ */ jsx84(IconButton, {
4938
5033
  style: { padding: 0, overflow: "hidden" },
4939
5034
  onClick: () => {
4940
5035
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "code");
4941
5036
  },
4942
- "aria-label": "Insert code block",
4943
- children: /* @__PURE__ */ jsx83("i", {
5037
+ "aria-label": tr("actionInsertCodeBlock"),
5038
+ children: /* @__PURE__ */ jsx84("i", {
4944
5039
  className: `format code w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isCode ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4945
5040
  })
4946
5041
  }),
4947
- /* @__PURE__ */ jsx83(IconButton, {
5042
+ /* @__PURE__ */ jsx84(IconButton, {
4948
5043
  style: { padding: 0, overflow: "hidden" },
4949
5044
  onClick: insertLink,
4950
- "aria-label": "Insert link",
4951
- children: /* @__PURE__ */ jsx83("i", {
5045
+ "aria-label": tr("actionInsertlink"),
5046
+ children: /* @__PURE__ */ jsx84("i", {
4952
5047
  className: `format link w-full h-full bg-[length:18px_18px] bg-no-repeat bg-center ${isLink ? "bg-purple-50-900 opacity-100" : "opacity-60"}`
4953
5048
  })
4954
5049
  })
@@ -4957,15 +5052,15 @@ function TextFormatFloatingToolbar({
4957
5052
  });
4958
5053
  }
4959
5054
  function useFloatingTextFormatToolbar(editor, anchorElem) {
4960
- const [isText, setIsText] = useState6(false);
4961
- const [isLink, setIsLink] = useState6(false);
4962
- const [isBold, setIsBold] = useState6(false);
4963
- const [isItalic, setIsItalic] = useState6(false);
4964
- const [isUnderline, setIsUnderline] = useState6(false);
4965
- const [isStrikethrough, setIsStrikethrough] = useState6(false);
4966
- const [isSubscript, setIsSubscript] = useState6(false);
4967
- const [isSuperscript, setIsSuperscript] = useState6(false);
4968
- const [isCode, setIsCode] = useState6(false);
5055
+ const [isText, setIsText] = useState7(false);
5056
+ const [isLink, setIsLink] = useState7(false);
5057
+ const [isBold, setIsBold] = useState7(false);
5058
+ const [isItalic, setIsItalic] = useState7(false);
5059
+ const [isUnderline, setIsUnderline] = useState7(false);
5060
+ const [isStrikethrough, setIsStrikethrough] = useState7(false);
5061
+ const [isSubscript, setIsSubscript] = useState7(false);
5062
+ const [isSuperscript, setIsSuperscript] = useState7(false);
5063
+ const [isCode, setIsCode] = useState7(false);
4969
5064
  const updatePopup = useCallback2(() => {
4970
5065
  editor.getEditorState().read(() => {
4971
5066
  if (editor.isComposing()) {
@@ -4996,19 +5091,19 @@ function useFloatingTextFormatToolbar(editor, anchorElem) {
4996
5091
  setIsLink(false);
4997
5092
  }
4998
5093
  if (!$isCodeHighlightNode(selection.anchor.getNode()) && selection.getTextContent() !== "") {
4999
- setIsText($isTextNode3(node));
5094
+ setIsText($isTextNode4(node));
5000
5095
  } else {
5001
5096
  setIsText(false);
5002
5097
  }
5003
5098
  });
5004
5099
  }, [editor]);
5005
- useEffect5(() => {
5100
+ useEffect6(() => {
5006
5101
  document.addEventListener("selectionchange", updatePopup);
5007
5102
  return () => {
5008
5103
  document.removeEventListener("selectionchange", updatePopup);
5009
5104
  };
5010
5105
  }, [updatePopup]);
5011
- useEffect5(() => {
5106
+ useEffect6(() => {
5012
5107
  return mergeRegister2(
5013
5108
  editor.registerUpdateListener(() => {
5014
5109
  updatePopup();
@@ -5024,7 +5119,7 @@ function useFloatingTextFormatToolbar(editor, anchorElem) {
5024
5119
  return null;
5025
5120
  }
5026
5121
  return createPortal3(
5027
- /* @__PURE__ */ jsx83(TextFormatFloatingToolbar, {
5122
+ /* @__PURE__ */ jsx84(TextFormatFloatingToolbar, {
5028
5123
  editor,
5029
5124
  anchorElem,
5030
5125
  isLink,
@@ -5049,9 +5144,9 @@ function FloatingTextFormatToolbarPlugin({
5049
5144
  // src/rich-text-editor/plugins/LinkPlugin/index.tsx
5050
5145
  import { LinkPlugin as LexicalLinkPlugin } from "@lexical/react/LexicalLinkPlugin";
5051
5146
  import "react";
5052
- import { jsx as jsx84 } from "react/jsx-runtime";
5147
+ import { jsx as jsx85 } from "react/jsx-runtime";
5053
5148
  function LinkPlugin() {
5054
- return /* @__PURE__ */ jsx84(LexicalLinkPlugin, {
5149
+ return /* @__PURE__ */ jsx85(LexicalLinkPlugin, {
5055
5150
  validateUrl
5056
5151
  });
5057
5152
  }
@@ -5066,7 +5161,7 @@ import {
5066
5161
  COMMAND_PRIORITY_CRITICAL as COMMAND_PRIORITY_CRITICAL2,
5067
5162
  INDENT_CONTENT_COMMAND
5068
5163
  } from "lexical";
5069
- import { useEffect as useEffect6 } from "react";
5164
+ import { useEffect as useEffect7 } from "react";
5070
5165
  function getElementNodesInSelection(selection) {
5071
5166
  const nodesInSelection = selection.getNodes();
5072
5167
  if (nodesInSelection.length === 0) {
@@ -5103,7 +5198,7 @@ function isIndentPermitted(maxDepth) {
5103
5198
  }
5104
5199
  function ListMaxIndentLevelPlugin({ maxDepth }) {
5105
5200
  const [editor] = useLexicalComposerContext6();
5106
- useEffect6(() => {
5201
+ useEffect7(() => {
5107
5202
  return editor.registerCommand(
5108
5203
  INDENT_CONTENT_COMMAND,
5109
5204
  () => !isIndentPermitted(maxDepth ?? 7),
@@ -5114,7 +5209,7 @@ function ListMaxIndentLevelPlugin({ maxDepth }) {
5114
5209
  }
5115
5210
 
5116
5211
  // src/rich-text-editor/plugins/MaxLengthPlugin/index.tsx
5117
- import { useEffect as useEffect7 } from "react";
5212
+ import { useEffect as useEffect8 } from "react";
5118
5213
  import { $getSelection as $getSelection6, $isRangeSelection as $isRangeSelection4 } from "lexical";
5119
5214
  import { useLexicalComposerContext as useLexicalComposerContext7 } from "@lexical/react/LexicalComposerContext";
5120
5215
  import { trimTextContentFromAnchor } from "@lexical/selection";
@@ -5156,7 +5251,7 @@ ${content}
5156
5251
  // src/rich-text-editor/plugins/MaxLengthPlugin/index.tsx
5157
5252
  function MaxLengthPlugin({ maxLength }) {
5158
5253
  const [editor] = useLexicalComposerContext7();
5159
- useEffect7(() => {
5254
+ useEffect8(() => {
5160
5255
  let lastRestoredEditorState = null;
5161
5256
  return editor.registerUpdateListener(({ editorState, prevEditorState }) => {
5162
5257
  editor.update(() => {
@@ -5186,14 +5281,9 @@ function MaxLengthPlugin({ maxLength }) {
5186
5281
  }
5187
5282
 
5188
5283
  // src/rich-text-editor/plugins/TabFocusPlugin/index.tsx
5284
+ import { useEffect as useEffect9 } from "react";
5285
+ import { $getSelection as $getSelection7, $isRangeSelection as $isRangeSelection5, $setSelection as $setSelection2, FOCUS_COMMAND } from "lexical";
5189
5286
  import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
5190
- import {
5191
- $getSelection as $getSelection7,
5192
- $isRangeSelection as $isRangeSelection5,
5193
- $setSelection as $setSelection2,
5194
- FOCUS_COMMAND
5195
- } from "lexical";
5196
- import { useEffect as useEffect8 } from "react";
5197
5287
  var COMMAND_PRIORITY_LOW3 = 1;
5198
5288
  var TAB_TO_FOCUS_INTERVAL = 100;
5199
5289
  var lastTabKeyDownTimestamp = 0;
@@ -5211,7 +5301,7 @@ function registerKeyTimeStampTracker() {
5211
5301
  }
5212
5302
  function TabFocusPlugin() {
5213
5303
  const [editor] = useLexicalComposerContext8();
5214
- useEffect8(() => {
5304
+ useEffect9(() => {
5215
5305
  if (!hasRegisteredKeyDownListener) {
5216
5306
  registerKeyTimeStampTracker();
5217
5307
  hasRegisteredKeyDownListener = true;
@@ -5234,7 +5324,7 @@ function TabFocusPlugin() {
5234
5324
  }
5235
5325
 
5236
5326
  // src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx
5237
- import { useCallback as useCallback3, useEffect as useEffect9, useRef as useRef4, useState as useState7 } from "react";
5327
+ import { useCallback as useCallback3, useEffect as useEffect10, useRef as useRef4, useState as useState8 } from "react";
5238
5328
  import { $getRoot as $getRoot3, $getSelection as $getSelection8, $isRangeSelection as $isRangeSelection6, DEPRECATED_$isGridSelection } from "lexical";
5239
5329
  import { createPortal as createPortal4 } from "react-dom";
5240
5330
  import { useLexicalComposerContext as useLexicalComposerContext9 } from "@lexical/react/LexicalComposerContext";
@@ -5256,15 +5346,16 @@ import {
5256
5346
  TableCellHeaderStates,
5257
5347
  TableCellNode as TableCellNode2
5258
5348
  } from "@lexical/table";
5259
- import { Fragment as Fragment6, jsx as jsx85, jsxs as jsxs63 } from "react/jsx-runtime";
5349
+ import { Fragment as Fragment6, jsx as jsx86, jsxs as jsxs63 } from "react/jsx-runtime";
5260
5350
  function TableActionMenu({ tableCellNode: _tableCellNode, tableStats }) {
5261
5351
  const [editor] = useLexicalComposerContext9();
5262
- const [tableCellNode, updateTableCellNode] = useState7(_tableCellNode);
5263
- const [selectionCounts, updateSelectionCounts] = useState7({
5352
+ const [tableCellNode, updateTableCellNode] = useState8(_tableCellNode);
5353
+ const [selectionCounts, updateSelectionCounts] = useState8({
5264
5354
  columns: 1,
5265
5355
  rows: 1
5266
5356
  });
5267
- useEffect9(() => {
5357
+ const tr = useTr();
5358
+ useEffect10(() => {
5268
5359
  return editor.registerMutationListener(TableCellNode2, (nodeMutations) => {
5269
5360
  const nodeUpdated = nodeMutations.get(tableCellNode.getKey()) === "updated";
5270
5361
  if (nodeUpdated) {
@@ -5274,7 +5365,7 @@ function TableActionMenu({ tableCellNode: _tableCellNode, tableStats }) {
5274
5365
  }
5275
5366
  });
5276
5367
  }, [editor, tableCellNode]);
5277
- useEffect9(() => {
5368
+ useEffect10(() => {
5278
5369
  editor.getEditorState().read(() => {
5279
5370
  const selection = $getSelection8();
5280
5371
  if (DEPRECATED_$isGridSelection(selection)) {
@@ -5412,75 +5503,57 @@ function TableActionMenu({ tableCellNode: _tableCellNode, tableStats }) {
5412
5503
  }, [editor, tableCellNode, clearTableSelection]);
5413
5504
  return /* @__PURE__ */ jsxs63(Fragment6, {
5414
5505
  children: [
5415
- /* @__PURE__ */ jsxs63(DropdownMenu.Item, {
5506
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5416
5507
  onSelect: () => insertTableRowAtSelection(false),
5417
- children: [
5418
- "Insert ",
5419
- selectionCounts.rows === 1 ? "row" : `${selectionCounts.rows} rows`,
5420
- " above"
5421
- ]
5508
+ children: tr("actionTableInsertRowsAbove", selectionCounts.rows)
5422
5509
  }),
5423
- /* @__PURE__ */ jsxs63(DropdownMenu.Item, {
5510
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5424
5511
  onSelect: () => insertTableRowAtSelection(true),
5425
- children: [
5426
- "Insert ",
5427
- selectionCounts.rows === 1 ? "row" : `${selectionCounts.rows} rows`,
5428
- " below"
5429
- ]
5512
+ children: tr("actionTableInsertRowsBelow", selectionCounts.rows)
5430
5513
  }),
5431
- /* @__PURE__ */ jsxs63(DropdownMenu.Item, {
5514
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5432
5515
  onSelect: () => insertTableColumnAtSelection(false),
5433
- children: [
5434
- "Insert ",
5435
- selectionCounts.columns === 1 ? "column" : `${selectionCounts.columns} columns`,
5436
- " left"
5437
- ]
5516
+ children: tr("actionTableInsertColumnsBefore", selectionCounts.columns)
5438
5517
  }),
5439
- /* @__PURE__ */ jsxs63(DropdownMenu.Item, {
5518
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5440
5519
  onSelect: () => insertTableColumnAtSelection(true),
5441
- children: [
5442
- "Insert ",
5443
- selectionCounts.columns === 1 ? "column" : `${selectionCounts.columns} columns`,
5444
- " right"
5445
- ]
5520
+ children: tr("actionTableInsertColumnsAfter", selectionCounts.columns)
5446
5521
  }),
5447
- /* @__PURE__ */ jsxs63(DropdownMenu.Item, {
5522
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5448
5523
  onSelect: () => toggleTableRowIsHeader(),
5449
- children: [
5450
- (tableCellNode.__headerState & TableCellHeaderStates.ROW) === TableCellHeaderStates.ROW ? "Remove" : "Add",
5451
- " row header"
5452
- ]
5524
+ children: tr(
5525
+ (tableCellNode.__headerState & TableCellHeaderStates.ROW) === TableCellHeaderStates.ROW ? "actionTableRemoveRowHeader" : "actionTableAddRowHeader"
5526
+ )
5453
5527
  }),
5454
- /* @__PURE__ */ jsxs63(DropdownMenu.Item, {
5528
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5455
5529
  onSelect: () => toggleTableColumnIsHeader(),
5456
- children: [
5457
- (tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN ? "Remove" : "Add",
5458
- " ",
5459
- "column header"
5460
- ]
5530
+ children: tr(
5531
+ (tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN ? "actionTableRemoveColumnHeader" : "actionTableAddColumnHeader"
5532
+ )
5461
5533
  }),
5462
- /* @__PURE__ */ jsx85(DropdownMenu.Separator, {}),
5463
- tableStats.columns > 1 && /* @__PURE__ */ jsx85(DropdownMenu.Item, {
5534
+ /* @__PURE__ */ jsx86(DropdownMenu.Separator, {}),
5535
+ tableStats.columns > 1 && /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5464
5536
  onSelect: () => deleteTableColumnAtSelection(),
5465
- children: "Delete column"
5537
+ children: tr("actionTableDeleteColumn")
5466
5538
  }),
5467
- tableStats.rows > 1 && /* @__PURE__ */ jsx85(DropdownMenu.Item, {
5539
+ tableStats.rows > 1 && /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5468
5540
  onSelect: () => deleteTableRowAtSelection(),
5469
- children: "Delete row"
5541
+ children: tr("actionTableDeleteRow")
5470
5542
  }),
5471
- /* @__PURE__ */ jsx85(DropdownMenu.Item, {
5543
+ /* @__PURE__ */ jsx86(DropdownMenu.Item, {
5472
5544
  onSelect: () => deleteTableAtSelection(),
5473
- children: "Delete table"
5545
+ children: tr("actionTableDeleteTable")
5474
5546
  })
5475
5547
  ]
5476
5548
  });
5477
5549
  }
5478
5550
  function TableCellActionMenuContainer({ anchorElem }) {
5479
5551
  const [editor] = useLexicalComposerContext9();
5552
+ const tr = useTr();
5480
5553
  const menuButtonRef = useRef4(null);
5481
- const [isMenuOpen, setIsMenuOpen] = useState7(false);
5482
- const [tableCellNode, setTableMenuCellNode] = useState7(null);
5483
- const [tableStats, setTablestats] = useState7({ rows: 1, columns: 1 });
5554
+ const [isMenuOpen, setIsMenuOpen] = useState8(false);
5555
+ const [tableCellNode, setTableMenuCellNode] = useState8(null);
5556
+ const [tableStats, setTablestats] = useState8({ rows: 1, columns: 1 });
5484
5557
  const moveMenu = useCallback3(() => {
5485
5558
  if (isMenuOpen) {
5486
5559
  return;
@@ -5524,14 +5597,14 @@ function TableCellActionMenuContainer({ anchorElem }) {
5524
5597
  setTableMenuCellNode(null);
5525
5598
  }
5526
5599
  }, [editor, isMenuOpen]);
5527
- useEffect9(() => {
5600
+ useEffect10(() => {
5528
5601
  return editor.registerUpdateListener(() => {
5529
5602
  editor.getEditorState().read(() => {
5530
5603
  moveMenu();
5531
5604
  });
5532
5605
  });
5533
5606
  });
5534
- useEffect9(() => {
5607
+ useEffect10(() => {
5535
5608
  const menuButtonDOM = menuButtonRef.current;
5536
5609
  if (menuButtonDOM != null && tableCellNode != null) {
5537
5610
  const tableCellNodeDOM = editor.getElementByKey(tableCellNode.getKey());
@@ -5549,19 +5622,20 @@ function TableCellActionMenuContainer({ anchorElem }) {
5549
5622
  }
5550
5623
  }
5551
5624
  }, [menuButtonRef, tableCellNode, editor, anchorElem]);
5552
- return /* @__PURE__ */ jsx85("div", {
5625
+ return /* @__PURE__ */ jsx86("div", {
5553
5626
  className: "table-cell-action-button-container",
5554
5627
  ref: menuButtonRef,
5555
- children: tableCellNode != null && /* @__PURE__ */ jsx85(DropdownMenu.Root, {
5628
+ children: tableCellNode != null && /* @__PURE__ */ jsx86(DropdownMenu.Root, {
5556
5629
  onOpenChange: (isOpen) => setIsMenuOpen(isOpen),
5557
- content: /* @__PURE__ */ jsx85(TableActionMenu, {
5630
+ content: /* @__PURE__ */ jsx86(TableActionMenu, {
5558
5631
  tableCellNode,
5559
5632
  tableStats
5560
5633
  }),
5561
- children: /* @__PURE__ */ jsx85(IconButton, {
5634
+ children: /* @__PURE__ */ jsx86(IconButton, {
5562
5635
  size: "xs",
5563
5636
  className: "table-cell-action-button",
5564
- children: /* @__PURE__ */ jsx85(Icon.Arrow, {})
5637
+ "aria-label": tr("actionTableOpenOptions"),
5638
+ children: /* @__PURE__ */ jsx86(Icon.Arrow, {})
5565
5639
  })
5566
5640
  })
5567
5641
  });
@@ -5570,13 +5644,13 @@ function TableActionMenuPlugin({
5570
5644
  anchorElem = document.body
5571
5645
  }) {
5572
5646
  const isEditable = useLexicalEditable();
5573
- return createPortal4(isEditable ? /* @__PURE__ */ jsx85(TableCellActionMenuContainer, {
5647
+ return createPortal4(isEditable ? /* @__PURE__ */ jsx86(TableCellActionMenuContainer, {
5574
5648
  anchorElem
5575
5649
  }) : null, anchorElem);
5576
5650
  }
5577
5651
 
5578
5652
  // src/rich-text-editor/plugins/ToolbarPlugin/index.tsx
5579
- import { useCallback as useCallback4, useEffect as useEffect10, useState as useState9 } from "react";
5653
+ import { useCallback as useCallback4, useEffect as useEffect11, useState as useState10 } from "react";
5580
5654
  import {
5581
5655
  $createParagraphNode as $createParagraphNode2,
5582
5656
  $getNodeByKey,
@@ -5584,7 +5658,7 @@ import {
5584
5658
  $getSelection as $getSelection9,
5585
5659
  $isRangeSelection as $isRangeSelection7,
5586
5660
  $isRootOrShadowRoot,
5587
- $isTextNode as $isTextNode4,
5661
+ $isTextNode as $isTextNode5,
5588
5662
  CAN_REDO_COMMAND,
5589
5663
  CAN_UNDO_COMMAND,
5590
5664
  COMMAND_PRIORITY_CRITICAL as COMMAND_PRIORITY_CRITICAL3,
@@ -5621,13 +5695,10 @@ import {
5621
5695
  mergeRegister as mergeRegister3
5622
5696
  } from "@lexical/utils";
5623
5697
 
5624
- // src/rich-text-editor/utils/environment.ts
5625
- var IS_APPLE = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
5626
-
5627
5698
  // src/rich-text-editor/plugins/ActionsPlugin/index.tsx
5628
5699
  import { CLEAR_EDITOR_COMMAND } from "lexical";
5629
5700
  import { useLexicalComposerContext as useLexicalComposerContext10 } from "@lexical/react/LexicalComposerContext";
5630
- import { jsx as jsx86, jsxs as jsxs64 } from "react/jsx-runtime";
5701
+ import { jsx as jsx87, jsxs as jsxs64 } from "react/jsx-runtime";
5631
5702
  async function copyJson(editor) {
5632
5703
  const json = lexicalToCrystallizeRichText({ editor, editorState: editor.getEditorState() });
5633
5704
  try {
@@ -5636,53 +5707,36 @@ async function copyJson(editor) {
5636
5707
  console.warn("Copy failed", error);
5637
5708
  }
5638
5709
  }
5639
- async function exportJson(editor) {
5640
- const json = lexicalToCrystallizeRichText({ editorState: editor.getEditorState() });
5641
- const blob = new Blob([JSON.stringify(json, null, 1)], {
5642
- type: "application/json"
5643
- });
5644
- const href = URL.createObjectURL(blob);
5645
- const link = document.createElement("a");
5646
- link.href = href;
5647
- link.download = "crystallizeRichText.json";
5648
- document.body.appendChild(link);
5649
- link.click();
5650
- document.body.removeChild(link);
5651
- URL.revokeObjectURL(href);
5652
- }
5653
5710
  function ActionsPlugin({
5654
5711
  append,
5655
5712
  prepend
5656
5713
  }) {
5657
5714
  const [editor] = useLexicalComposerContext10();
5715
+ const tr = useTr();
5658
5716
  return /* @__PURE__ */ jsxs64("div", {
5659
5717
  className: "z-50 flex items-center ",
5660
5718
  children: [
5661
- /* @__PURE__ */ jsx86("div", {}),
5719
+ /* @__PURE__ */ jsx87("div", {}),
5662
5720
  /* @__PURE__ */ jsxs64(ActionMenu, {
5663
5721
  children: [
5664
- !prepend ? null : prepend.map((actionItem) => /* @__PURE__ */ jsx86(ActionMenu.Item, {
5722
+ !prepend ? null : prepend.map((actionItem) => /* @__PURE__ */ jsx87(ActionMenu.Item, {
5665
5723
  onSelect: actionItem.action,
5666
5724
  className: actionItem.type === "danger" ? "danger" : "",
5667
5725
  children: actionItem.title
5668
5726
  }, actionItem.title)),
5669
- /* @__PURE__ */ jsx86(ActionMenu.Item, {
5727
+ /* @__PURE__ */ jsx87(ActionMenu.Item, {
5670
5728
  onSelect: () => copyJson(editor),
5671
- children: "Copy JSON"
5729
+ children: tr("actionCopyJSON")
5672
5730
  }),
5673
- /* @__PURE__ */ jsx86(ActionMenu.Item, {
5674
- onSelect: () => exportJson(editor),
5675
- children: "Export JSON"
5676
- }),
5677
- /* @__PURE__ */ jsx86(ActionMenu.Item, {
5731
+ /* @__PURE__ */ jsx87(ActionMenu.Item, {
5678
5732
  className: "danger",
5679
5733
  onSelect: () => {
5680
5734
  editor.dispatchCommand(CLEAR_EDITOR_COMMAND, void 0);
5681
5735
  editor.focus();
5682
5736
  },
5683
- children: "Clear paragraph"
5737
+ children: tr("actionClear")
5684
5738
  }),
5685
- !append ? null : append.map((actionItem) => /* @__PURE__ */ jsx86(ActionMenu.Item, {
5739
+ !append ? null : append.map((actionItem) => /* @__PURE__ */ jsx87(ActionMenu.Item, {
5686
5740
  onSelect: actionItem.action,
5687
5741
  className: actionItem.type === "danger" ? "danger" : "",
5688
5742
  children: actionItem.title
@@ -5694,12 +5748,13 @@ function ActionsPlugin({
5694
5748
  }
5695
5749
 
5696
5750
  // src/rich-text-editor/plugins/ToolbarPlugin/insert-table.tsx
5697
- import { useState as useState8 } from "react";
5751
+ import { useState as useState9 } from "react";
5698
5752
  import { INSERT_TABLE_COMMAND } from "@lexical/table";
5699
- import { Fragment as Fragment7, jsx as jsx87, jsxs as jsxs65 } from "react/jsx-runtime";
5753
+ import { Fragment as Fragment7, jsx as jsx88, jsxs as jsxs65 } from "react/jsx-runtime";
5700
5754
  function InsertTableDialog({ activeEditor }) {
5701
- const [rows, setRows] = useState8("5");
5702
- const [columns, setColumns] = useState8("5");
5755
+ const [rows, setRows] = useState9("5");
5756
+ const [columns, setColumns] = useState9("5");
5757
+ const tr = useTr();
5703
5758
  const onClick = () => {
5704
5759
  if (parseInt(rows) < 1 || parseInt(columns) < 1) {
5705
5760
  return;
@@ -5718,20 +5773,20 @@ function InsertTableDialog({ activeEditor }) {
5718
5773
  /* @__PURE__ */ jsxs65("div", {
5719
5774
  className: "grid grid-cols-[1fr_1px_1fr] border border-gray-100-800 border-solid shadow-sm rounded-md ",
5720
5775
  children: [
5721
- /* @__PURE__ */ jsx87(InputWithLabel, {
5722
- label: "Rows",
5776
+ /* @__PURE__ */ jsx88(InputWithLabel, {
5777
+ label: tr("insertTableRows"),
5723
5778
  value: rows,
5724
5779
  placeholder: "0",
5725
5780
  type: "text",
5726
5781
  inputMode: "numeric",
5727
5782
  onChange: (e) => setRows(e.target.value)
5728
5783
  }),
5729
- /* @__PURE__ */ jsx87("span", {
5784
+ /* @__PURE__ */ jsx88("span", {
5730
5785
  className: "h-full bg-gray-100-800"
5731
5786
  }),
5732
- /* @__PURE__ */ jsx87(InputWithLabel, {
5787
+ /* @__PURE__ */ jsx88(InputWithLabel, {
5733
5788
  type: "text",
5734
- label: "Columns",
5789
+ label: tr("insertTableColumns"),
5735
5790
  placeholder: "0",
5736
5791
  value: columns,
5737
5792
  inputMode: "numeric",
@@ -5739,15 +5794,15 @@ function InsertTableDialog({ activeEditor }) {
5739
5794
  })
5740
5795
  ]
5741
5796
  }),
5742
- /* @__PURE__ */ jsx87("div", {
5797
+ /* @__PURE__ */ jsx88("div", {
5743
5798
  className: "flex justify-end mt-3",
5744
- children: /* @__PURE__ */ jsx87(Button, {
5799
+ children: /* @__PURE__ */ jsx88(Button, {
5745
5800
  as: Dialog.Close,
5746
5801
  size: "sm",
5747
5802
  intent: "action",
5748
- "aria-label": "Confirm",
5803
+ "aria-label": tr("insertTableCommit"),
5749
5804
  onClick,
5750
- children: "Confirm"
5805
+ children: tr("insertTableCommit")
5751
5806
  })
5752
5807
  })
5753
5808
  ]
@@ -5755,7 +5810,7 @@ function InsertTableDialog({ activeEditor }) {
5755
5810
  }
5756
5811
 
5757
5812
  // src/rich-text-editor/plugins/ToolbarPlugin/index.tsx
5758
- import { Fragment as Fragment8, jsx as jsx88, jsxs as jsxs66 } from "react/jsx-runtime";
5813
+ import { Fragment as Fragment8, jsx as jsx89, jsxs as jsxs66 } from "react/jsx-runtime";
5759
5814
  var headingTypeToBlockName = {
5760
5815
  h1: "Heading 1",
5761
5816
  h2: "Heading 2",
@@ -5859,7 +5914,7 @@ function BlockFormatDropDown({
5859
5914
  });
5860
5915
  }
5861
5916
  };
5862
- return /* @__PURE__ */ jsx88(DropdownMenu.Root, {
5917
+ return /* @__PURE__ */ jsx89(DropdownMenu.Root, {
5863
5918
  disabled,
5864
5919
  style: { zIndex: 1 },
5865
5920
  content: /* @__PURE__ */ jsxs66(Fragment8, {
@@ -5867,13 +5922,13 @@ function BlockFormatDropDown({
5867
5922
  /* @__PURE__ */ jsxs66(DropdownMenu.Item, {
5868
5923
  onClick: formatParagraph,
5869
5924
  children: [
5870
- /* @__PURE__ */ jsx88("i", {
5925
+ /* @__PURE__ */ jsx89("i", {
5871
5926
  className: `icon paragraph border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${blockType === "paragraph" ? "opacity-100 bg-purple-50-900" : "opacity-60"}`
5872
5927
  }),
5873
- /* @__PURE__ */ jsx88("i", {
5928
+ /* @__PURE__ */ jsx89("i", {
5874
5929
  className: "icon paragraph"
5875
5930
  }),
5876
- /* @__PURE__ */ jsx88("span", {
5931
+ /* @__PURE__ */ jsx89("span", {
5877
5932
  className: `${blockType === "paragraph" ? "font-bold" : "font-normal"} text-sm px-3 min-w-[150px]`,
5878
5933
  children: "Normal"
5879
5934
  })
@@ -5882,10 +5937,10 @@ function BlockFormatDropDown({
5882
5937
  headings.map((headingSize) => /* @__PURE__ */ jsxs66(DropdownMenu.Item, {
5883
5938
  onClick: () => formatHeading(headingSize),
5884
5939
  children: [
5885
- /* @__PURE__ */ jsx88("i", {
5940
+ /* @__PURE__ */ jsx89("i", {
5886
5941
  className: `icon ${headingSize} border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${blockType === headingSize ? "opacity-100 bg-purple-50-900" : "opacity-60"}`
5887
5942
  }),
5888
- /* @__PURE__ */ jsx88("span", {
5943
+ /* @__PURE__ */ jsx89("span", {
5889
5944
  className: `${blockType === headingSize ? "font-bold" : "font-normal"} text-sm px-3 min-w-[150px]`,
5890
5945
  children: headingTypeToBlockName[headingSize]
5891
5946
  })
@@ -5894,10 +5949,10 @@ function BlockFormatDropDown({
5894
5949
  /* @__PURE__ */ jsxs66(DropdownMenu.Item, {
5895
5950
  onClick: formatBulletList,
5896
5951
  children: [
5897
- /* @__PURE__ */ jsx88("i", {
5952
+ /* @__PURE__ */ jsx89("i", {
5898
5953
  className: `icon bullet-list border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${blockType === "bullet" ? "opacity-100 bg-purple-50-900" : "opacity-60"}`
5899
5954
  }),
5900
- /* @__PURE__ */ jsx88("span", {
5955
+ /* @__PURE__ */ jsx89("span", {
5901
5956
  className: `${blockType === "bullet" ? "font-bold" : "font-normal"} text-sm px-3 min-w-[150px]`,
5902
5957
  children: "Bullet List"
5903
5958
  })
@@ -5906,10 +5961,10 @@ function BlockFormatDropDown({
5906
5961
  /* @__PURE__ */ jsxs66(DropdownMenu.Item, {
5907
5962
  onClick: formatNumberedList,
5908
5963
  children: [
5909
- /* @__PURE__ */ jsx88("i", {
5964
+ /* @__PURE__ */ jsx89("i", {
5910
5965
  className: `icon numbered-list border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${blockType === "number" ? "opacity-100 bg-purple-50-900" : "opacity-60"}`
5911
5966
  }),
5912
- /* @__PURE__ */ jsx88("span", {
5967
+ /* @__PURE__ */ jsx89("span", {
5913
5968
  className: `${blockType === "number" ? "font-bold" : "font-normal"} text-sm px-3 min-w-[150px]`,
5914
5969
  children: "Numbered List"
5915
5970
  })
@@ -5919,10 +5974,10 @@ function BlockFormatDropDown({
5919
5974
  onClick: formatQuote,
5920
5975
  "data-testid": "toggle-block-format-quote",
5921
5976
  children: [
5922
- /* @__PURE__ */ jsx88("i", {
5977
+ /* @__PURE__ */ jsx89("i", {
5923
5978
  className: `icon quote border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${blockType === "quote" ? "opacity-100 bg-purple-50-900" : "opacity-60"}`
5924
5979
  }),
5925
- /* @__PURE__ */ jsx88("span", {
5980
+ /* @__PURE__ */ jsx89("span", {
5926
5981
  className: `${blockType === "quote" ? "font-bold" : "font-normal"} text-sm px-3 min-w-[150px]`,
5927
5982
  children: "Quote"
5928
5983
  })
@@ -5932,10 +5987,10 @@ function BlockFormatDropDown({
5932
5987
  onClick: formatCode,
5933
5988
  "data-testid": "toggle-block-format-code",
5934
5989
  children: [
5935
- /* @__PURE__ */ jsx88("i", {
5990
+ /* @__PURE__ */ jsx89("i", {
5936
5991
  className: `icon code border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${blockType === "code" ? "opacity-100 bg-purple-50-900" : "opacity-60"}`
5937
5992
  }),
5938
- /* @__PURE__ */ jsx88("span", {
5993
+ /* @__PURE__ */ jsx89("span", {
5939
5994
  className: `${blockType === "code" ? "font-bold" : "font-normal"} text-sm px-3 min-w-[150px]`,
5940
5995
  children: "Code block"
5941
5996
  })
@@ -5948,16 +6003,16 @@ function BlockFormatDropDown({
5948
6003
  "aria-label": "Formatting options for text style",
5949
6004
  "data-testid": "toggle-block-format",
5950
6005
  children: [
5951
- /* @__PURE__ */ jsx88("i", {
6006
+ /* @__PURE__ */ jsx89("i", {
5952
6007
  className: `icon ${blockType} border bg-no-repeat bg-center bg-[length:18px_18px] w-6 h-6`
5953
6008
  }),
5954
- /* @__PURE__ */ jsx88(Icon.Arrow, {})
6009
+ /* @__PURE__ */ jsx89(Icon.Arrow, {})
5955
6010
  ]
5956
6011
  })
5957
6012
  });
5958
6013
  }
5959
6014
  function Divider() {
5960
- return /* @__PURE__ */ jsx88("div", {
6015
+ return /* @__PURE__ */ jsx89("div", {
5961
6016
  className: "divider"
5962
6017
  });
5963
6018
  }
@@ -5966,21 +6021,22 @@ function ToolbarPlugin({
5966
6021
  actionsMenuAppend
5967
6022
  }) {
5968
6023
  const [editor] = useLexicalComposerContext11();
5969
- const [activeEditor, setActiveEditor] = useState9(editor);
5970
- const [blockType, setBlockType] = useState9("paragraph");
5971
- const [selectedElementKey, setSelectedElementKey] = useState9(null);
5972
- const [isLink, setIsLink] = useState9(false);
5973
- const [isBold, setIsBold] = useState9(false);
5974
- const [isItalic, setIsItalic] = useState9(false);
5975
- const [isUnderline, setIsUnderline] = useState9(false);
5976
- const [isStrikethrough, setIsStrikethrough] = useState9(false);
5977
- const [isSubscript, setIsSubscript] = useState9(false);
5978
- const [isSuperscript, setIsSuperscript] = useState9(false);
5979
- const [isCode, setIsCode] = useState9(false);
5980
- const [canUndo, setCanUndo] = useState9(false);
5981
- const [canRedo, setCanRedo] = useState9(false);
5982
- const [codeLanguage, setCodeLanguage] = useState9("");
5983
- const [isEditable, setIsEditable] = useState9(() => editor.isEditable());
6024
+ const [activeEditor, setActiveEditor] = useState10(editor);
6025
+ const [blockType, setBlockType] = useState10("paragraph");
6026
+ const [selectedElementKey, setSelectedElementKey] = useState10(null);
6027
+ const [isLink, setIsLink] = useState10(false);
6028
+ const [isBold, setIsBold] = useState10(false);
6029
+ const [isItalic, setIsItalic] = useState10(false);
6030
+ const [isUnderline, setIsUnderline] = useState10(false);
6031
+ const [isStrikethrough, setIsStrikethrough] = useState10(false);
6032
+ const [isSubscript, setIsSubscript] = useState10(false);
6033
+ const [isSuperscript, setIsSuperscript] = useState10(false);
6034
+ const [isCode, setIsCode] = useState10(false);
6035
+ const [canUndo, setCanUndo] = useState10(false);
6036
+ const [canRedo, setCanRedo] = useState10(false);
6037
+ const tr = useTr();
6038
+ const [codeLanguage, setCodeLanguage] = useState10("");
6039
+ const [isEditable, setIsEditable] = useState10(() => editor.isEditable());
5984
6040
  const updateToolbar = useCallback4(() => {
5985
6041
  const selection = $getSelection9();
5986
6042
  if ($isRangeSelection7(selection)) {
@@ -6028,7 +6084,7 @@ function ToolbarPlugin({
6028
6084
  }
6029
6085
  }
6030
6086
  }, [activeEditor]);
6031
- useEffect10(() => {
6087
+ useEffect11(() => {
6032
6088
  return editor.registerCommand(
6033
6089
  SELECTION_CHANGE_COMMAND3,
6034
6090
  (_payload, newEditor) => {
@@ -6039,7 +6095,7 @@ function ToolbarPlugin({
6039
6095
  COMMAND_PRIORITY_CRITICAL3
6040
6096
  );
6041
6097
  }, [editor, updateToolbar]);
6042
- useEffect10(() => {
6098
+ useEffect11(() => {
6043
6099
  return mergeRegister3(
6044
6100
  editor.registerEditableListener((editable) => {
6045
6101
  setIsEditable(editable);
@@ -6073,7 +6129,7 @@ function ToolbarPlugin({
6073
6129
  if ($isRangeSelection7(selection)) {
6074
6130
  $selectAll(selection);
6075
6131
  selection.getNodes().forEach((node) => {
6076
- if ($isTextNode4(node)) {
6132
+ if ($isTextNode5(node)) {
6077
6133
  node.setFormat(0);
6078
6134
  node.setStyle("");
6079
6135
  $getNearestBlockElementAncestorOrThrow(node).setFormat("");
@@ -6111,138 +6167,138 @@ function ToolbarPlugin({
6111
6167
  /* @__PURE__ */ jsxs66("div", {
6112
6168
  className: "flex",
6113
6169
  children: [
6114
- /* @__PURE__ */ jsx88(IconButton, {
6170
+ /* @__PURE__ */ jsx89(IconButton, {
6115
6171
  disabled: !canUndo || !isEditable,
6116
6172
  onClick: () => {
6117
6173
  activeEditor.dispatchCommand(UNDO_COMMAND, void 0);
6118
6174
  },
6119
- title: IS_APPLE ? "Undo (\u2318Z)" : "Undo (Ctrl+Z)",
6120
6175
  type: "button",
6121
- "aria-label": "Undo",
6122
- children: /* @__PURE__ */ jsx88("i", {
6176
+ title: tr(IS_APPLE ? "actionUndoTitleApple" : "actionUndoTitle"),
6177
+ "aria-label": tr("actionUndoLabel"),
6178
+ children: /* @__PURE__ */ jsx89("i", {
6123
6179
  className: `format icon undo border w-4 h-6 bg-no-repeat bg-center bg-[length:17px_17px] ${canUndo ? "opacity-100" : "opacity-30"}
6124
6180
  `
6125
6181
  })
6126
6182
  }),
6127
- /* @__PURE__ */ jsx88(IconButton, {
6183
+ /* @__PURE__ */ jsx89(IconButton, {
6128
6184
  disabled: !canRedo || !isEditable,
6129
6185
  onClick: () => {
6130
6186
  activeEditor.dispatchCommand(REDO_COMMAND, void 0);
6131
6187
  },
6132
- title: IS_APPLE ? "Redo (\u2318Y)" : "Redo (Ctrl+Y)",
6133
6188
  type: "button",
6134
- "aria-label": "Redo",
6135
- children: /* @__PURE__ */ jsx88("i", {
6189
+ title: tr(IS_APPLE ? "actionRedoTitleApple" : "actionRedoTitle"),
6190
+ "aria-label": tr("actionRedoLabel"),
6191
+ children: /* @__PURE__ */ jsx89("i", {
6136
6192
  className: `format icon redo border w-4 h-6 bg-no-repeat bg-center bg-[length:17px_17px] ${canRedo ? "opacity-100" : "opacity-30"}`
6137
6193
  })
6138
6194
  }),
6139
- /* @__PURE__ */ jsx88(Divider, {}),
6195
+ /* @__PURE__ */ jsx89(Divider, {}),
6140
6196
  blockType in blockTypeToBlockName && activeEditor === editor && /* @__PURE__ */ jsxs66(Fragment8, {
6141
6197
  children: [
6142
- /* @__PURE__ */ jsx88(BlockFormatDropDown, {
6198
+ /* @__PURE__ */ jsx89(BlockFormatDropDown, {
6143
6199
  disabled: !isEditable,
6144
6200
  blockType,
6145
6201
  editor
6146
6202
  }),
6147
- /* @__PURE__ */ jsx88(Divider, {})
6203
+ /* @__PURE__ */ jsx89(Divider, {})
6148
6204
  ]
6149
6205
  }),
6150
- blockType === "code" ? /* @__PURE__ */ jsx88(Fragment8, {
6151
- children: /* @__PURE__ */ jsx88(DropdownMenu.Root, {
6206
+ blockType === "code" ? /* @__PURE__ */ jsx89(Fragment8, {
6207
+ children: /* @__PURE__ */ jsx89(DropdownMenu.Root, {
6152
6208
  disabled: !isEditable,
6153
6209
  style: { zIndex: 1 },
6154
- content: /* @__PURE__ */ jsx88(Fragment8, {
6210
+ content: /* @__PURE__ */ jsx89(Fragment8, {
6155
6211
  children: CODE_LANGUAGE_OPTIONS.map(([value, name]) => {
6156
- return /* @__PURE__ */ jsx88(DropdownMenu.Item, {
6212
+ return /* @__PURE__ */ jsx89(DropdownMenu.Item, {
6157
6213
  className: `item ${dropDownActiveClass(value === codeLanguage)}`,
6158
6214
  onClick: () => onCodeLanguageSelect(value),
6159
- children: /* @__PURE__ */ jsx88("span", {
6215
+ children: /* @__PURE__ */ jsx89("span", {
6160
6216
  className: `text min-w-[200px] block text-sm px-3 ${dropDownActiveClass(value === codeLanguage) ? "font-bold opacity-100" : "font-normal opacity-80"}`,
6161
6217
  children: name
6162
6218
  })
6163
6219
  }, value);
6164
6220
  })
6165
6221
  }),
6166
- children: /* @__PURE__ */ jsx88(Button, {
6167
- "aria-label": "Select language",
6168
- append: /* @__PURE__ */ jsx88(Icon.Arrow, {}),
6169
- children: /* @__PURE__ */ jsx88("span", {
6222
+ children: /* @__PURE__ */ jsx89(Button, {
6223
+ "aria-label": tr("codeSelectLanguage"),
6224
+ append: /* @__PURE__ */ jsx89(Icon.Arrow, {}),
6225
+ children: /* @__PURE__ */ jsx89("span", {
6170
6226
  className: "font-medium text-sm",
6171
6227
  children: getLanguageFriendlyName2(codeLanguage)
6172
6228
  })
6173
6229
  })
6174
6230
  })
6175
- }) : /* @__PURE__ */ jsx88(Dialog, {
6231
+ }) : /* @__PURE__ */ jsx89(Dialog, {
6176
6232
  children: /* @__PURE__ */ jsxs66("div", {
6177
6233
  className: "flex gap-1",
6178
6234
  children: [
6179
- /* @__PURE__ */ jsx88(IconButton, {
6235
+ /* @__PURE__ */ jsx89(IconButton, {
6180
6236
  disabled: !isEditable,
6181
- title: IS_APPLE ? "Bold (\u2318B)" : "Bold (Ctrl+B)",
6182
6237
  className: `${isBold ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`,
6183
6238
  type: "button",
6184
- "aria-label": `Format text as bold. Shortcut: ${IS_APPLE ? "\u2318B" : "Ctrl+B"}`,
6239
+ title: tr(IS_APPLE ? "actionFormatAsStrongTitleApple" : "actionFormatAsStrongTitle"),
6240
+ "aria-label": tr("actionFormatAsStrongLabel"),
6185
6241
  "data-testid": "toggle-format-bold",
6186
6242
  onClick: () => {
6187
6243
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "bold");
6188
6244
  },
6189
- children: /* @__PURE__ */ jsx88("i", {
6245
+ children: /* @__PURE__ */ jsx89("i", {
6190
6246
  className: `format icon bold border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`
6191
6247
  })
6192
6248
  }),
6193
- /* @__PURE__ */ jsx88(IconButton, {
6249
+ /* @__PURE__ */ jsx89(IconButton, {
6194
6250
  className: `${isItalic ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`,
6195
6251
  disabled: !isEditable,
6196
6252
  onClick: () => {
6197
6253
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "italic");
6198
6254
  },
6199
- title: IS_APPLE ? "Italic (\u2318I)" : "Italic (Ctrl+I)",
6200
6255
  type: "button",
6201
- "aria-label": `Format text as italics. Shortcut: ${IS_APPLE ? "\u2318I" : "Ctrl+I"}`,
6256
+ title: tr(IS_APPLE ? "actionFormatAsEmphasizedTitleApple" : "actionFormatAsEmphasizedTitle"),
6257
+ "aria-label": tr("actionFormatAsEmphasizedLabel"),
6202
6258
  "data-testid": "toggle-format-emphasized",
6203
- children: /* @__PURE__ */ jsx88("i", {
6259
+ children: /* @__PURE__ */ jsx89("i", {
6204
6260
  className: `format icon italic border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`
6205
6261
  })
6206
6262
  }),
6207
- /* @__PURE__ */ jsx88(IconButton, {
6263
+ /* @__PURE__ */ jsx89(IconButton, {
6208
6264
  className: `${isUnderline ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`,
6209
6265
  disabled: !isEditable,
6210
6266
  onClick: () => {
6211
6267
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "underline");
6212
6268
  },
6213
- title: IS_APPLE ? "Underline (\u2318U)" : "Underline (Ctrl+U)",
6214
6269
  type: "button",
6215
- "aria-label": `Format text to underlined. Shortcut: ${IS_APPLE ? "\u2318U" : "Ctrl+U"}`,
6270
+ title: tr(IS_APPLE ? "actionFormatAsUnderlinedTitleApple" : "actionFormatAsUnderlinedTitle"),
6271
+ "aria-label": tr("actionFormatAsUnderlinedLabel"),
6216
6272
  "data-testid": "toggle-format-underlined",
6217
- children: /* @__PURE__ */ jsx88("i", {
6273
+ children: /* @__PURE__ */ jsx89("i", {
6218
6274
  className: `format icon underline border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`
6219
6275
  })
6220
6276
  }),
6221
- /* @__PURE__ */ jsx88(IconButton, {
6277
+ /* @__PURE__ */ jsx89(IconButton, {
6222
6278
  className: `${isCode ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`,
6223
6279
  disabled: !isEditable,
6224
6280
  onClick: () => {
6225
6281
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "code");
6226
6282
  },
6227
- title: "Insert code block",
6228
6283
  type: "button",
6229
- "aria-label": "Insert code block",
6230
- children: /* @__PURE__ */ jsx88("i", {
6284
+ title: tr("actionInsertCodeBlock"),
6285
+ "aria-label": tr("actionInsertCodeBlock"),
6286
+ children: /* @__PURE__ */ jsx89("i", {
6231
6287
  className: `format icon code border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`
6232
6288
  })
6233
6289
  }),
6234
- /* @__PURE__ */ jsx88(IconButton, {
6290
+ /* @__PURE__ */ jsx89(IconButton, {
6235
6291
  className: `${isLink ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`,
6236
6292
  disabled: !isEditable,
6237
6293
  onClick: insertLink,
6238
- "aria-label": "Insert link",
6239
- title: "Insert link",
6240
6294
  type: "button",
6241
- children: /* @__PURE__ */ jsx88("i", {
6295
+ "aria-label": tr("actionInsertlink"),
6296
+ title: tr("actionInsertlink"),
6297
+ children: /* @__PURE__ */ jsx89("i", {
6242
6298
  className: `format icon link border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`
6243
6299
  })
6244
6300
  }),
6245
- /* @__PURE__ */ jsx88(DropdownMenu.Root, {
6301
+ /* @__PURE__ */ jsx89(DropdownMenu.Root, {
6246
6302
  disabled: !isEditable,
6247
6303
  style: { zIndex: 1 },
6248
6304
  content: /* @__PURE__ */ jsxs66(Fragment8, {
@@ -6251,15 +6307,15 @@ function ToolbarPlugin({
6251
6307
  onClick: () => {
6252
6308
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "strikethrough");
6253
6309
  },
6254
- title: "Strikethrough",
6255
- "aria-label": "Format text with a strikethrough",
6310
+ title: tr("actionFormatWithStrikethroughTitle"),
6311
+ "aria-label": tr("actionFormatWithStrikethroughLabel"),
6256
6312
  children: [
6257
- /* @__PURE__ */ jsx88("i", {
6313
+ /* @__PURE__ */ jsx89("i", {
6258
6314
  className: `icon w-6 h-6 strikethrough border bg-no-repeat bg-center bg-[length:16px_16px] rounded-sm ${isStrikethrough ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`
6259
6315
  }),
6260
- /* @__PURE__ */ jsx88("span", {
6316
+ /* @__PURE__ */ jsx89("span", {
6261
6317
  className: `px-3 text-sm font-sans ${isStrikethrough ? "font-medium" : "font-normal"}`,
6262
- children: "Strikethrough"
6318
+ children: tr("actionFormatAsStrongTitle")
6263
6319
  })
6264
6320
  ]
6265
6321
  }),
@@ -6267,15 +6323,15 @@ function ToolbarPlugin({
6267
6323
  onClick: () => {
6268
6324
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "subscript");
6269
6325
  },
6270
- title: "Subscript",
6271
- "aria-label": "Format text with a subscript",
6326
+ title: tr("actionFormatWithSubscriptTitle"),
6327
+ "aria-label": tr("actionFormatWithSubscriptLabel"),
6272
6328
  children: [
6273
- /* @__PURE__ */ jsx88("i", {
6329
+ /* @__PURE__ */ jsx89("i", {
6274
6330
  className: `icon w-6 h-6 subscript border bg-no-repeat bg-center bg-[length:16px_16px] rounded-sm ${isSubscript ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`
6275
6331
  }),
6276
- /* @__PURE__ */ jsx88("span", {
6332
+ /* @__PURE__ */ jsx89("span", {
6277
6333
  className: `px-3 text-sm font-sans ${isSubscript ? "font-medium" : "font-normal"}`,
6278
- children: "Subscript"
6334
+ children: tr("actionFormatWithSubscriptTitle")
6279
6335
  })
6280
6336
  ]
6281
6337
  }),
@@ -6283,28 +6339,28 @@ function ToolbarPlugin({
6283
6339
  onClick: () => {
6284
6340
  activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND2, "superscript");
6285
6341
  },
6286
- title: "Superscript",
6287
- "aria-label": "Format text with a superscript",
6342
+ title: tr("actionFormatWithSuperscriptTitle"),
6343
+ "aria-label": tr("actionFormatWithSuperscriptLabel"),
6288
6344
  children: [
6289
- /* @__PURE__ */ jsx88("i", {
6345
+ /* @__PURE__ */ jsx89("i", {
6290
6346
  className: `icon w-6 h-6 superscript border bg-no-repeat bg-center bg-[length:16px_16px] rounded-sm ${isSuperscript ? "opacity-100 !bg-purple-50-900" : "opacity-60"}`
6291
6347
  }),
6292
- /* @__PURE__ */ jsx88("span", {
6348
+ /* @__PURE__ */ jsx89("span", {
6293
6349
  className: `px-3 text-sm font-sans ${isSuperscript ? "bg-purple-50-900" : "font-normal"}`,
6294
- children: "Superscript"
6350
+ children: tr("actionFormatWithSuperscriptTitle")
6295
6351
  })
6296
6352
  ]
6297
6353
  }),
6298
6354
  /* @__PURE__ */ jsxs66(DropdownMenu.Item, {
6299
6355
  onClick: clearFormatting,
6300
6356
  className: "item",
6301
- title: "Clear text formatting",
6302
- "aria-label": "Clear all text formatting",
6357
+ title: tr("actionClearTextFormatting"),
6358
+ "aria-label": tr("actionClearTextFormatting"),
6303
6359
  children: [
6304
- /* @__PURE__ */ jsx88("i", {
6360
+ /* @__PURE__ */ jsx89("i", {
6305
6361
  className: "icon w-6 h-6 clear border bg-no-repeat bg-center bg-[length:16px_16px] opacity-60"
6306
6362
  }),
6307
- /* @__PURE__ */ jsx88("span", {
6363
+ /* @__PURE__ */ jsx89("span", {
6308
6364
  className: "px-3 text-sm text-pink-600-300 font-sans font-normal",
6309
6365
  children: "Clear Formatting"
6310
6366
  })
@@ -6314,50 +6370,50 @@ function ToolbarPlugin({
6314
6370
  }),
6315
6371
  children: /* @__PURE__ */ jsxs66(Button, {
6316
6372
  style: { backgroundColor: "transparent", padding: "0 8px" },
6317
- "aria-label": "Formatting options for additional text styles",
6373
+ "aria-label": tr("actionTextFormattingOptions"),
6318
6374
  children: [
6319
- /* @__PURE__ */ jsx88("i", {
6375
+ /* @__PURE__ */ jsx89("i", {
6320
6376
  className: `icon dropdown-more border bg-no-repeat bg-center bg-[length:18px_18px] w-6 h-6`
6321
6377
  }),
6322
- /* @__PURE__ */ jsx88(Icon.Arrow, {})
6378
+ /* @__PURE__ */ jsx89(Icon.Arrow, {})
6323
6379
  ]
6324
6380
  })
6325
6381
  }),
6326
- /* @__PURE__ */ jsx88(Divider, {}),
6327
- /* @__PURE__ */ jsx88(DropdownMenu.Root, {
6382
+ /* @__PURE__ */ jsx89(Divider, {}),
6383
+ /* @__PURE__ */ jsx89(DropdownMenu.Root, {
6328
6384
  style: { zIndex: 1 },
6329
6385
  disabled: !isEditable,
6330
6386
  content: /* @__PURE__ */ jsxs66(Fragment8, {
6331
6387
  children: [
6332
- /* @__PURE__ */ jsx88(DropdownMenu.Item, {
6388
+ /* @__PURE__ */ jsx89(DropdownMenu.Item, {
6333
6389
  onClick: () => {
6334
6390
  activeEditor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, void 0);
6335
6391
  },
6336
6392
  children: /* @__PURE__ */ jsxs66("div", {
6337
6393
  className: "flex items-center font-sans font-normal",
6338
6394
  children: [
6339
- /* @__PURE__ */ jsx88("i", {
6395
+ /* @__PURE__ */ jsx89("i", {
6340
6396
  className: "icon w-5 h-5 horizontal-rule border bg-no-repeat bg-center bg-[length:16px_16px] opacity-60"
6341
6397
  }),
6342
- /* @__PURE__ */ jsx88("span", {
6398
+ /* @__PURE__ */ jsx89("span", {
6343
6399
  className: "px-3 text-sm",
6344
- children: "Horizontal rule"
6400
+ children: tr("horizontalRule")
6345
6401
  })
6346
6402
  ]
6347
6403
  })
6348
6404
  }),
6349
- /* @__PURE__ */ jsx88(DropdownMenu.Item, {
6350
- children: /* @__PURE__ */ jsx88(Dialog.Trigger, {
6405
+ /* @__PURE__ */ jsx89(DropdownMenu.Item, {
6406
+ children: /* @__PURE__ */ jsx89(Dialog.Trigger, {
6351
6407
  asChild: true,
6352
6408
  children: /* @__PURE__ */ jsxs66("div", {
6353
6409
  className: "flex items-center font-sans font-normal",
6354
6410
  children: [
6355
- /* @__PURE__ */ jsx88("i", {
6411
+ /* @__PURE__ */ jsx89("i", {
6356
6412
  className: "icon w-5 h-5 table border bg-no-repeat bg-center bg-[length:16px_16px] opacity-60"
6357
6413
  }),
6358
- /* @__PURE__ */ jsx88("span", {
6414
+ /* @__PURE__ */ jsx89("span", {
6359
6415
  className: "px-3 text-sm",
6360
- children: "Table"
6416
+ children: tr("table")
6361
6417
  })
6362
6418
  ]
6363
6419
  })
@@ -6365,23 +6421,23 @@ function ToolbarPlugin({
6365
6421
  })
6366
6422
  ]
6367
6423
  }),
6368
- children: /* @__PURE__ */ jsx88(IconButton, {
6369
- children: /* @__PURE__ */ jsx88("i", {
6424
+ children: /* @__PURE__ */ jsx89(IconButton, {
6425
+ children: /* @__PURE__ */ jsx89("i", {
6370
6426
  className: "icon plus border w-full h-full bg-no-repeat bg-center bg-[length:20px_20px] "
6371
6427
  })
6372
6428
  })
6373
6429
  }),
6374
6430
  /* @__PURE__ */ jsxs66(Dialog.Content, {
6375
6431
  children: [
6376
- /* @__PURE__ */ jsx88(Dialog.Title, {
6377
- children: "Insert table"
6432
+ /* @__PURE__ */ jsx89(Dialog.Title, {
6433
+ children: tr("insertTableTitle")
6378
6434
  }),
6379
- /* @__PURE__ */ jsx88(Dialog.Description, {
6380
- children: "Define your starting point of a table, you can add and remove columns and rows after creation."
6435
+ /* @__PURE__ */ jsx89(Dialog.Description, {
6436
+ children: tr("insertTableDescription")
6381
6437
  }),
6382
- /* @__PURE__ */ jsx88("div", {
6438
+ /* @__PURE__ */ jsx89("div", {
6383
6439
  className: "items-center justify-between",
6384
- children: /* @__PURE__ */ jsx88(InsertTableDialog, {
6440
+ children: /* @__PURE__ */ jsx89(InsertTableDialog, {
6385
6441
  activeEditor
6386
6442
  })
6387
6443
  })
@@ -6392,7 +6448,7 @@ function ToolbarPlugin({
6392
6448
  })
6393
6449
  ]
6394
6450
  }),
6395
- /* @__PURE__ */ jsx88(ActionsPlugin, {
6451
+ /* @__PURE__ */ jsx89(ActionsPlugin, {
6396
6452
  prepend: actionsMenuPrepend,
6397
6453
  append: actionsMenuAppend
6398
6454
  })
@@ -6502,21 +6558,13 @@ var theme = {
6502
6558
  };
6503
6559
  var CrystallizeRTEditorTheme_default = theme;
6504
6560
 
6505
- // src/rich-text-editor/ui/ContentEditable.tsx
6506
- import "react";
6507
- import { ContentEditable } from "@lexical/react/LexicalContentEditable";
6508
- import { jsx as jsx89 } from "react/jsx-runtime";
6509
- function LexicalContentEditable({ className }) {
6510
- return /* @__PURE__ */ jsx89(ContentEditable, {
6511
- className: className || "ContentEditable__root"
6512
- });
6513
- }
6514
-
6515
6561
  // src/rich-text-editor/rich-text-editor.tsx
6516
6562
  import { Fragment as Fragment9, jsx as jsx90, jsxs as jsxs67 } from "react/jsx-runtime";
6517
6563
  function RichTextEditor({
6518
6564
  initialData,
6519
6565
  editable = true,
6566
+ language = "en",
6567
+ labelTranslations,
6520
6568
  ...rest
6521
6569
  }) {
6522
6570
  return /* @__PURE__ */ jsx90(LexicalComposer, {
@@ -6532,12 +6580,16 @@ function RichTextEditor({
6532
6580
  richText: initialData
6533
6581
  }) : void 0
6534
6582
  },
6535
- children: /* @__PURE__ */ jsx90(SharedHistoryContext, {
6536
- children: /* @__PURE__ */ jsx90("div", {
6537
- className: "c-rich-text-editor",
6538
- children: /* @__PURE__ */ jsx90(RichTextEditorWithoutContext, {
6539
- ...rest,
6540
- editable
6583
+ children: /* @__PURE__ */ jsx90(I18nProvider, {
6584
+ language,
6585
+ labelTranslations,
6586
+ children: /* @__PURE__ */ jsx90(SharedHistoryContext, {
6587
+ children: /* @__PURE__ */ jsx90("div", {
6588
+ className: "c-rich-text-editor",
6589
+ children: /* @__PURE__ */ jsx90(RichTextEditorWithoutContext, {
6590
+ ...rest,
6591
+ editable
6592
+ })
6541
6593
  })
6542
6594
  })
6543
6595
  })
@@ -6560,18 +6612,18 @@ function RichTextEditorWithoutContext({
6560
6612
  children: placeholderText ?? ""
6561
6613
  });
6562
6614
  const [editor] = useLexicalComposerContext12();
6563
- const [floatingAnchorElem, setFloatingAnchorElem] = useState10(null);
6564
- const [isSmallWidthViewport, setIsSmallWidthViewport] = useState10(false);
6615
+ const [floatingAnchorElem, setFloatingAnchorElem] = useState11(null);
6616
+ const [isSmallWidthViewport, setIsSmallWidthViewport] = useState11(false);
6565
6617
  const firstOnChangeTriggeredRef = useRef5(!autoFocus);
6566
6618
  const onRef = (_floatingAnchorElem) => {
6567
6619
  if (_floatingAnchorElem !== null) {
6568
6620
  setFloatingAnchorElem(_floatingAnchorElem);
6569
6621
  }
6570
6622
  };
6571
- useEffect11(() => {
6623
+ useEffect12(() => {
6572
6624
  editor.setEditable(editable || false);
6573
6625
  }, [editable, editor]);
6574
- useEffect11(() => {
6626
+ useEffect12(() => {
6575
6627
  const updateViewPortWidth = () => {
6576
6628
  const isNextSmallWidthViewport = window.matchMedia("(max-width: 1025px)").matches;
6577
6629
  if (isNextSmallWidthViewport !== isSmallWidthViewport) {
@@ -6620,7 +6672,9 @@ function RichTextEditorWithoutContext({
6620
6672
  children: /* @__PURE__ */ jsx90("div", {
6621
6673
  className: "editor",
6622
6674
  ref: onRef,
6623
- children: /* @__PURE__ */ jsx90(LexicalContentEditable, {})
6675
+ children: /* @__PURE__ */ jsx90(ContentEditable, {
6676
+ className: "ContentEditable__root"
6677
+ })
6624
6678
  })
6625
6679
  }),
6626
6680
  placeholder,