@underverse-ui/underverse 1.0.49 → 1.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -748,6 +748,11 @@ var en_default = {
748
748
  cancelBtn: "Cancel",
749
749
  addFromUrl: "Add from URL"
750
750
  },
751
+ emojiPicker: {
752
+ searchPlaceholder: "Search emoji",
753
+ noResults: "No emoji found",
754
+ tryDifferentSearch: "Try a different keyword"
755
+ },
751
756
  tableMenu: {
752
757
  insert3x3: "Insert 3\xD73 Table",
753
758
  addColumnBefore: "Add Column Before",
@@ -967,6 +972,11 @@ var vi_default = {
967
972
  cancelBtn: "H\u1EE7y",
968
973
  addFromUrl: "Th\xEAm t\u1EEB URL"
969
974
  },
975
+ emojiPicker: {
976
+ searchPlaceholder: "T\xECm ki\u1EBFm bi\u1EC3u t\u01B0\u1EE3ng c\u1EA3m x\xFAc",
977
+ noResults: "Kh\xF4ng t\xECm th\u1EA5y emoji",
978
+ tryDifferentSearch: "Th\u1EED t\u1EEB kh\xF3a kh\xE1c"
979
+ },
970
980
  tableMenu: {
971
981
  insert3x3: "Ch\xE8n b\u1EA3ng 3\xD73",
972
982
  addColumnBefore: "Th\xEAm c\u1ED9t tr\u01B0\u1EDBc",
@@ -1185,6 +1195,11 @@ var ko_default = {
1185
1195
  cancelBtn: "\uCDE8\uC18C",
1186
1196
  addFromUrl: "URL\uC5D0\uC11C \uCD94\uAC00"
1187
1197
  },
1198
+ emojiPicker: {
1199
+ searchPlaceholder: "\uC774\uBAA8\uC9C0 \uAC80\uC0C9",
1200
+ noResults: "\uC774\uBAA8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
1201
+ tryDifferentSearch: "\uB2E4\uB978 \uAC80\uC0C9\uC5B4\uB97C \uC2DC\uB3C4\uD574 \uBCF4\uC138\uC694"
1202
+ },
1188
1203
  tableMenu: {
1189
1204
  insert3x3: "3x3 \uD45C \uC0BD\uC785",
1190
1205
  addColumnBefore: "\uC55E\uC5D0 \uC5F4 \uCD94\uAC00",
@@ -1403,6 +1418,11 @@ var ja_default = {
1403
1418
  cancelBtn: "\u30AD\u30E3\u30F3\u30BB\u30EB",
1404
1419
  addFromUrl: "URL\u304B\u3089\u8FFD\u52A0"
1405
1420
  },
1421
+ emojiPicker: {
1422
+ searchPlaceholder: "\u7D75\u6587\u5B57\u3092\u691C\u7D22",
1423
+ noResults: "\u7D75\u6587\u5B57\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
1424
+ tryDifferentSearch: "\u5225\u306E\u30AD\u30FC\u30EF\u30FC\u30C9\u3067\u304A\u8A66\u3057\u304F\u3060\u3055\u3044"
1425
+ },
1406
1426
  tableMenu: {
1407
1427
  insert3x3: "3x3 \u8868\u3092\u633F\u5165",
1408
1428
  addColumnBefore: "\u524D\u306B\u5217\u3092\u8FFD\u52A0",
@@ -1424,6 +1444,25 @@ var defaultTranslations = {
1424
1444
  ko: ko_default,
1425
1445
  ja: ja_default
1426
1446
  };
1447
+ function resolveTranslationValue(translations, namespace, key) {
1448
+ const parts = namespace.split(".");
1449
+ let current = translations;
1450
+ for (const part of parts) {
1451
+ if (current && typeof current === "object" && part in current) {
1452
+ current = current[part];
1453
+ } else {
1454
+ return null;
1455
+ }
1456
+ }
1457
+ if (current && typeof current === "object" && key in current) {
1458
+ const value = current[key];
1459
+ return typeof value === "string" ? value : null;
1460
+ }
1461
+ return null;
1462
+ }
1463
+ function getUnderverseDefaultTranslation(locale, namespace, key) {
1464
+ return resolveTranslationValue(defaultTranslations[locale] ?? defaultTranslations.en, namespace, key) ?? resolveTranslationValue(defaultTranslations.en, namespace, key) ?? key;
1465
+ }
1427
1466
  var TranslationContext = React4.createContext(null);
1428
1467
  var TranslationProvider = ({ children, locale = "en", translations }) => {
1429
1468
  const t = React4.useCallback(
@@ -1433,20 +1472,7 @@ var TranslationProvider = ({ children, locale = "en", translations }) => {
1433
1472
  ...defaultTranslations[locale],
1434
1473
  ...translations?.[locale]
1435
1474
  };
1436
- const parts = namespace.split(".");
1437
- let current = mergedTranslations;
1438
- for (const part of parts) {
1439
- if (current && typeof current === "object" && part in current) {
1440
- current = current[part];
1441
- } else {
1442
- return key;
1443
- }
1444
- }
1445
- if (current && typeof current === "object" && key in current) {
1446
- const value = current[key];
1447
- return typeof value === "string" ? value : key;
1448
- }
1449
- return key;
1475
+ return resolveTranslationValue(mergedTranslations, namespace, key) ?? key;
1450
1476
  };
1451
1477
  },
1452
1478
  [locale, translations]
@@ -1457,20 +1483,7 @@ var useUnderverseTranslations = (namespace) => {
1457
1483
  const context = React4.useContext(TranslationContext);
1458
1484
  if (!context) {
1459
1485
  return (key) => {
1460
- const parts = namespace.split(".");
1461
- let current = defaultTranslations.en;
1462
- for (const part of parts) {
1463
- if (current && typeof current === "object" && part in current) {
1464
- current = current[part];
1465
- } else {
1466
- return key;
1467
- }
1468
- }
1469
- if (current && typeof current === "object" && key in current) {
1470
- const value = current[key];
1471
- return typeof value === "string" ? value : key;
1472
- }
1473
- return key;
1486
+ return getUnderverseDefaultTranslation("en", namespace, key);
1474
1487
  };
1475
1488
  }
1476
1489
  return context.t(namespace);
@@ -1496,17 +1509,53 @@ var ForceInternalContext = React5.createContext(false);
1496
1509
  var ForceInternalTranslationsProvider = ({ children }) => {
1497
1510
  return /* @__PURE__ */ jsx6(ForceInternalContext.Provider, { value: true, children });
1498
1511
  };
1512
+ function normalizeLocale(locale, fallback) {
1513
+ const normalized = locale?.toLowerCase().split("-")[0];
1514
+ if (normalized === "en" || normalized === "vi" || normalized === "ko" || normalized === "ja") {
1515
+ return normalized;
1516
+ }
1517
+ return fallback;
1518
+ }
1519
+ function isUnresolvedTranslation(value, namespace, key) {
1520
+ return value === key || value === `${namespace}.${key}`;
1521
+ }
1499
1522
  function useSmartTranslations(namespace) {
1500
1523
  const forceInternal = React5.useContext(ForceInternalContext);
1501
1524
  const internalT = useUnderverseTranslations(namespace);
1525
+ const internalLocale = useUnderverseLocale();
1502
1526
  if (forceInternal || !nextIntlHooks?.useTranslations) {
1503
1527
  return internalT;
1504
1528
  }
1529
+ let resolvedLocale = internalLocale;
1530
+ try {
1531
+ resolvedLocale = normalizeLocale(nextIntlHooks.useLocale?.(), internalLocale);
1532
+ } catch {
1533
+ resolvedLocale = internalLocale;
1534
+ }
1505
1535
  try {
1506
1536
  const nextIntlT = nextIntlHooks.useTranslations(namespace);
1507
- return nextIntlT;
1537
+ return (key) => {
1538
+ try {
1539
+ const translated = nextIntlT(key);
1540
+ if (!isUnresolvedTranslation(translated, namespace, key)) {
1541
+ return translated;
1542
+ }
1543
+ } catch {
1544
+ }
1545
+ const internalValue = internalT(key);
1546
+ if (internalValue !== key) {
1547
+ return internalValue;
1548
+ }
1549
+ return getUnderverseDefaultTranslation(resolvedLocale, namespace, key);
1550
+ };
1508
1551
  } catch {
1509
- return internalT;
1552
+ return (key) => {
1553
+ const internalValue = internalT(key);
1554
+ if (internalValue !== key) {
1555
+ return internalValue;
1556
+ }
1557
+ return getUnderverseDefaultTranslation(resolvedLocale, namespace, key);
1558
+ };
1510
1559
  }
1511
1560
  }
1512
1561
  function useSmartLocale() {
@@ -15017,9 +15066,9 @@ function CategoryTreeSelect(props) {
15017
15066
  category.id
15018
15067
  );
15019
15068
  };
15020
- const renderSearch = () => {
15069
+ const renderSearch = ({ sticky = true, className: className2 } = {}) => {
15021
15070
  if (!isSearchEnabled) return null;
15022
- return /* @__PURE__ */ jsx46("div", { className: "sticky top-0 z-10 bg-popover/85 backdrop-blur-xl pb-2", children: /* @__PURE__ */ jsxs38("div", { className: "relative", children: [
15071
+ return /* @__PURE__ */ jsx46("div", { className: cn(sticky && "sticky top-0 z-10 bg-popover/85 pb-2 backdrop-blur-xl", className2), children: /* @__PURE__ */ jsxs38("div", { className: "relative", children: [
15023
15072
  /* @__PURE__ */ jsx46(Search5, { className: "absolute left-3.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground/60 transition-colors peer-focus:text-primary" }),
15024
15073
  /* @__PURE__ */ jsx46(
15025
15074
  "input",
@@ -15195,18 +15244,18 @@ function CategoryTreeSelect(props) {
15195
15244
  displayText = mergedLabels.selectedText(selectedCount);
15196
15245
  }
15197
15246
  }
15198
- const dropdownBody = /* @__PURE__ */ jsxs38(
15199
- "div",
15200
- {
15201
- ref: dropdownViewportRef,
15202
- id: `${resolvedId}-tree`,
15203
- className: cn("max-h-80 overflow-auto overflow-x-hidden p-2"),
15204
- children: [
15205
- renderSearch(),
15206
- renderTreeContent()
15207
- ]
15208
- }
15209
- );
15247
+ const dropdownBody = /* @__PURE__ */ jsxs38("div", { className: "flex max-h-80 flex-col overflow-hidden", children: [
15248
+ renderSearch({ sticky: false, className: "border-b border-border/30 p-2 pb-2" }),
15249
+ /* @__PURE__ */ jsx46(
15250
+ "div",
15251
+ {
15252
+ ref: dropdownViewportRef,
15253
+ id: `${resolvedId}-tree`,
15254
+ className: cn("min-h-0 flex-1 overflow-auto overflow-x-hidden p-2 pt-2"),
15255
+ children: renderTreeContent()
15256
+ }
15257
+ )
15258
+ ] });
15210
15259
  return /* @__PURE__ */ jsxs38("div", { className: cn("w-full space-y-2", className), children: [
15211
15260
  renderLabel(),
15212
15261
  /* @__PURE__ */ jsx46(
@@ -22352,7 +22401,6 @@ import Blockquote from "@tiptap/extension-blockquote";
22352
22401
  import Code from "@tiptap/extension-code";
22353
22402
  import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
22354
22403
  import History2 from "@tiptap/extension-history";
22355
- import Placeholder from "@tiptap/extension-placeholder";
22356
22404
  import Link from "@tiptap/extension-link";
22357
22405
  import { TextStyle } from "@tiptap/extension-text-style";
22358
22406
  import Color from "@tiptap/extension-color";
@@ -22389,6 +22437,32 @@ import {
22389
22437
  } from "lucide-react";
22390
22438
  import tippy from "tippy.js";
22391
22439
  import { jsx as jsx79, jsxs as jsxs69 } from "react/jsx-runtime";
22440
+ var DEFAULT_MESSAGES = {
22441
+ noResults: "No results",
22442
+ basicBlocks: "Basic Blocks",
22443
+ text: "Text",
22444
+ textDesc: "Start writing with plain text",
22445
+ heading1: "Heading 1",
22446
+ heading1Desc: "Large section heading",
22447
+ heading2: "Heading 2",
22448
+ heading2Desc: "Medium section heading",
22449
+ heading3: "Heading 3",
22450
+ heading3Desc: "Small section heading",
22451
+ bulletList: "Bullet List",
22452
+ bulletListDesc: "Create a simple bullet list",
22453
+ orderedList: "Numbered List",
22454
+ orderedListDesc: "Create a list with numbering",
22455
+ todoList: "Todo List",
22456
+ todoListDesc: "Track tasks with a todo list",
22457
+ quote: "Quote",
22458
+ quoteDesc: "Capture a quote",
22459
+ codeBlock: "Code Block",
22460
+ codeBlockDesc: "Display code with syntax highlighting",
22461
+ divider: "Divider",
22462
+ dividerDesc: "Visually divide blocks",
22463
+ table: "Table",
22464
+ tableDesc: "Insert a table"
22465
+ };
22392
22466
  var CommandList = forwardRef13((props, ref) => {
22393
22467
  const [selectedIndex, setSelectedIndex] = useState47(0);
22394
22468
  const listRef = useRef30(null);
@@ -22420,10 +22494,10 @@ var CommandList = forwardRef13((props, ref) => {
22420
22494
  }
22421
22495
  }));
22422
22496
  if (props.items.length === 0) {
22423
- return /* @__PURE__ */ jsx79("div", { className: "w-72 p-4 text-center text-sm text-muted-foreground", children: "No results" });
22497
+ return /* @__PURE__ */ jsx79("div", { className: "w-72 p-4 text-center text-sm text-muted-foreground", children: props.messages.noResults });
22424
22498
  }
22425
22499
  return /* @__PURE__ */ jsxs69("div", { ref: listRef, className: "w-72 max-h-80 overflow-y-auto bg-card border border-border rounded-2xl shadow-lg", children: [
22426
- /* @__PURE__ */ jsx79("div", { className: "px-3 py-2 border-b", children: /* @__PURE__ */ jsx79("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Basic Blocks" }) }),
22500
+ /* @__PURE__ */ jsx79("div", { className: "px-3 py-2 border-b", children: /* @__PURE__ */ jsx79("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: props.messages.basicBlocks }) }),
22427
22501
  /* @__PURE__ */ jsx79("div", { className: "p-1", children: props.items.map((item, index) => /* @__PURE__ */ jsxs69(
22428
22502
  "button",
22429
22503
  {
@@ -22456,92 +22530,92 @@ var CommandList = forwardRef13((props, ref) => {
22456
22530
  ] });
22457
22531
  });
22458
22532
  CommandList.displayName = "CommandList";
22459
- var getSuggestionItems = ({ query }) => {
22533
+ var getSuggestionItems = ({ query, messages }) => {
22460
22534
  return [
22461
22535
  {
22462
22536
  icon: Type,
22463
- title: "Text",
22464
- description: "Start writing with plain text",
22537
+ title: messages.text,
22538
+ description: messages.textDesc,
22465
22539
  command: ({ editor, range }) => {
22466
22540
  editor.chain().focus().deleteRange(range).setParagraph().run();
22467
22541
  }
22468
22542
  },
22469
22543
  {
22470
22544
  icon: Heading1,
22471
- title: "Heading 1",
22472
- description: "Large section heading",
22545
+ title: messages.heading1,
22546
+ description: messages.heading1Desc,
22473
22547
  command: ({ editor, range }) => {
22474
22548
  editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
22475
22549
  }
22476
22550
  },
22477
22551
  {
22478
22552
  icon: Heading2,
22479
- title: "Heading 2",
22480
- description: "Medium section heading",
22553
+ title: messages.heading2,
22554
+ description: messages.heading2Desc,
22481
22555
  command: ({ editor, range }) => {
22482
22556
  editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
22483
22557
  }
22484
22558
  },
22485
22559
  {
22486
22560
  icon: Heading3,
22487
- title: "Heading 3",
22488
- description: "Small section heading",
22561
+ title: messages.heading3,
22562
+ description: messages.heading3Desc,
22489
22563
  command: ({ editor, range }) => {
22490
22564
  editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
22491
22565
  }
22492
22566
  },
22493
22567
  {
22494
22568
  icon: List3,
22495
- title: "Bullet List",
22496
- description: "Create a simple bullet list",
22569
+ title: messages.bulletList,
22570
+ description: messages.bulletListDesc,
22497
22571
  command: ({ editor, range }) => {
22498
22572
  editor.chain().focus().deleteRange(range).toggleBulletList().run();
22499
22573
  }
22500
22574
  },
22501
22575
  {
22502
22576
  icon: ListOrdered,
22503
- title: "Numbered List",
22504
- description: "Create a list with numbering",
22577
+ title: messages.orderedList,
22578
+ description: messages.orderedListDesc,
22505
22579
  command: ({ editor, range }) => {
22506
22580
  editor.chain().focus().deleteRange(range).toggleOrderedList().run();
22507
22581
  }
22508
22582
  },
22509
22583
  {
22510
22584
  icon: ListTodo,
22511
- title: "Todo List",
22512
- description: "Track tasks with a todo list",
22585
+ title: messages.todoList,
22586
+ description: messages.todoListDesc,
22513
22587
  command: ({ editor, range }) => {
22514
22588
  editor.chain().focus().deleteRange(range).toggleTaskList().run();
22515
22589
  }
22516
22590
  },
22517
22591
  {
22518
22592
  icon: Quote,
22519
- title: "Quote",
22520
- description: "Capture a quote",
22593
+ title: messages.quote,
22594
+ description: messages.quoteDesc,
22521
22595
  command: ({ editor, range }) => {
22522
22596
  editor.chain().focus().deleteRange(range).toggleBlockquote().run();
22523
22597
  }
22524
22598
  },
22525
22599
  {
22526
22600
  icon: FileCode2,
22527
- title: "Code Block",
22528
- description: "Display code with syntax highlighting",
22601
+ title: messages.codeBlock,
22602
+ description: messages.codeBlockDesc,
22529
22603
  command: ({ editor, range }) => {
22530
22604
  editor.chain().focus().deleteRange(range).toggleCodeBlock().run();
22531
22605
  }
22532
22606
  },
22533
22607
  {
22534
22608
  icon: Minus,
22535
- title: "Divider",
22536
- description: "Visually divide blocks",
22609
+ title: messages.divider,
22610
+ description: messages.dividerDesc,
22537
22611
  command: ({ editor, range }) => {
22538
22612
  editor.chain().focus().deleteRange(range).setHorizontalRule().run();
22539
22613
  }
22540
22614
  },
22541
22615
  {
22542
22616
  icon: Table2,
22543
- title: "Table",
22544
- description: "Insert a table",
22617
+ title: messages.table,
22618
+ description: messages.tableDesc,
22545
22619
  command: ({ editor, range }) => {
22546
22620
  editor.chain().focus().deleteRange(range).insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
22547
22621
  }
@@ -22550,7 +22624,13 @@ var getSuggestionItems = ({ query }) => {
22550
22624
  };
22551
22625
  var SlashCommand = Extension.create({
22552
22626
  name: "slashCommand",
22627
+ addOptions() {
22628
+ return {
22629
+ messages: DEFAULT_MESSAGES
22630
+ };
22631
+ },
22553
22632
  addProseMirrorPlugins() {
22633
+ const messages = this.options.messages;
22554
22634
  return [
22555
22635
  Suggestion({
22556
22636
  editor: this.editor,
@@ -22558,14 +22638,17 @@ var SlashCommand = Extension.create({
22558
22638
  command: ({ editor, range, props }) => {
22559
22639
  props.command({ editor, range });
22560
22640
  },
22561
- items: getSuggestionItems,
22641
+ items: ({ query, editor }) => getSuggestionItems({ query, editor, messages }),
22562
22642
  render: () => {
22563
22643
  let component;
22564
22644
  let popup;
22565
22645
  return {
22566
22646
  onStart: (props) => {
22567
22647
  component = new ReactRenderer(CommandList, {
22568
- props,
22648
+ props: {
22649
+ ...props,
22650
+ messages
22651
+ },
22569
22652
  editor: props.editor
22570
22653
  });
22571
22654
  if (!props.clientRect) {
@@ -22582,7 +22665,10 @@ var SlashCommand = Extension.create({
22582
22665
  });
22583
22666
  },
22584
22667
  onUpdate(props) {
22585
- component?.updateProps(props);
22668
+ component?.updateProps({
22669
+ ...props,
22670
+ messages
22671
+ });
22586
22672
  if (!props.clientRect) {
22587
22673
  return;
22588
22674
  }
@@ -23615,6 +23701,79 @@ var EmojiSuggestion = Extension3.create({
23615
23701
  }
23616
23702
  });
23617
23703
 
23704
+ // src/components/UEditor/placeholder.ts
23705
+ import { Extension as Extension4, isNodeEmpty } from "@tiptap/core";
23706
+ import { Plugin as Plugin2, PluginKey as PluginKey2 } from "@tiptap/pm/state";
23707
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
23708
+ var UEditorPlaceholder = Extension4.create({
23709
+ name: "placeholder",
23710
+ addOptions() {
23711
+ return {
23712
+ emptyEditorClass: "is-editor-empty",
23713
+ emptyNodeClass: "is-empty",
23714
+ dataAttribute: "placeholder",
23715
+ placeholder: "Write something...",
23716
+ showOnlyWhenEditable: true,
23717
+ showOnlyCurrent: true,
23718
+ includeChildren: false,
23719
+ shouldShow: () => true
23720
+ };
23721
+ },
23722
+ addProseMirrorPlugins() {
23723
+ const dataAttribute = `data-${this.options.dataAttribute}`;
23724
+ return [
23725
+ new Plugin2({
23726
+ key: new PluginKey2("placeholder"),
23727
+ props: {
23728
+ decorations: ({ doc, selection }) => {
23729
+ const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
23730
+ const { anchor } = selection;
23731
+ const decorations = [];
23732
+ let hasTable = false;
23733
+ if (!active) {
23734
+ return null;
23735
+ }
23736
+ const isEmptyDoc = this.editor.isEmpty;
23737
+ doc.descendants((node) => {
23738
+ if (node.type.name === "table") {
23739
+ hasTable = true;
23740
+ return false;
23741
+ }
23742
+ return void 0;
23743
+ });
23744
+ doc.descendants((node, pos) => {
23745
+ const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
23746
+ const isEmpty = !node.isLeaf && isNodeEmpty(node);
23747
+ if (!((hasAnchor || !this.options.showOnlyCurrent) && isEmpty)) {
23748
+ return this.options.includeChildren;
23749
+ }
23750
+ if (!this.options.shouldShow({ editor: this.editor, node, pos, hasAnchor, isEmptyDoc, hasTable })) {
23751
+ return this.options.includeChildren;
23752
+ }
23753
+ const placeholderValue = typeof this.options.placeholder === "function" ? this.options.placeholder({ editor: this.editor, node, pos, hasAnchor }) : this.options.placeholder;
23754
+ if (!placeholderValue) {
23755
+ return this.options.includeChildren;
23756
+ }
23757
+ const classes = [this.options.emptyNodeClass];
23758
+ if (isEmptyDoc) {
23759
+ classes.push(this.options.emptyEditorClass);
23760
+ }
23761
+ decorations.push(
23762
+ Decoration.node(pos, pos + node.nodeSize, {
23763
+ class: classes.join(" "),
23764
+ [dataAttribute]: placeholderValue
23765
+ })
23766
+ );
23767
+ return this.options.includeChildren;
23768
+ });
23769
+ return DecorationSet.create(doc, decorations);
23770
+ }
23771
+ }
23772
+ })
23773
+ ];
23774
+ }
23775
+ });
23776
+
23618
23777
  // src/components/UEditor/resizable-image.tsx
23619
23778
  import { useEffect as useEffect33, useRef as useRef31, useState as useState49 } from "react";
23620
23779
  import Image3 from "@tiptap/extension-image";
@@ -23834,6 +23993,7 @@ var resizable_image_default = ResizableImage;
23834
23993
  var lowlight = createLowlight(common);
23835
23994
  function buildUEditorExtensions({
23836
23995
  placeholder,
23996
+ translate,
23837
23997
  maxCharacters,
23838
23998
  uploadImage,
23839
23999
  imageInsertMode = "base64",
@@ -23926,12 +24086,49 @@ function buildUEditorExtensions({
23926
24086
  }),
23927
24087
  Typography,
23928
24088
  History2,
23929
- Placeholder.configure({
24089
+ UEditorPlaceholder.configure({
23930
24090
  placeholder,
23931
24091
  emptyEditorClass: "is-editor-empty",
23932
- emptyNodeClass: "is-empty"
24092
+ emptyNodeClass: "is-empty",
24093
+ shouldShow: ({ node, hasTable }) => {
24094
+ const nodeName = node.type.name;
24095
+ if (nodeName === "table" || nodeName === "tableCell" || nodeName === "tableHeader") {
24096
+ return false;
24097
+ }
24098
+ if (hasTable) {
24099
+ return false;
24100
+ }
24101
+ return true;
24102
+ }
24103
+ }),
24104
+ SlashCommand.configure({
24105
+ messages: {
24106
+ noResults: translate("slashCommand.noResults"),
24107
+ basicBlocks: translate("slashCommand.basicBlocks"),
24108
+ text: translate("slashCommand.text"),
24109
+ textDesc: translate("slashCommand.textDesc"),
24110
+ heading1: translate("slashCommand.heading1"),
24111
+ heading1Desc: translate("slashCommand.heading1Desc"),
24112
+ heading2: translate("slashCommand.heading2"),
24113
+ heading2Desc: translate("slashCommand.heading2Desc"),
24114
+ heading3: translate("slashCommand.heading3"),
24115
+ heading3Desc: translate("slashCommand.heading3Desc"),
24116
+ bulletList: translate("slashCommand.bulletList"),
24117
+ bulletListDesc: translate("slashCommand.bulletListDesc"),
24118
+ orderedList: translate("slashCommand.orderedList"),
24119
+ orderedListDesc: translate("slashCommand.orderedListDesc"),
24120
+ todoList: translate("slashCommand.todoList"),
24121
+ todoListDesc: translate("slashCommand.todoListDesc"),
24122
+ quote: translate("slashCommand.quote"),
24123
+ quoteDesc: translate("slashCommand.quoteDesc"),
24124
+ codeBlock: translate("slashCommand.codeBlock"),
24125
+ codeBlockDesc: translate("slashCommand.codeBlockDesc"),
24126
+ divider: translate("slashCommand.divider"),
24127
+ dividerDesc: translate("slashCommand.dividerDesc"),
24128
+ table: translate("slashCommand.table"),
24129
+ tableDesc: translate("slashCommand.tableDesc")
24130
+ }
23933
24131
  }),
23934
- SlashCommand,
23935
24132
  EmojiSuggestion
23936
24133
  ];
23937
24134
  }
@@ -24152,6 +24349,7 @@ var CATEGORY_ICONS = {
24152
24349
  "flags": Flag
24153
24350
  };
24154
24351
  var EmojiPicker = ({ onSelect, onClose }) => {
24352
+ const t = useSmartTranslations("UEditor");
24155
24353
  const [search, setSearch] = useState51("");
24156
24354
  const [activeCategory, setActiveCategory] = useState51(EMOJI_LIST[0]?.id || "");
24157
24355
  const scrollContainerRef = useRef33(null);
@@ -24221,7 +24419,7 @@ var EmojiPicker = ({ onSelect, onClose }) => {
24221
24419
  "input",
24222
24420
  {
24223
24421
  type: "text",
24224
- placeholder: "T\xECm ki\u1EBFm bi\u1EC3u t\u01B0\u1EE3ng c\u1EA3m x\xFAc",
24422
+ placeholder: t("emojiPicker.searchPlaceholder"),
24225
24423
  value: search,
24226
24424
  onChange: (e) => setSearch(e.target.value),
24227
24425
  className: cn(
@@ -24267,8 +24465,8 @@ var EmojiPicker = ({ onSelect, onClose }) => {
24267
24465
  )) })
24268
24466
  ] }, category.id)) : /* @__PURE__ */ jsxs74("div", { className: "flex flex-col items-center justify-center h-full text-center", children: [
24269
24467
  /* @__PURE__ */ jsx84("div", { className: "text-4xl mb-2", children: "\u{1F50D}" }),
24270
- /* @__PURE__ */ jsx84("div", { className: "text-sm font-medium text-muted-foreground", children: "Kh\xF4ng t\xECm th\u1EA5y emoji" }),
24271
- /* @__PURE__ */ jsx84("div", { className: "text-xs text-muted-foreground mt-1", children: "Th\u1EED t\u1EEB kh\xF3a kh\xE1c" })
24468
+ /* @__PURE__ */ jsx84("div", { className: "text-sm font-medium text-muted-foreground", children: t("emojiPicker.noResults") }),
24469
+ /* @__PURE__ */ jsx84("div", { className: "text-xs text-muted-foreground mt-1", children: t("emojiPicker.tryDifferentSearch") })
24272
24470
  ] })
24273
24471
  ) : (
24274
24472
  // All Categories - Messenger Style
@@ -25560,8 +25758,8 @@ var UEditor = React79.forwardRef(({
25560
25758
  const effectivePlaceholder = placeholder ?? t("placeholder");
25561
25759
  const inFlightPrepareRef = useRef36(null);
25562
25760
  const extensions = useMemo29(
25563
- () => buildUEditorExtensions({ placeholder: effectivePlaceholder, maxCharacters, uploadImage, imageInsertMode, editable }),
25564
- [effectivePlaceholder, maxCharacters, uploadImage, imageInsertMode, editable]
25761
+ () => buildUEditorExtensions({ placeholder: effectivePlaceholder, translate: t, maxCharacters, uploadImage, imageInsertMode, editable }),
25762
+ [effectivePlaceholder, t, maxCharacters, uploadImage, imageInsertMode, editable]
25565
25763
  );
25566
25764
  const editor = useEditor({
25567
25765
  immediatelyRender: false,