@underverse-ui/underverse 1.0.75 → 1.0.77

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
@@ -704,6 +704,17 @@ var en_default = {
704
704
  undo: "Undo (Ctrl+Z)",
705
705
  redo: "Redo (Ctrl+Y)",
706
706
  textStyle: "Text Style",
707
+ fontFamily: "Font Family",
708
+ fontSize: "Font Size",
709
+ lineHeight: "Line Height",
710
+ fontDefault: "Default Font",
711
+ sizeDefault: "Default Size",
712
+ lineHeightDefault: "Default Leading",
713
+ letterSpacing: "Letter Spacing",
714
+ letterSpacingDefault: "Default Tracking",
715
+ fontSans: "Sans",
716
+ fontSerif: "Serif",
717
+ fontMono: "Mono",
707
718
  normal: "Normal text",
708
719
  heading1: "Heading 1",
709
720
  heading2: "Heading 2",
@@ -777,6 +788,8 @@ var en_default = {
777
788
  },
778
789
  tableMenu: {
779
790
  insert3x3: "Insert 3\xD73 Table",
791
+ insertTable: "Insert Table",
792
+ gridPreview: "Insert {rows}\xD7{cols} Table",
780
793
  addColumnBefore: "Add Column Before",
781
794
  addColumnAfter: "Add Column After",
782
795
  addRowBefore: "Add Row Before",
@@ -795,7 +808,10 @@ var en_default = {
795
808
  quickAddRowAfter: "Quick Add Row After",
796
809
  expandTable: "Expand Table",
797
810
  dragRow: "Drag Row",
798
- dragColumn: "Drag Column"
811
+ dragColumn: "Drag Column",
812
+ alignLeft: "Align Table Left",
813
+ alignCenter: "Align Table Center",
814
+ alignRight: "Align Table Right"
799
815
  }
800
816
  }
801
817
  };
@@ -953,6 +969,17 @@ var vi_default = {
953
969
  undo: "Ho\xE0n t\xE1c (Ctrl+Z)",
954
970
  redo: "L\xE0m l\u1EA1i (Ctrl+Y)",
955
971
  textStyle: "Ki\u1EC3u ch\u1EEF",
972
+ fontFamily: "Ph\xF4ng ch\u1EEF",
973
+ fontSize: "C\u1EE1 ch\u1EEF",
974
+ lineHeight: "Gi\xE3n d\xF2ng",
975
+ fontDefault: "Ph\xF4ng m\u1EB7c \u0111\u1ECBnh",
976
+ sizeDefault: "C\u1EE1 m\u1EB7c \u0111\u1ECBnh",
977
+ lineHeightDefault: "Gi\xE3n d\xF2ng m\u1EB7c \u0111\u1ECBnh",
978
+ letterSpacing: "Gi\xE3n ch\u1EEF",
979
+ letterSpacingDefault: "Gi\xE3n ch\u1EEF m\u1EB7c \u0111\u1ECBnh",
980
+ fontSans: "Sans",
981
+ fontSerif: "Serif",
982
+ fontMono: "Mono",
956
983
  normal: "V\u0103n b\u1EA3n th\u01B0\u1EDDng",
957
984
  heading1: "Ti\xEAu \u0111\u1EC1 1",
958
985
  heading2: "Ti\xEAu \u0111\u1EC1 2",
@@ -1026,6 +1053,8 @@ var vi_default = {
1026
1053
  },
1027
1054
  tableMenu: {
1028
1055
  insert3x3: "Ch\xE8n b\u1EA3ng 3\xD73",
1056
+ insertTable: "Ch\xE8n b\u1EA3ng",
1057
+ gridPreview: "Ch\xE8n b\u1EA3ng {rows}\xD7{cols}",
1029
1058
  addColumnBefore: "Th\xEAm c\u1ED9t tr\u01B0\u1EDBc",
1030
1059
  addColumnAfter: "Th\xEAm c\u1ED9t sau",
1031
1060
  addRowBefore: "Th\xEAm h\xE0ng tr\u01B0\u1EDBc",
@@ -1044,7 +1073,10 @@ var vi_default = {
1044
1073
  quickAddRowAfter: "Th\xEAm nhanh h\xE0ng sau",
1045
1074
  expandTable: "M\u1EDF r\u1ED9ng b\u1EA3ng",
1046
1075
  dragRow: "K\xE9o h\xE0ng",
1047
- dragColumn: "K\xE9o c\u1ED9t"
1076
+ dragColumn: "K\xE9o c\u1ED9t",
1077
+ alignLeft: "C\u0103n b\u1EA3ng tr\xE1i",
1078
+ alignCenter: "C\u0103n b\u1EA3ng gi\u1EEFa",
1079
+ alignRight: "C\u0103n b\u1EA3ng ph\u1EA3i"
1048
1080
  }
1049
1081
  }
1050
1082
  };
@@ -1202,6 +1234,17 @@ var ko_default = {
1202
1234
  undo: "\uC2E4\uD589 \uCDE8\uC18C",
1203
1235
  redo: "\uB2E4\uC2DC \uC2E4\uD589",
1204
1236
  textStyle: "\uD14D\uC2A4\uD2B8 \uC2A4\uD0C0\uC77C",
1237
+ fontFamily: "\uAE00\uAF34",
1238
+ fontSize: "\uAE00\uC790 \uD06C\uAE30",
1239
+ lineHeight: "\uC904 \uAC04\uACA9",
1240
+ fontDefault: "\uAE30\uBCF8 \uAE00\uAF34",
1241
+ sizeDefault: "\uAE30\uBCF8 \uD06C\uAE30",
1242
+ lineHeightDefault: "\uAE30\uBCF8 \uC904 \uAC04\uACA9",
1243
+ letterSpacing: "\uC790\uAC04",
1244
+ letterSpacingDefault: "\uAE30\uBCF8 \uC790\uAC04",
1245
+ fontSans: "Sans",
1246
+ fontSerif: "Serif",
1247
+ fontMono: "Mono",
1205
1248
  normal: "\uC77C\uBC18 \uD14D\uC2A4\uD2B8",
1206
1249
  heading1: "\uC81C\uBAA9 1",
1207
1250
  heading2: "\uC81C\uBAA9 2",
@@ -1274,6 +1317,8 @@ var ko_default = {
1274
1317
  },
1275
1318
  tableMenu: {
1276
1319
  insert3x3: "3x3 \uD45C \uC0BD\uC785",
1320
+ insertTable: "\uD45C \uC0BD\uC785",
1321
+ gridPreview: "{rows}\xD7{cols} \uD45C \uC0BD\uC785",
1277
1322
  addColumnBefore: "\uC55E\uC5D0 \uC5F4 \uCD94\uAC00",
1278
1323
  addColumnAfter: "\uB4A4\uC5D0 \uC5F4 \uCD94\uAC00",
1279
1324
  addRowBefore: "\uC704\uC5D0 \uD589 \uCD94\uAC00",
@@ -1292,7 +1337,10 @@ var ko_default = {
1292
1337
  quickAddRowAfter: "\uC544\uB798 \uD589 \uBE60\uB974\uAC8C \uCD94\uAC00",
1293
1338
  expandTable: "\uD45C \uD655\uC7A5",
1294
1339
  dragRow: "\uD589 \uB4DC\uB798\uADF8",
1295
- dragColumn: "\uC5F4 \uB4DC\uB798\uADF8"
1340
+ dragColumn: "\uC5F4 \uB4DC\uB798\uADF8",
1341
+ alignLeft: "\uD45C \uC67C\uCABD \uC815\uB82C",
1342
+ alignCenter: "\uD45C \uAC00\uC6B4\uB370 \uC815\uB82C",
1343
+ alignRight: "\uD45C \uC624\uB978\uCABD \uC815\uB82C"
1296
1344
  }
1297
1345
  }
1298
1346
  };
@@ -1450,6 +1498,17 @@ var ja_default = {
1450
1498
  undo: "\u5143\u306B\u623B\u3059",
1451
1499
  redo: "\u3084\u308A\u76F4\u3057",
1452
1500
  textStyle: "\u30C6\u30AD\u30B9\u30C8\u30B9\u30BF\u30A4\u30EB",
1501
+ fontFamily: "\u30D5\u30A9\u30F3\u30C8",
1502
+ fontSize: "\u6587\u5B57\u30B5\u30A4\u30BA",
1503
+ lineHeight: "\u884C\u9593",
1504
+ fontDefault: "\u6A19\u6E96\u30D5\u30A9\u30F3\u30C8",
1505
+ sizeDefault: "\u6A19\u6E96\u30B5\u30A4\u30BA",
1506
+ lineHeightDefault: "\u6A19\u6E96\u306E\u884C\u9593",
1507
+ letterSpacing: "\u6587\u5B57\u9593\u9694",
1508
+ letterSpacingDefault: "\u6A19\u6E96\u306E\u5B57\u9593",
1509
+ fontSans: "Sans",
1510
+ fontSerif: "Serif",
1511
+ fontMono: "Mono",
1453
1512
  normal: "\u6A19\u6E96\u30C6\u30AD\u30B9\u30C8",
1454
1513
  heading1: "\u898B\u51FA\u3057 1",
1455
1514
  heading2: "\u898B\u51FA\u3057 2",
@@ -1522,6 +1581,8 @@ var ja_default = {
1522
1581
  },
1523
1582
  tableMenu: {
1524
1583
  insert3x3: "3x3 \u8868\u3092\u633F\u5165",
1584
+ insertTable: "\u8868\u3092\u633F\u5165",
1585
+ gridPreview: "{rows}\xD7{cols} \u306E\u8868\u3092\u633F\u5165",
1525
1586
  addColumnBefore: "\u524D\u306B\u5217\u3092\u8FFD\u52A0",
1526
1587
  addColumnAfter: "\u5F8C\u306B\u5217\u3092\u8FFD\u52A0",
1527
1588
  addRowBefore: "\u524D\u306B\u884C\u3092\u8FFD\u52A0",
@@ -1540,7 +1601,10 @@ var ja_default = {
1540
1601
  quickAddRowAfter: "\u4E0B\u306B\u884C\u3092\u3059\u3070\u3084\u304F\u8FFD\u52A0",
1541
1602
  expandTable: "\u8868\u3092\u62E1\u5F35",
1542
1603
  dragRow: "\u884C\u3092\u30C9\u30E9\u30C3\u30B0",
1543
- dragColumn: "\u5217\u3092\u30C9\u30E9\u30C3\u30B0"
1604
+ dragColumn: "\u5217\u3092\u30C9\u30E9\u30C3\u30B0",
1605
+ alignLeft: "\u8868\u3092\u5DE6\u5BC4\u305B",
1606
+ alignCenter: "\u8868\u3092\u4E2D\u592E\u63C3\u3048",
1607
+ alignRight: "\u8868\u3092\u53F3\u5BC4\u305B"
1544
1608
  }
1545
1609
  }
1546
1610
  };
@@ -3696,7 +3760,8 @@ var EmojiPicker = ({
3696
3760
  showSearch = true,
3697
3761
  showCategoryNav = true,
3698
3762
  columns = 9,
3699
- maxHeight = "20rem"
3763
+ maxHeight = "20rem",
3764
+ chrome = "standalone"
3700
3765
  }) => {
3701
3766
  const t = useSmartTranslations("UEditor");
3702
3767
  const [search, setSearch] = useState5("");
@@ -3707,6 +3772,11 @@ var EmojiPicker = ({
3707
3772
  const resolvedSearchPlaceholder = searchPlaceholder ?? t("emojiPicker.searchPlaceholder");
3708
3773
  const resolvedEmptyText = emptyText ?? t("emojiPicker.noResults");
3709
3774
  const resolvedEmptyHint = emptyHint ?? t("emojiPicker.tryDifferentSearch");
3775
+ const resolvedColumns = Math.max(1, Math.floor(columns));
3776
+ const isEmbedded = chrome === "embedded";
3777
+ const gridStyle = {
3778
+ gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))`
3779
+ };
3710
3780
  const filteredCategories = useMemo3(() => {
3711
3781
  if (!search.trim()) return EMOJI_LIST;
3712
3782
  const query = search.toLowerCase();
@@ -3746,7 +3816,6 @@ var EmojiPicker = ({
3746
3816
  useEffect3(() => {
3747
3817
  isUserScrolling.current = true;
3748
3818
  }, []);
3749
- const gridColsClass = `grid-cols-${columns}`;
3750
3819
  const renderEmojiCategory = (category, assignRef2 = false) => /* @__PURE__ */ jsxs7(
3751
3820
  "div",
3752
3821
  {
@@ -3755,7 +3824,7 @@ var EmojiPicker = ({
3755
3824
  } : void 0,
3756
3825
  children: [
3757
3826
  /* @__PURE__ */ jsx12("div", { className: "sticky top-0 z-10 bg-card py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: category.name }),
3758
- /* @__PURE__ */ jsx12("div", { className: cn("grid gap-1", gridColsClass), children: category.emojis.map((emoji) => /* @__PURE__ */ jsx12(
3827
+ /* @__PURE__ */ jsx12("div", { className: "grid gap-1", style: gridStyle, children: category.emojis.map((emoji) => /* @__PURE__ */ jsx12(
3759
3828
  EmojiGridButton,
3760
3829
  {
3761
3830
  emoji: emoji.emoji,
@@ -3788,50 +3857,60 @@ var EmojiPicker = ({
3788
3857
  isUserScrolling.current = true;
3789
3858
  }, 500);
3790
3859
  };
3791
- return /* @__PURE__ */ jsxs7("div", { className: cn("flex max-h-128 w-96 flex-col overflow-hidden rounded-2xl border border-border bg-card shadow-xl", className), children: [
3792
- showSearch && /* @__PURE__ */ jsx12("div", { className: "shrink-0 border-b bg-muted/30 p-3", children: /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
3793
- /* @__PURE__ */ jsx12(Search2, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
3794
- /* @__PURE__ */ jsx12(
3795
- "input",
3796
- {
3797
- type: "text",
3798
- placeholder: resolvedSearchPlaceholder,
3799
- value: search,
3800
- onChange: (e) => setSearch(e.target.value),
3801
- className: cn(
3802
- "w-full rounded-lg border border-border bg-background py-2 pl-9 pr-9 text-sm",
3803
- "placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
3804
- )
3805
- }
3860
+ return /* @__PURE__ */ jsxs7(
3861
+ "div",
3862
+ {
3863
+ className: cn(
3864
+ "flex max-h-128 w-96 flex-col overflow-hidden",
3865
+ isEmbedded ? "bg-transparent" : "rounded-2xl border border-border bg-card shadow-xl",
3866
+ className
3806
3867
  ),
3807
- search && /* @__PURE__ */ jsx12(
3808
- "button",
3809
- {
3810
- type: "button",
3811
- onClick: () => setSearch(""),
3812
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
3813
- children: /* @__PURE__ */ jsx12(X2, { className: "h-4 w-4" })
3814
- }
3815
- )
3816
- ] }) }),
3817
- /* @__PURE__ */ jsx12("div", { ref: scrollContainerRef, className: "shrink overflow-y-auto px-3 py-2", style: { height: maxHeight }, children: search ? searchResultContent : /* @__PURE__ */ jsx12("div", { className: "space-y-4", children: EMOJI_LIST.map((category) => renderEmojiCategory(category, true)) }) }),
3818
- !search && showCategoryNav && /* @__PURE__ */ jsx12("div", { className: "flex shrink-0 items-center justify-around border-t bg-muted/30 px-2 py-2", children: EMOJI_LIST.map((category) => {
3819
- const IconComponent = CATEGORY_ICONS[category.id] || Smile;
3820
- return /* @__PURE__ */ jsx12(
3821
- "button",
3822
- {
3823
- type: "button",
3824
- onClick: () => handleCategoryClick(category.id),
3825
- className: cn(
3826
- "rounded-lg p-2 transition-colors",
3827
- activeCategory === category.id ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-accent hover:text-foreground"
3868
+ children: [
3869
+ showSearch && /* @__PURE__ */ jsx12("div", { className: cn("shrink-0 border-b p-3", isEmbedded ? "bg-transparent" : "bg-muted/30"), children: /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
3870
+ /* @__PURE__ */ jsx12(Search2, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
3871
+ /* @__PURE__ */ jsx12(
3872
+ "input",
3873
+ {
3874
+ type: "text",
3875
+ placeholder: resolvedSearchPlaceholder,
3876
+ value: search,
3877
+ onChange: (e) => setSearch(e.target.value),
3878
+ className: cn(
3879
+ "w-full rounded-lg border border-border bg-background py-2 pl-9 pr-9 text-sm",
3880
+ "placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
3881
+ )
3882
+ }
3828
3883
  ),
3829
- children: /* @__PURE__ */ jsx12(Tooltip, { placement: "top", content: /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium", children: category.name }), children: /* @__PURE__ */ jsx12("span", { className: "inline-flex", children: /* @__PURE__ */ jsx12(IconComponent, { className: "h-5 w-5" }) }) })
3830
- },
3831
- category.id
3832
- );
3833
- }) })
3834
- ] });
3884
+ search && /* @__PURE__ */ jsx12(
3885
+ "button",
3886
+ {
3887
+ type: "button",
3888
+ onClick: () => setSearch(""),
3889
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
3890
+ children: /* @__PURE__ */ jsx12(X2, { className: "h-4 w-4" })
3891
+ }
3892
+ )
3893
+ ] }) }),
3894
+ /* @__PURE__ */ jsx12("div", { ref: scrollContainerRef, className: "shrink overflow-y-auto px-3 py-2", style: { height: maxHeight }, children: search ? searchResultContent : /* @__PURE__ */ jsx12("div", { className: "space-y-4", children: EMOJI_LIST.map((category) => renderEmojiCategory(category, true)) }) }),
3895
+ !search && showCategoryNav && /* @__PURE__ */ jsx12("div", { className: cn("flex shrink-0 items-center justify-around border-t px-2 py-2", isEmbedded ? "bg-transparent" : "bg-muted/30"), children: EMOJI_LIST.map((category) => {
3896
+ const IconComponent = CATEGORY_ICONS[category.id] || Smile;
3897
+ return /* @__PURE__ */ jsx12(
3898
+ "button",
3899
+ {
3900
+ type: "button",
3901
+ onClick: () => handleCategoryClick(category.id),
3902
+ className: cn(
3903
+ "rounded-lg p-2 transition-colors",
3904
+ activeCategory === category.id ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-accent hover:text-foreground"
3905
+ ),
3906
+ children: /* @__PURE__ */ jsx12(Tooltip, { placement: "top", content: /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium", children: category.name }), children: /* @__PURE__ */ jsx12("span", { className: "inline-flex", children: /* @__PURE__ */ jsx12(IconComponent, { className: "h-5 w-5" }) }) })
3907
+ },
3908
+ category.id
3909
+ );
3910
+ }) })
3911
+ ]
3912
+ }
3913
+ );
3835
3914
  };
3836
3915
  var EmojiPicker_default = EmojiPicker;
3837
3916
 
@@ -22021,7 +22100,6 @@ import { TextStyle } from "@tiptap/extension-text-style";
22021
22100
  import Color from "@tiptap/extension-color";
22022
22101
  import Highlight from "@tiptap/extension-highlight";
22023
22102
  import TextAlign from "@tiptap/extension-text-align";
22024
- import { Table as Table3 } from "@tiptap/extension-table";
22025
22103
  import TableCell2 from "@tiptap/extension-table-cell";
22026
22104
  import TableHeader2 from "@tiptap/extension-table-header";
22027
22105
  import CharacterCount from "@tiptap/extension-character-count";
@@ -23001,6 +23079,283 @@ var UEditorTableRow = TableRow2.extend({
23001
23079
  });
23002
23080
  var table_row_default = UEditorTableRow;
23003
23081
 
23082
+ // src/components/UEditor/font-family.ts
23083
+ import { Extension as Extension5 } from "@tiptap/core";
23084
+ var FontFamily = Extension5.create({
23085
+ name: "fontFamily",
23086
+ addOptions() {
23087
+ return {
23088
+ types: ["textStyle"]
23089
+ };
23090
+ },
23091
+ addGlobalAttributes() {
23092
+ return [
23093
+ {
23094
+ types: this.options.types,
23095
+ attributes: {
23096
+ fontFamily: {
23097
+ default: null,
23098
+ parseHTML: (element) => element.style.fontFamily || null,
23099
+ renderHTML: (attributes) => {
23100
+ const fontFamily = typeof attributes.fontFamily === "string" ? attributes.fontFamily.trim() : "";
23101
+ if (!fontFamily) return {};
23102
+ return { style: `font-family: ${fontFamily}` };
23103
+ }
23104
+ }
23105
+ }
23106
+ }
23107
+ ];
23108
+ },
23109
+ addCommands() {
23110
+ return {
23111
+ setFontFamily: (fontFamily) => ({ chain }) => chain().setMark("textStyle", { fontFamily }).run(),
23112
+ unsetFontFamily: () => ({ chain }) => chain().setMark("textStyle", { fontFamily: null }).removeEmptyTextStyle().run()
23113
+ };
23114
+ }
23115
+ });
23116
+ var font_family_default = FontFamily;
23117
+
23118
+ // src/components/UEditor/font-size.ts
23119
+ import { Extension as Extension6 } from "@tiptap/core";
23120
+ var FontSize = Extension6.create({
23121
+ name: "fontSize",
23122
+ addOptions() {
23123
+ return {
23124
+ types: ["textStyle"]
23125
+ };
23126
+ },
23127
+ addGlobalAttributes() {
23128
+ return [
23129
+ {
23130
+ types: this.options.types,
23131
+ attributes: {
23132
+ fontSize: {
23133
+ default: null,
23134
+ parseHTML: (element) => element.style.fontSize || null,
23135
+ renderHTML: (attributes) => {
23136
+ const fontSize = typeof attributes.fontSize === "string" ? attributes.fontSize.trim() : "";
23137
+ if (!fontSize) return {};
23138
+ return { style: `font-size: ${fontSize}` };
23139
+ }
23140
+ }
23141
+ }
23142
+ }
23143
+ ];
23144
+ },
23145
+ addCommands() {
23146
+ return {
23147
+ setFontSize: (fontSize) => ({ chain }) => chain().setMark("textStyle", { fontSize }).run(),
23148
+ unsetFontSize: () => ({ chain }) => chain().setMark("textStyle", { fontSize: null }).removeEmptyTextStyle().run()
23149
+ };
23150
+ }
23151
+ });
23152
+ var font_size_default = FontSize;
23153
+
23154
+ // src/components/UEditor/line-height.ts
23155
+ import { Extension as Extension7 } from "@tiptap/core";
23156
+ var LineHeight = Extension7.create({
23157
+ name: "lineHeight",
23158
+ addOptions() {
23159
+ return {
23160
+ types: ["textStyle"]
23161
+ };
23162
+ },
23163
+ addGlobalAttributes() {
23164
+ return [
23165
+ {
23166
+ types: this.options.types,
23167
+ attributes: {
23168
+ lineHeight: {
23169
+ default: null,
23170
+ parseHTML: (element) => element.style.lineHeight || null,
23171
+ renderHTML: (attributes) => {
23172
+ const lineHeight = typeof attributes.lineHeight === "string" ? attributes.lineHeight.trim() : "";
23173
+ if (!lineHeight) return {};
23174
+ return { style: `line-height: ${lineHeight}` };
23175
+ }
23176
+ }
23177
+ }
23178
+ }
23179
+ ];
23180
+ },
23181
+ addCommands() {
23182
+ return {
23183
+ setLineHeight: (lineHeight) => ({ chain }) => chain().setMark("textStyle", { lineHeight }).run(),
23184
+ unsetLineHeight: () => ({ chain }) => chain().setMark("textStyle", { lineHeight: null }).removeEmptyTextStyle().run()
23185
+ };
23186
+ }
23187
+ });
23188
+ var line_height_default = LineHeight;
23189
+
23190
+ // src/components/UEditor/letter-spacing.ts
23191
+ import { Extension as Extension8 } from "@tiptap/core";
23192
+ var LetterSpacing = Extension8.create({
23193
+ name: "letterSpacing",
23194
+ addOptions() {
23195
+ return {
23196
+ types: ["textStyle"]
23197
+ };
23198
+ },
23199
+ addGlobalAttributes() {
23200
+ return [
23201
+ {
23202
+ types: this.options.types,
23203
+ attributes: {
23204
+ letterSpacing: {
23205
+ default: null,
23206
+ parseHTML: (element) => element.style.letterSpacing || null,
23207
+ renderHTML: (attributes) => {
23208
+ const letterSpacing = typeof attributes.letterSpacing === "string" ? attributes.letterSpacing.trim() : "";
23209
+ if (!letterSpacing) return {};
23210
+ return { style: `letter-spacing: ${letterSpacing}` };
23211
+ }
23212
+ }
23213
+ }
23214
+ }
23215
+ ];
23216
+ },
23217
+ addCommands() {
23218
+ return {
23219
+ setLetterSpacing: (letterSpacing) => ({ chain }) => chain().setMark("textStyle", { letterSpacing }).run(),
23220
+ unsetLetterSpacing: () => ({ chain }) => chain().setMark("textStyle", { letterSpacing: null }).removeEmptyTextStyle().run()
23221
+ };
23222
+ }
23223
+ });
23224
+ var letter_spacing_default = LetterSpacing;
23225
+
23226
+ // src/components/UEditor/table-align.ts
23227
+ import { Table as Table3 } from "@tiptap/extension-table";
23228
+
23229
+ // src/components/UEditor/table-align-utils.ts
23230
+ function findTableNodeInfoAtResolvedPos($pos) {
23231
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
23232
+ const node = $pos.node(depth);
23233
+ if (node.type.name === "table") {
23234
+ return {
23235
+ depth,
23236
+ pos: $pos.before(depth),
23237
+ node
23238
+ };
23239
+ }
23240
+ }
23241
+ return null;
23242
+ }
23243
+ function findTableNodeInfoFromState(state, anchorPos) {
23244
+ if (typeof anchorPos === "number" && Number.isFinite(anchorPos)) {
23245
+ const safePos = Math.max(0, Math.min(anchorPos, state.doc.content.size));
23246
+ return findTableNodeInfoAtResolvedPos(state.doc.resolve(safePos));
23247
+ }
23248
+ return findTableNodeInfoAtResolvedPos(state.selection.$from);
23249
+ }
23250
+ function applyTableAlignment(editor, tableAlign, anchorPos) {
23251
+ const tableInfo = findTableNodeInfoFromState(editor.state, anchorPos);
23252
+ if (!tableInfo) return false;
23253
+ editor.view.dispatch(
23254
+ editor.state.tr.setNodeMarkup(tableInfo.pos, tableInfo.node.type, {
23255
+ ...tableInfo.node.attrs,
23256
+ tableAlign
23257
+ })
23258
+ );
23259
+ const tableDom = editor.view.nodeDOM(tableInfo.pos);
23260
+ const tableElement = tableDom instanceof HTMLTableElement ? tableDom : tableDom instanceof HTMLElement ? tableDom.querySelector("table") : null;
23261
+ if (tableElement instanceof HTMLTableElement) {
23262
+ if (tableAlign) {
23263
+ tableElement.setAttribute("data-table-align", tableAlign);
23264
+ tableElement.style.width = "max-content";
23265
+ tableElement.style.maxWidth = "100%";
23266
+ tableElement.style.marginLeft = tableAlign === "center" || tableAlign === "right" ? "auto" : "0";
23267
+ tableElement.style.marginRight = tableAlign === "center" ? "auto" : tableAlign === "right" ? "0" : "auto";
23268
+ } else {
23269
+ tableElement.removeAttribute("data-table-align");
23270
+ tableElement.style.removeProperty("width");
23271
+ tableElement.style.removeProperty("max-width");
23272
+ tableElement.style.removeProperty("margin-left");
23273
+ tableElement.style.removeProperty("margin-right");
23274
+ }
23275
+ }
23276
+ return true;
23277
+ }
23278
+
23279
+ // src/components/UEditor/table-align.ts
23280
+ function normalizeTableAlign(value) {
23281
+ if (value === "left" || value === "center" || value === "right") {
23282
+ return value;
23283
+ }
23284
+ return null;
23285
+ }
23286
+ function parseTableAlign(element) {
23287
+ const dataAlign = normalizeTableAlign(element.getAttribute("data-table-align"));
23288
+ if (dataAlign) return dataAlign;
23289
+ const marginLeft = element.style.marginLeft?.trim();
23290
+ const marginRight = element.style.marginRight?.trim();
23291
+ if (marginLeft === "auto" && marginRight === "auto") return "center";
23292
+ if (marginLeft === "auto" && (marginRight === "0px" || marginRight === "0")) return "right";
23293
+ if ((marginLeft === "0px" || marginLeft === "0") && marginRight === "auto") return "left";
23294
+ return null;
23295
+ }
23296
+ function renderTableAlignStyle(tableAlign) {
23297
+ switch (tableAlign) {
23298
+ case "center":
23299
+ return "width: max-content; max-width: 100%; margin-left: auto; margin-right: auto;";
23300
+ case "right":
23301
+ return "width: max-content; max-width: 100%; margin-left: auto; margin-right: 0;";
23302
+ case "left":
23303
+ return "width: max-content; max-width: 100%; margin-left: 0; margin-right: auto;";
23304
+ default:
23305
+ return "";
23306
+ }
23307
+ }
23308
+ var UEditorTable = Table3.extend({
23309
+ addAttributes() {
23310
+ return {
23311
+ ...this.parent?.(),
23312
+ tableAlign: {
23313
+ default: null,
23314
+ parseHTML: (element) => {
23315
+ if (!(element instanceof HTMLElement)) return null;
23316
+ return parseTableAlign(element);
23317
+ },
23318
+ renderHTML: (attributes) => {
23319
+ const tableAlign = normalizeTableAlign(attributes.tableAlign);
23320
+ if (!tableAlign) return {};
23321
+ return {
23322
+ "data-table-align": tableAlign,
23323
+ style: renderTableAlignStyle(tableAlign)
23324
+ };
23325
+ }
23326
+ }
23327
+ };
23328
+ },
23329
+ addCommands() {
23330
+ return {
23331
+ ...this.parent?.(),
23332
+ setTableAlign: (tableAlign) => ({ state, dispatch }) => {
23333
+ const tableInfo = findTableNodeInfoFromState(state);
23334
+ if (!tableInfo) return false;
23335
+ dispatch?.(
23336
+ state.tr.setNodeMarkup(tableInfo.pos, tableInfo.node.type, {
23337
+ ...tableInfo.node.attrs,
23338
+ tableAlign
23339
+ })
23340
+ );
23341
+ return true;
23342
+ },
23343
+ unsetTableAlign: () => ({ state, dispatch }) => {
23344
+ const tableInfo = findTableNodeInfoFromState(state);
23345
+ if (!tableInfo) return false;
23346
+ dispatch?.(
23347
+ state.tr.setNodeMarkup(tableInfo.pos, tableInfo.node.type, {
23348
+ ...tableInfo.node.attrs,
23349
+ tableAlign: null
23350
+ })
23351
+ );
23352
+ return true;
23353
+ }
23354
+ };
23355
+ }
23356
+ });
23357
+ var table_align_default = UEditorTable;
23358
+
23004
23359
  // src/components/UEditor/extensions.ts
23005
23360
  var lowlight = createLowlight(common);
23006
23361
  function buildUEditorExtensions({
@@ -23056,7 +23411,7 @@ function buildUEditorExtensions({
23056
23411
  CodeBlockLowlight.configure({
23057
23412
  lowlight,
23058
23413
  HTMLAttributes: {
23059
- class: "rounded-lg bg-[#1e1e1e] p-4 font-mono text-sm overflow-x-auto"
23414
+ class: "rounded-lg border border-border/60 bg-muted/40 text-foreground p-4 font-mono text-sm overflow-x-auto"
23060
23415
  }
23061
23416
  }),
23062
23417
  HorizontalRule,
@@ -23069,6 +23424,10 @@ function buildUEditorExtensions({
23069
23424
  resizable_image_default,
23070
23425
  ClipboardImages.configure({ upload: uploadImage, insertMode: imageInsertMode }),
23071
23426
  TextStyle,
23427
+ font_family_default,
23428
+ font_size_default,
23429
+ line_height_default,
23430
+ letter_spacing_default,
23072
23431
  Color,
23073
23432
  Highlight.configure({
23074
23433
  multicolor: true
@@ -23076,7 +23435,7 @@ function buildUEditorExtensions({
23076
23435
  TextAlign.configure({
23077
23436
  types: ["heading", "paragraph", "image"]
23078
23437
  }),
23079
- Table3.configure({
23438
+ table_align_default.configure({
23080
23439
  resizable: true,
23081
23440
  handleWidth: 10,
23082
23441
  allowTableNodeSelection: true,
@@ -23418,9 +23777,51 @@ var ImageInput = ({ onSubmit, onCancel }) => {
23418
23777
  // src/components/UEditor/emoji-picker.tsx
23419
23778
  import { jsx as jsx79 } from "react/jsx-runtime";
23420
23779
  var EmojiPicker2 = ({ onSelect }) => {
23421
- return /* @__PURE__ */ jsx79(EmojiPicker, { onEmojiSelect: onSelect });
23780
+ return /* @__PURE__ */ jsx79(EmojiPicker, { onEmojiSelect: onSelect, chrome: "embedded" });
23422
23781
  };
23423
23782
 
23783
+ // src/components/UEditor/typography-options.ts
23784
+ function normalizeStyleValue(value) {
23785
+ return typeof value === "string" ? value.trim().replace(/^['"]|['"]$/g, "") : "";
23786
+ }
23787
+ function getDefaultFontFamilies(t) {
23788
+ return [
23789
+ { label: "Inter", value: "Inter, ui-sans-serif, system-ui, sans-serif" },
23790
+ { label: "System UI", value: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" },
23791
+ { label: "Georgia", value: "Georgia, 'Times New Roman', serif" },
23792
+ { label: "Palatino", value: "'Palatino Linotype', Palatino, Georgia, serif" },
23793
+ { label: "Times", value: "'Times New Roman', Times, serif" },
23794
+ { label: "JetBrains Mono", value: "'JetBrains Mono', 'Fira Code', 'SFMono-Regular', Consolas, monospace" }
23795
+ ];
23796
+ }
23797
+ function getDefaultFontSizes() {
23798
+ return [
23799
+ { label: "12", value: "12px" },
23800
+ { label: "14", value: "14px" },
23801
+ { label: "16", value: "16px" },
23802
+ { label: "18", value: "18px" },
23803
+ { label: "24", value: "24px" },
23804
+ { label: "32", value: "32px" }
23805
+ ];
23806
+ }
23807
+ function getDefaultLineHeights() {
23808
+ return [
23809
+ { label: "1.2", value: "1.2" },
23810
+ { label: "1.5", value: "1.5" },
23811
+ { label: "1.75", value: "1.75" },
23812
+ { label: "2", value: "2" }
23813
+ ];
23814
+ }
23815
+ function getDefaultLetterSpacings() {
23816
+ return [
23817
+ { label: "-0.02em", value: "-0.02em" },
23818
+ { label: "0", value: "0" },
23819
+ { label: "0.02em", value: "0.02em" },
23820
+ { label: "0.05em", value: "0.05em" },
23821
+ { label: "0.08em", value: "0.08em" }
23822
+ ];
23823
+ }
23824
+
23424
23825
  // src/components/UEditor/toolbar.tsx
23425
23826
  import { Fragment as Fragment25, jsx as jsx80, jsxs as jsxs67 } from "react/jsx-runtime";
23426
23827
  function fileToDataUrl2(file) {
@@ -23431,12 +23832,16 @@ function fileToDataUrl2(file) {
23431
23832
  reader.readAsDataURL(file);
23432
23833
  });
23433
23834
  }
23835
+ function formatTableInsertLabel(template, rows, cols) {
23836
+ return template.replace("{rows}", String(rows)).replace("{cols}", String(cols));
23837
+ }
23434
23838
  var ToolbarButton = React71.forwardRef(({ onClick, onMouseDown, active, disabled, children, title, className }, ref) => {
23435
23839
  const button = /* @__PURE__ */ jsx80(
23436
23840
  "button",
23437
23841
  {
23438
23842
  ref,
23439
23843
  type: "button",
23844
+ "aria-label": title,
23440
23845
  onMouseDown: (e) => {
23441
23846
  onMouseDown?.(e);
23442
23847
  e.preventDefault();
@@ -23461,22 +23866,115 @@ var ToolbarButton = React71.forwardRef(({ onClick, onMouseDown, active, disabled
23461
23866
  });
23462
23867
  ToolbarButton.displayName = "ToolbarButton";
23463
23868
  var ToolbarDivider = () => /* @__PURE__ */ jsx80("div", { className: "w-px h-6 bg-border/50 mx-1" });
23869
+ var TableInsertGrid = ({
23870
+ insertLabel,
23871
+ previewTemplate,
23872
+ onInsert
23873
+ }) => {
23874
+ const [selection, setSelection] = React71.useState({ rows: 3, cols: 3 });
23875
+ const maxRows = 8;
23876
+ const maxCols = 8;
23877
+ return /* @__PURE__ */ jsxs67("div", { className: "mb-2 rounded-xl border border-border/60 bg-muted/20 p-2", children: [
23878
+ /* @__PURE__ */ jsx80("div", { className: "mb-2 text-sm font-medium text-foreground", children: formatTableInsertLabel(previewTemplate, selection.rows, selection.cols) }),
23879
+ /* @__PURE__ */ jsx80(
23880
+ "div",
23881
+ {
23882
+ className: "grid grid-cols-8 gap-1",
23883
+ onMouseLeave: () => setSelection((prev) => prev),
23884
+ children: Array.from({ length: maxRows }).map(
23885
+ (_, rowIndex) => Array.from({ length: maxCols }).map((__, colIndex) => {
23886
+ const rows = rowIndex + 1;
23887
+ const cols = colIndex + 1;
23888
+ const active = rows <= selection.rows && cols <= selection.cols;
23889
+ return /* @__PURE__ */ jsx80(
23890
+ "button",
23891
+ {
23892
+ type: "button",
23893
+ "aria-label": formatTableInsertLabel(previewTemplate, rows, cols),
23894
+ onMouseDown: (e) => e.preventDefault(),
23895
+ onMouseEnter: () => setSelection({ rows, cols }),
23896
+ onFocus: () => setSelection({ rows, cols }),
23897
+ onClick: () => onInsert(rows, cols),
23898
+ className: cn(
23899
+ "h-5 w-5 rounded-[4px] border transition-colors",
23900
+ active ? "border-primary bg-primary/20" : "border-border/70 bg-background hover:border-primary/60 hover:bg-primary/10"
23901
+ )
23902
+ },
23903
+ `${rows}-${cols}`
23904
+ );
23905
+ })
23906
+ )
23907
+ }
23908
+ ),
23909
+ /* @__PURE__ */ jsx80("div", { className: "mt-2 text-xs text-muted-foreground", children: insertLabel })
23910
+ ] });
23911
+ };
23464
23912
  var EditorToolbar = ({
23465
23913
  editor,
23466
23914
  variant,
23467
23915
  uploadImage,
23468
- imageInsertMode = "base64"
23916
+ imageInsertMode = "base64",
23917
+ fontFamilies,
23918
+ fontSizes,
23919
+ lineHeights,
23920
+ letterSpacings
23469
23921
  }) => {
23470
23922
  const t = useSmartTranslations("UEditor");
23471
23923
  const { textColors, highlightColors } = useEditorColors();
23472
23924
  const [showImageInput, setShowImageInput] = useState43(false);
23925
+ const [isTableMenuOpen, setIsTableMenuOpen] = useState43(false);
23926
+ const tableCommandAnchorPosRef = useRef29(null);
23473
23927
  const fileInputRef = useRef29(null);
23474
23928
  const [isUploadingImage, setIsUploadingImage] = useState43(false);
23475
23929
  const [imageUploadError, setImageUploadError] = useState43(null);
23930
+ const [fontSizeDraft, setFontSizeDraft] = useState43("");
23476
23931
  const isImageSelected = editor.isActive("image");
23477
23932
  const imageAttrs = editor.getAttributes("image");
23933
+ const tableAttrs = editor.getAttributes("table");
23934
+ const textStyleAttrs = editor.getAttributes("textStyle");
23478
23935
  const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
23479
23936
  const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
23937
+ const currentTableAlign = tableAttrs.tableAlign === "center" || tableAttrs.tableAlign === "right" ? tableAttrs.tableAlign : "left";
23938
+ const isTableSelected = editor.isActive("table");
23939
+ const hasTableContext = isTableSelected || tableCommandAnchorPosRef.current !== null;
23940
+ const currentFontFamily = normalizeStyleValue(textStyleAttrs.fontFamily);
23941
+ const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
23942
+ const currentLineHeight = normalizeStyleValue(textStyleAttrs.lineHeight);
23943
+ const currentLetterSpacing = normalizeStyleValue(textStyleAttrs.letterSpacing);
23944
+ const availableFontFamilies = React71.useMemo(
23945
+ () => fontFamilies ?? getDefaultFontFamilies(t),
23946
+ [fontFamilies, t]
23947
+ );
23948
+ const availableFontSizes = React71.useMemo(
23949
+ () => fontSizes ?? getDefaultFontSizes(),
23950
+ [fontSizes]
23951
+ );
23952
+ const availableLineHeights = React71.useMemo(
23953
+ () => lineHeights ?? getDefaultLineHeights(),
23954
+ [lineHeights]
23955
+ );
23956
+ const availableLetterSpacings = React71.useMemo(
23957
+ () => letterSpacings ?? getDefaultLetterSpacings(),
23958
+ [letterSpacings]
23959
+ );
23960
+ const currentFontFamilyLabel = availableFontFamilies.find((option) => normalizeStyleValue(option.value) === currentFontFamily)?.label ?? t("toolbar.fontDefault");
23961
+ const currentFontSizeLabel = availableFontSizes.find((option) => normalizeStyleValue(option.value) === currentFontSize)?.label ?? t("toolbar.sizeDefault");
23962
+ const currentLineHeightLabel = availableLineHeights.find((option) => normalizeStyleValue(option.value) === currentLineHeight)?.label ?? t("toolbar.lineHeightDefault");
23963
+ const currentLetterSpacingLabel = availableLetterSpacings.find((option) => normalizeStyleValue(option.value) === currentLetterSpacing)?.label ?? t("toolbar.letterSpacingDefault");
23964
+ React71.useEffect(() => {
23965
+ setFontSizeDraft(currentFontSize.replace(/px$/i, ""));
23966
+ }, [currentFontSize]);
23967
+ const applyFontSizeDraft = () => {
23968
+ const normalized = fontSizeDraft.trim();
23969
+ if (!normalized) {
23970
+ editor.chain().focus().unsetFontSize().run();
23971
+ return;
23972
+ }
23973
+ const parsed = Number.parseFloat(normalized);
23974
+ if (!Number.isFinite(parsed) || parsed <= 0) return;
23975
+ const clamped = Math.min(96, Math.max(8, parsed));
23976
+ editor.chain().focus().setFontSize(`${clamped}px`).run();
23977
+ };
23480
23978
  const insertImageFiles = async (files) => {
23481
23979
  if (files.length === 0) return;
23482
23980
  setIsUploadingImage(true);
@@ -23513,6 +24011,7 @@ var EditorToolbar = ({
23513
24011
  /* @__PURE__ */ jsxs67(
23514
24012
  DropdownMenu,
23515
24013
  {
24014
+ contentClassName: "p-2",
23516
24015
  trigger: /* @__PURE__ */ jsxs67(ToolbarButton, { onClick: () => {
23517
24016
  }, title: t("toolbar.textStyle"), className: "px-2 w-auto gap-1", children: [
23518
24017
  /* @__PURE__ */ jsx80(Type2, { className: "w-4 h-4" }),
@@ -23561,6 +24060,183 @@ var EditorToolbar = ({
23561
24060
  ]
23562
24061
  }
23563
24062
  ),
24063
+ /* @__PURE__ */ jsxs67(
24064
+ DropdownMenu,
24065
+ {
24066
+ trigger: /* @__PURE__ */ jsx80(
24067
+ ToolbarButton,
24068
+ {
24069
+ onClick: () => {
24070
+ },
24071
+ title: t("toolbar.fontFamily"),
24072
+ className: "relative",
24073
+ children: /* @__PURE__ */ jsx80(Type2, { className: "w-4 h-4" })
24074
+ }
24075
+ ),
24076
+ contentClassName: "max-h-80 overflow-y-auto min-w-56 p-2",
24077
+ children: [
24078
+ /* @__PURE__ */ jsx80(
24079
+ DropdownMenuItem,
24080
+ {
24081
+ icon: Type2,
24082
+ label: t("toolbar.fontDefault"),
24083
+ onClick: () => editor.chain().focus().unsetFontFamily().run(),
24084
+ active: !currentFontFamily
24085
+ }
24086
+ ),
24087
+ availableFontFamilies.map((option) => /* @__PURE__ */ jsx80(
24088
+ DropdownMenuItem,
24089
+ {
24090
+ label: option.label,
24091
+ onClick: () => editor.chain().focus().setFontFamily(option.value).run(),
24092
+ active: normalizeStyleValue(option.value) === currentFontFamily,
24093
+ className: "font-medium"
24094
+ },
24095
+ option.value
24096
+ ))
24097
+ ]
24098
+ }
24099
+ ),
24100
+ /* @__PURE__ */ jsxs67(
24101
+ DropdownMenu,
24102
+ {
24103
+ closeOnSelect: false,
24104
+ trigger: /* @__PURE__ */ jsx80(
24105
+ ToolbarButton,
24106
+ {
24107
+ onClick: () => {
24108
+ },
24109
+ title: t("toolbar.fontSize"),
24110
+ className: "px-2 w-auto min-w-9",
24111
+ children: /* @__PURE__ */ jsx80("span", { className: "text-[10px] font-semibold leading-none", children: currentFontSize.replace(/px$/i, "") || "T" })
24112
+ }
24113
+ ),
24114
+ contentClassName: "max-h-80 overflow-y-auto min-w-44 p-2",
24115
+ children: [
24116
+ /* @__PURE__ */ jsx80("div", { className: "mb-2 rounded-lg border border-border/60 bg-muted/30 p-2", children: /* @__PURE__ */ jsxs67("label", { className: "flex items-center gap-2", children: [
24117
+ /* @__PURE__ */ jsx80(
24118
+ "input",
24119
+ {
24120
+ type: "number",
24121
+ min: 8,
24122
+ max: 96,
24123
+ step: 1,
24124
+ value: fontSizeDraft,
24125
+ onChange: (e) => setFontSizeDraft(e.target.value),
24126
+ onMouseDown: (e) => e.stopPropagation(),
24127
+ onClick: (e) => e.stopPropagation(),
24128
+ onKeyDown: (e) => {
24129
+ e.stopPropagation();
24130
+ if (e.key === "Enter") {
24131
+ e.preventDefault();
24132
+ applyFontSizeDraft();
24133
+ }
24134
+ },
24135
+ "aria-label": t("toolbar.fontSize"),
24136
+ className: "h-8 w-full rounded-md border border-border bg-background px-2 text-sm outline-none focus:ring-2 focus:ring-primary/20"
24137
+ }
24138
+ ),
24139
+ /* @__PURE__ */ jsx80("span", { className: "text-xs text-muted-foreground", children: "px" })
24140
+ ] }) }),
24141
+ /* @__PURE__ */ jsx80(
24142
+ DropdownMenuItem,
24143
+ {
24144
+ icon: Type2,
24145
+ label: t("toolbar.sizeDefault"),
24146
+ onClick: () => editor.chain().focus().unsetFontSize().run(),
24147
+ active: !currentFontSize
24148
+ }
24149
+ ),
24150
+ availableFontSizes.map((option) => /* @__PURE__ */ jsx80(
24151
+ DropdownMenuItem,
24152
+ {
24153
+ label: option.label,
24154
+ onClick: () => editor.chain().focus().setFontSize(option.value).run(),
24155
+ active: normalizeStyleValue(option.value) === currentFontSize
24156
+ },
24157
+ option.value
24158
+ ))
24159
+ ]
24160
+ }
24161
+ ),
24162
+ /* @__PURE__ */ jsxs67(
24163
+ DropdownMenu,
24164
+ {
24165
+ trigger: /* @__PURE__ */ jsxs67(
24166
+ ToolbarButton,
24167
+ {
24168
+ onClick: () => {
24169
+ },
24170
+ title: t("toolbar.lineHeight"),
24171
+ className: "gap-0.5",
24172
+ children: [
24173
+ /* @__PURE__ */ jsx80(ArrowUp, { className: "w-3 h-3" }),
24174
+ /* @__PURE__ */ jsx80(ArrowDown, { className: "w-3 h-3" })
24175
+ ]
24176
+ }
24177
+ ),
24178
+ contentClassName: "max-h-72 overflow-y-auto p-2",
24179
+ children: [
24180
+ /* @__PURE__ */ jsx80(
24181
+ DropdownMenuItem,
24182
+ {
24183
+ icon: Type2,
24184
+ label: t("toolbar.lineHeightDefault"),
24185
+ onClick: () => editor.chain().focus().unsetLineHeight().run(),
24186
+ active: !currentLineHeight
24187
+ }
24188
+ ),
24189
+ availableLineHeights.map((option) => /* @__PURE__ */ jsx80(
24190
+ DropdownMenuItem,
24191
+ {
24192
+ label: option.label,
24193
+ onClick: () => editor.chain().focus().setLineHeight(option.value).run(),
24194
+ active: normalizeStyleValue(option.value) === currentLineHeight
24195
+ },
24196
+ option.value
24197
+ ))
24198
+ ]
24199
+ }
24200
+ ),
24201
+ /* @__PURE__ */ jsxs67(
24202
+ DropdownMenu,
24203
+ {
24204
+ trigger: /* @__PURE__ */ jsxs67(
24205
+ ToolbarButton,
24206
+ {
24207
+ onClick: () => {
24208
+ },
24209
+ title: t("toolbar.letterSpacing"),
24210
+ className: "gap-0.5",
24211
+ children: [
24212
+ /* @__PURE__ */ jsx80(ArrowLeft, { className: "w-3 h-3" }),
24213
+ /* @__PURE__ */ jsx80(ArrowRight, { className: "w-3 h-3" })
24214
+ ]
24215
+ }
24216
+ ),
24217
+ contentClassName: "max-h-72 overflow-y-auto p-2",
24218
+ children: [
24219
+ /* @__PURE__ */ jsx80(
24220
+ DropdownMenuItem,
24221
+ {
24222
+ icon: Type2,
24223
+ label: t("toolbar.letterSpacingDefault"),
24224
+ onClick: () => editor.chain().focus().unsetLetterSpacing().run(),
24225
+ active: !currentLetterSpacing
24226
+ }
24227
+ ),
24228
+ availableLetterSpacings.map((option) => /* @__PURE__ */ jsx80(
24229
+ DropdownMenuItem,
24230
+ {
24231
+ label: option.label,
24232
+ onClick: () => editor.chain().focus().setLetterSpacing(option.value).run(),
24233
+ active: normalizeStyleValue(option.value) === currentLetterSpacing
24234
+ },
24235
+ option.value
24236
+ ))
24237
+ ]
24238
+ }
24239
+ ),
23564
24240
  /* @__PURE__ */ jsx80(ToolbarDivider, {}),
23565
24241
  /* @__PURE__ */ jsx80(ToolbarButton, { onClick: () => editor.chain().focus().toggleBold().run(), active: editor.isActive("bold"), title: t("toolbar.bold"), children: /* @__PURE__ */ jsx80(BoldIcon, { className: "w-4 h-4" }) }),
23566
24242
  /* @__PURE__ */ jsx80(ToolbarButton, { onClick: () => editor.chain().focus().toggleItalic().run(), active: editor.isActive("italic"), title: t("toolbar.italic"), children: /* @__PURE__ */ jsx80(ItalicIcon, { className: "w-4 h-4" }) }),
@@ -23630,6 +24306,7 @@ var EditorToolbar = ({
23630
24306
  /* @__PURE__ */ jsx80(
23631
24307
  DropdownMenu,
23632
24308
  {
24309
+ contentClassName: "p-0 overflow-hidden",
23633
24310
  trigger: /* @__PURE__ */ jsx80(ToolbarButton, { onClick: () => {
23634
24311
  }, title: t("toolbar.emoji"), children: /* @__PURE__ */ jsx80(Smile3, { className: "w-4 h-4" }) }),
23635
24312
  children: /* @__PURE__ */ jsx80(
@@ -23895,18 +24572,58 @@ var EditorToolbar = ({
23895
24572
  /* @__PURE__ */ jsxs67(
23896
24573
  DropdownMenu,
23897
24574
  {
24575
+ isOpen: isTableMenuOpen,
24576
+ onOpenChange: (open) => {
24577
+ setIsTableMenuOpen(open);
24578
+ tableCommandAnchorPosRef.current = open && editor.isActive("table") ? editor.state.selection.$from.pos : null;
24579
+ },
23898
24580
  trigger: /* @__PURE__ */ jsxs67(ToolbarButton, { onClick: () => {
23899
24581
  }, title: t("toolbar.table"), children: [
23900
24582
  /* @__PURE__ */ jsx80(TableIcon, { className: "w-4 h-4" }),
23901
24583
  /* @__PURE__ */ jsx80(ChevronDown7, { className: "w-3 h-3" })
23902
24584
  ] }),
24585
+ contentClassName: "p-2 min-w-56",
23903
24586
  children: [
24587
+ /* @__PURE__ */ jsx80(
24588
+ TableInsertGrid,
24589
+ {
24590
+ insertLabel: t("tableMenu.insertTable"),
24591
+ previewTemplate: t("tableMenu.gridPreview"),
24592
+ onInsert: (rows, cols) => {
24593
+ editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
24594
+ setIsTableMenuOpen(false);
24595
+ }
24596
+ }
24597
+ ),
24598
+ /* @__PURE__ */ jsx80("div", { className: "my-1 border-t" }),
23904
24599
  /* @__PURE__ */ jsx80(
23905
24600
  DropdownMenuItem,
23906
24601
  {
23907
- icon: TableIcon,
23908
- label: t("tableMenu.insert3x3"),
23909
- onClick: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()
24602
+ icon: AlignLeft,
24603
+ label: t("tableMenu.alignLeft"),
24604
+ onClick: () => applyTableAlignment(editor, "left", tableCommandAnchorPosRef.current ?? void 0),
24605
+ active: hasTableContext && currentTableAlign === "left",
24606
+ disabled: !hasTableContext
24607
+ }
24608
+ ),
24609
+ /* @__PURE__ */ jsx80(
24610
+ DropdownMenuItem,
24611
+ {
24612
+ icon: AlignCenter,
24613
+ label: t("tableMenu.alignCenter"),
24614
+ onClick: () => applyTableAlignment(editor, "center", tableCommandAnchorPosRef.current ?? void 0),
24615
+ active: hasTableContext && currentTableAlign === "center",
24616
+ disabled: !hasTableContext
24617
+ }
24618
+ ),
24619
+ /* @__PURE__ */ jsx80(
24620
+ DropdownMenuItem,
24621
+ {
24622
+ icon: AlignRight,
24623
+ label: t("tableMenu.alignRight"),
24624
+ onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPosRef.current ?? void 0),
24625
+ active: hasTableContext && currentTableAlign === "right",
24626
+ disabled: !hasTableContext
23910
24627
  }
23911
24628
  ),
23912
24629
  /* @__PURE__ */ jsx80("div", { className: "my-1 border-t" }),
@@ -23916,7 +24633,7 @@ var EditorToolbar = ({
23916
24633
  icon: ArrowLeft,
23917
24634
  label: t("tableMenu.addColumnBefore"),
23918
24635
  onClick: () => editor.chain().focus().addColumnBefore().run(),
23919
- disabled: !editor.can().addColumnBefore()
24636
+ disabled: !hasTableContext || !editor.can().addColumnBefore()
23920
24637
  }
23921
24638
  ),
23922
24639
  /* @__PURE__ */ jsx80(
@@ -23925,7 +24642,7 @@ var EditorToolbar = ({
23925
24642
  icon: ArrowDown,
23926
24643
  label: t("tableMenu.addColumnAfter"),
23927
24644
  onClick: () => editor.chain().focus().addColumnAfter().run(),
23928
- disabled: !editor.can().addColumnAfter()
24645
+ disabled: !hasTableContext || !editor.can().addColumnAfter()
23929
24646
  }
23930
24647
  ),
23931
24648
  /* @__PURE__ */ jsx80(
@@ -23934,7 +24651,7 @@ var EditorToolbar = ({
23934
24651
  icon: ArrowUp,
23935
24652
  label: t("tableMenu.addRowBefore"),
23936
24653
  onClick: () => editor.chain().focus().addRowBefore().run(),
23937
- disabled: !editor.can().addRowBefore()
24654
+ disabled: !hasTableContext || !editor.can().addRowBefore()
23938
24655
  }
23939
24656
  ),
23940
24657
  /* @__PURE__ */ jsx80(
@@ -23943,7 +24660,7 @@ var EditorToolbar = ({
23943
24660
  icon: ArrowRight,
23944
24661
  label: t("tableMenu.addRowAfter"),
23945
24662
  onClick: () => editor.chain().focus().addRowAfter().run(),
23946
- disabled: !editor.can().addRowAfter()
24663
+ disabled: !hasTableContext || !editor.can().addRowAfter()
23947
24664
  }
23948
24665
  ),
23949
24666
  /* @__PURE__ */ jsx80("div", { className: "my-1 border-t" }),
@@ -23953,7 +24670,7 @@ var EditorToolbar = ({
23953
24670
  icon: TableIcon,
23954
24671
  label: t("tableMenu.toggleHeaderRow"),
23955
24672
  onClick: () => editor.chain().focus().toggleHeaderRow().run(),
23956
- disabled: !editor.can().toggleHeaderRow()
24673
+ disabled: !hasTableContext || !editor.can().toggleHeaderRow()
23957
24674
  }
23958
24675
  ),
23959
24676
  /* @__PURE__ */ jsx80(
@@ -23962,7 +24679,7 @@ var EditorToolbar = ({
23962
24679
  icon: TableIcon,
23963
24680
  label: t("tableMenu.toggleHeaderColumn"),
23964
24681
  onClick: () => editor.chain().focus().toggleHeaderColumn().run(),
23965
- disabled: !editor.can().toggleHeaderColumn()
24682
+ disabled: !hasTableContext || !editor.can().toggleHeaderColumn()
23966
24683
  }
23967
24684
  ),
23968
24685
  /* @__PURE__ */ jsx80("div", { className: "my-1 border-t" }),
@@ -23972,7 +24689,7 @@ var EditorToolbar = ({
23972
24689
  icon: Trash22,
23973
24690
  label: t("tableMenu.deleteColumn"),
23974
24691
  onClick: () => editor.chain().focus().deleteColumn().run(),
23975
- disabled: !editor.can().deleteColumn()
24692
+ disabled: !hasTableContext || !editor.can().deleteColumn()
23976
24693
  }
23977
24694
  ),
23978
24695
  /* @__PURE__ */ jsx80(
@@ -23981,7 +24698,7 @@ var EditorToolbar = ({
23981
24698
  icon: Trash22,
23982
24699
  label: t("tableMenu.deleteRow"),
23983
24700
  onClick: () => editor.chain().focus().deleteRow().run(),
23984
- disabled: !editor.can().deleteRow()
24701
+ disabled: !hasTableContext || !editor.can().deleteRow()
23985
24702
  }
23986
24703
  ),
23987
24704
  /* @__PURE__ */ jsx80(
@@ -23990,7 +24707,7 @@ var EditorToolbar = ({
23990
24707
  icon: Trash22,
23991
24708
  label: t("tableMenu.deleteTable"),
23992
24709
  onClick: () => editor.chain().focus().deleteTable().run(),
23993
- disabled: !editor.can().deleteTable()
24710
+ disabled: !hasTableContext || !editor.can().deleteTable()
23994
24711
  }
23995
24712
  )
23996
24713
  ]
@@ -24096,7 +24813,9 @@ var FloatingMenuContent = ({ editor }) => {
24096
24813
  };
24097
24814
  var BubbleMenuContent = ({
24098
24815
  editor,
24099
- onKeepOpenChange
24816
+ onKeepOpenChange,
24817
+ fontSizes,
24818
+ lineHeights
24100
24819
  }) => {
24101
24820
  const t = useSmartTranslations("UEditor");
24102
24821
  const { textColors, highlightColors } = useEditorColors();
@@ -24106,6 +24825,17 @@ var BubbleMenuContent = ({
24106
24825
  const imageAttrs = editor.getAttributes("image");
24107
24826
  const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
24108
24827
  const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
24828
+ const textStyleAttrs = editor.getAttributes("textStyle");
24829
+ const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
24830
+ const currentLineHeight = normalizeStyleValue(textStyleAttrs.lineHeight);
24831
+ const quickFontSizes = useMemo23(
24832
+ () => (fontSizes ?? getDefaultFontSizes()).filter((option) => ["14px", "16px", "24px"].includes(option.value)),
24833
+ [fontSizes]
24834
+ );
24835
+ const quickLineHeights = useMemo23(
24836
+ () => (lineHeights ?? getDefaultLineHeights()).filter((option) => ["1.2", "1.5", "1.75"].includes(option.value)),
24837
+ [lineHeights]
24838
+ );
24109
24839
  useEffect33(() => {
24110
24840
  onKeepOpenChange?.(showLinkInput);
24111
24841
  }, [onKeepOpenChange, showLinkInput]);
@@ -24225,6 +24955,50 @@ var BubbleMenuContent = ({
24225
24955
  ),
24226
24956
  /* @__PURE__ */ jsx81(ToolbarButton, { onClick: () => setShowEditorColorPalette(true), title: t("colors.textColor"), children: /* @__PURE__ */ jsx81(Palette3, { className: "w-4 h-4" }) }),
24227
24957
  /* @__PURE__ */ jsx81("div", { className: "w-px h-6 bg-border/50 mx-1" }),
24958
+ /* @__PURE__ */ jsx81(
24959
+ ToolbarButton,
24960
+ {
24961
+ onClick: () => editor.chain().focus().unsetFontSize().run(),
24962
+ active: !currentFontSize,
24963
+ title: t("toolbar.sizeDefault"),
24964
+ className: "px-2 w-auto",
24965
+ children: /* @__PURE__ */ jsx81("span", { className: "text-[10px] font-semibold", children: "A" })
24966
+ }
24967
+ ),
24968
+ quickFontSizes.map((option) => /* @__PURE__ */ jsx81(
24969
+ ToolbarButton,
24970
+ {
24971
+ onClick: () => editor.chain().focus().setFontSize(option.value).run(),
24972
+ active: normalizeStyleValue(option.value) === currentFontSize,
24973
+ title: `${t("toolbar.fontSize")} ${option.label}`,
24974
+ className: "px-2 w-auto",
24975
+ children: /* @__PURE__ */ jsx81("span", { className: "text-[10px] font-semibold", children: option.label })
24976
+ },
24977
+ option.value
24978
+ )),
24979
+ /* @__PURE__ */ jsx81("div", { className: "w-px h-6 bg-border/50 mx-1" }),
24980
+ /* @__PURE__ */ jsx81(
24981
+ ToolbarButton,
24982
+ {
24983
+ onClick: () => editor.chain().focus().unsetLineHeight().run(),
24984
+ active: !currentLineHeight,
24985
+ title: t("toolbar.lineHeightDefault"),
24986
+ className: "px-2 w-auto",
24987
+ children: /* @__PURE__ */ jsx81("span", { className: "text-[10px] font-semibold leading-none", children: "LH" })
24988
+ }
24989
+ ),
24990
+ quickLineHeights.map((option) => /* @__PURE__ */ jsx81(
24991
+ ToolbarButton,
24992
+ {
24993
+ onClick: () => editor.chain().focus().setLineHeight(option.value).run(),
24994
+ active: normalizeStyleValue(option.value) === currentLineHeight,
24995
+ title: `${t("toolbar.lineHeight")} ${option.label}`,
24996
+ className: "px-2 w-auto",
24997
+ children: /* @__PURE__ */ jsx81("span", { className: "text-[10px] font-semibold", children: option.label })
24998
+ },
24999
+ option.value
25000
+ )),
25001
+ /* @__PURE__ */ jsx81("div", { className: "w-px h-6 bg-border/50 mx-1" }),
24228
25002
  /* @__PURE__ */ jsx81(
24229
25003
  ToolbarButton,
24230
25004
  {
@@ -24245,8 +25019,13 @@ var BubbleMenuContent = ({
24245
25019
  )
24246
25020
  ] });
24247
25021
  };
24248
- var CustomBubbleMenu = ({ editor }) => {
25022
+ var CustomBubbleMenu = ({
25023
+ editor,
25024
+ fontSizes,
25025
+ lineHeights
25026
+ }) => {
24249
25027
  const SHOW_DELAY_MS = 180;
25028
+ const BUBBLE_MENU_OFFSET = 16;
24250
25029
  const [isVisible, setIsVisible] = useState44(false);
24251
25030
  const [position, setPosition] = useState44({ top: 0, left: 0 });
24252
25031
  const menuRef = useRef30(null);
@@ -24274,7 +25053,7 @@ var CustomBubbleMenu = ({ editor }) => {
24274
25053
  const start = view.coordsAtPos(from);
24275
25054
  const end = view.coordsAtPos(to);
24276
25055
  const left = (start.left + end.left) / 2;
24277
- const top = start.top - 10;
25056
+ const top = start.top - BUBBLE_MENU_OFFSET;
24278
25057
  setPosition({ top, left });
24279
25058
  if (keepOpenRef.current) {
24280
25059
  clearShowTimeout();
@@ -24320,7 +25099,9 @@ var CustomBubbleMenu = ({ editor }) => {
24320
25099
  BubbleMenuContent,
24321
25100
  {
24322
25101
  editor,
24323
- onKeepOpenChange: setKeepOpen
25102
+ onKeepOpenChange: setKeepOpen,
25103
+ fontSizes,
25104
+ lineHeights
24324
25105
  }
24325
25106
  )
24326
25107
  }
@@ -24329,6 +25110,7 @@ var CustomBubbleMenu = ({ editor }) => {
24329
25110
  );
24330
25111
  };
24331
25112
  var CustomFloatingMenu = ({ editor }) => {
25113
+ const FLOATING_MENU_OFFSET = 16;
24332
25114
  const [isVisible, setIsVisible] = useState44(false);
24333
25115
  const [position, setPosition] = useState44({ top: 0, left: 0 });
24334
25116
  useEffect33(() => {
@@ -24341,7 +25123,7 @@ var CustomFloatingMenu = ({ editor }) => {
24341
25123
  return;
24342
25124
  }
24343
25125
  const coords = view.coordsAtPos($from.pos);
24344
- setPosition({ top: coords.top - 10, left: coords.left });
25126
+ setPosition({ top: coords.top - FLOATING_MENU_OFFSET, left: coords.left });
24345
25127
  setIsVisible(true);
24346
25128
  };
24347
25129
  const handleBlur = () => setIsVisible(false);
@@ -28811,6 +29593,9 @@ var columnResizingPluginKey = new PluginKey3("tableColumnResizing");
28811
29593
 
28812
29594
  // src/components/UEditor/table-controls.tsx
28813
29595
  import {
29596
+ AlignCenter as AlignCenter3,
29597
+ AlignLeft as AlignLeft3,
29598
+ AlignRight as AlignRight3,
28814
29599
  ArrowDown as ArrowDown2,
28815
29600
  ArrowLeft as ArrowLeft2,
28816
29601
  ArrowRight as ArrowRight2,
@@ -28828,9 +29613,16 @@ var FALLBACK_TABLE_COLUMN_WIDTH = 160;
28828
29613
  var MENU_HOVER_PADDING = 18;
28829
29614
  var ROW_HANDLE_HOVER_WIDTH = 28;
28830
29615
  var COLUMN_HANDLE_HOVER_HEIGHT = 28;
29616
+ var ROW_HANDLE_GUTTER = 20;
29617
+ var TABLE_MENU_TOP_OFFSET = 10;
29618
+ var COLUMN_HANDLE_TOP_OFFSET = 8;
29619
+ var ADD_COLUMN_RAIL_GAP = 4;
29620
+ var ADD_ROW_RAIL_GAP = 4;
28831
29621
  var ADD_COLUMN_HOVER_WIDTH = 24;
28832
29622
  var ADD_ROW_HOVER_HEIGHT = 24;
28833
29623
  var HANDLE_HOVER_RADIUS = 14;
29624
+ var IDLE_HANDLE_OPACITY = "0.4";
29625
+ var IDLE_HANDLE_SCALE = "0.78";
28834
29626
  var DEFAULT_HOVER_STATE = {
28835
29627
  menuVisible: false,
28836
29628
  addColumnVisible: false,
@@ -29072,8 +29864,8 @@ function TableControls({ editor, containerRef }) {
29072
29864
  const rowHandleIndex = Number.isFinite(directRowHandleIndex) ? directRowHandleIndex : activeLayout.rowHandles.find((rowHandle) => relativeX >= activeLayout.tableLeft - ROW_HANDLE_HOVER_WIDTH && relativeX <= activeLayout.tableLeft && Math.abs(relativeY - rowHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
29073
29865
  const columnHandleIndex = Number.isFinite(directColumnHandleIndex) ? directColumnHandleIndex : activeLayout.columnHandles.find((columnHandle) => relativeY >= activeLayout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= activeLayout.tableTop && Math.abs(relativeX - columnHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
29074
29866
  const menuVisible = Boolean(directTableMenu) || relativeX >= activeLayout.tableLeft - MENU_HOVER_PADDING && relativeX <= activeLayout.tableLeft + 42 && relativeY >= activeLayout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= activeLayout.tableTop + MENU_HOVER_PADDING;
29075
- const addColumnVisible = Boolean(directAddColumn) || relativeX >= activeLayout.wrapperLeft + visibleTableWidth2 && relativeX <= activeLayout.wrapperLeft + visibleTableWidth2 + ADD_COLUMN_HOVER_WIDTH && relativeY >= activeLayout.wrapperTop && relativeY <= activeLayout.wrapperTop + visibleTableHeight2;
29076
- const addRowVisible = Boolean(directAddRow) || relativeY >= activeLayout.wrapperTop + activeLayout.wrapperHeight && relativeY <= activeLayout.wrapperTop + activeLayout.wrapperHeight + ADD_ROW_HOVER_HEIGHT && relativeX >= activeLayout.wrapperLeft && relativeX <= activeLayout.wrapperLeft + visibleTableWidth2;
29867
+ const addColumnVisible = Boolean(directAddColumn) || relativeX >= activeLayout.tableLeft + visibleTableWidth2 && relativeX <= activeLayout.tableLeft + visibleTableWidth2 + ADD_COLUMN_HOVER_WIDTH && relativeY >= activeLayout.tableTop && relativeY <= activeLayout.tableTop + visibleTableHeight2;
29868
+ const addRowVisible = Boolean(directAddRow) || relativeY >= activeLayout.tableTop + visibleTableHeight2 && relativeY <= activeLayout.tableTop + visibleTableHeight2 + ADD_ROW_HOVER_HEIGHT && relativeX >= activeLayout.tableLeft && relativeX <= activeLayout.tableLeft + visibleTableWidth2;
29077
29869
  setHoverState((prev) => {
29078
29870
  if (prev.menuVisible === menuVisible && prev.addColumnVisible === addColumnVisible && prev.addRowVisible === addRowVisible && prev.rowHandleIndex === rowHandleIndex && prev.columnHandleIndex === columnHandleIndex) {
29079
29871
  return prev;
@@ -29313,6 +30105,21 @@ function TableControls({ editor, containerRef }) {
29313
30105
  const menuItems = React73.useMemo(() => {
29314
30106
  if (!layout) return [];
29315
30107
  return [
30108
+ {
30109
+ label: t("tableMenu.alignLeft"),
30110
+ icon: AlignLeft3,
30111
+ onClick: () => applyTableAlignment(editor, "left", layout.cellPos)
30112
+ },
30113
+ {
30114
+ label: t("tableMenu.alignCenter"),
30115
+ icon: AlignCenter3,
30116
+ onClick: () => applyTableAlignment(editor, "center", layout.cellPos)
30117
+ },
30118
+ {
30119
+ label: t("tableMenu.alignRight"),
30120
+ icon: AlignRight3,
30121
+ onClick: () => applyTableAlignment(editor, "right", layout.cellPos)
30122
+ },
29316
30123
  {
29317
30124
  label: t("tableMenu.addColumnBefore"),
29318
30125
  icon: ArrowLeft2,
@@ -29422,16 +30229,16 @@ function TableControls({ editor, containerRef }) {
29422
30229
  if (!layout) {
29423
30230
  return null;
29424
30231
  }
29425
- const menuTop = Math.max(8, layout.tableTop - 16);
30232
+ const menuTop = Math.max(8, layout.tableTop - TABLE_MENU_TOP_OFFSET);
29426
30233
  const menuLeft = Math.max(8, layout.tableLeft);
29427
- const rowHandleLeft = Math.max(8, layout.tableLeft - 66);
29428
- const columnHandleTop = Math.max(8, layout.tableTop - 14);
30234
+ const rowHandleLeft = Math.max(8, layout.tableLeft - ROW_HANDLE_GUTTER);
30235
+ const columnHandleTop = Math.max(8, layout.tableTop - COLUMN_HANDLE_TOP_OFFSET);
29429
30236
  const visibleTableWidth = Math.min(layout.tableWidth, layout.viewportWidth);
29430
30237
  const visibleTableHeight = Math.min(layout.tableHeight, layout.viewportHeight);
29431
- const columnRailTop = layout.wrapperTop;
29432
- const columnRailLeft = layout.wrapperLeft + visibleTableWidth + 8;
29433
- const rowRailTop = layout.wrapperTop + layout.wrapperHeight + 8;
29434
- const rowRailLeft = layout.wrapperLeft;
30238
+ const columnRailTop = layout.tableTop;
30239
+ const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
30240
+ const rowRailTop = layout.tableTop + visibleTableHeight + ADD_ROW_RAIL_GAP;
30241
+ const rowRailLeft = layout.tableLeft;
29435
30242
  const expandPreviewWidth = dragPreview?.kind === "add-column" ? layout.tableWidth + dragPreview.previewCols * layout.avgColumnWidth : layout.tableWidth;
29436
30243
  const expandPreviewHeight = dragPreview?.kind === "add-row" ? layout.tableHeight + dragPreview.previewRows * layout.avgRowHeight : layout.tableHeight;
29437
30244
  const dragStatusText = dragPreview?.kind === "row" ? `${t("tableMenu.dragRow")} ${dragPreview.originIndex + 1} -> ${dragPreview.targetIndex + 1}` : dragPreview?.kind === "column" ? `${t("tableMenu.dragColumn")} ${dragPreview.originIndex + 1} -> ${dragPreview.targetIndex + 1}` : dragPreview?.kind === "add-row" ? `+${dragPreview.previewRows}R` : dragPreview?.kind === "add-column" ? `+${dragPreview.previewCols}C` : null;
@@ -29439,7 +30246,6 @@ function TableControls({ editor, containerRef }) {
29439
30246
  layout.rowHandles.map((rowHandle) => {
29440
30247
  const menuKey = getRowMenuKey(rowHandle.index);
29441
30248
  const visible = controlsVisible || hoverState.rowHandleIndex === rowHandle.index || openMenuKey === menuKey;
29442
- if (!visible) return null;
29443
30249
  return /* @__PURE__ */ jsx82(
29444
30250
  "div",
29445
30251
  {
@@ -29453,6 +30259,7 @@ function TableControls({ editor, containerRef }) {
29453
30259
  Tooltip,
29454
30260
  {
29455
30261
  placement: "right",
30262
+ disabled: openMenuKey === menuKey,
29456
30263
  content: /* @__PURE__ */ jsx82("span", { className: "text-xs font-medium", children: `${t("tableMenu.dragRow")} ${rowHandle.index + 1}` }),
29457
30264
  children: /* @__PURE__ */ jsx82("span", { className: "inline-flex", children: /* @__PURE__ */ jsx82(
29458
30265
  DropdownMenu,
@@ -29462,6 +30269,7 @@ function TableControls({ editor, containerRef }) {
29462
30269
  onOpenChange: (open) => {
29463
30270
  setOpenMenuKey((prev) => open ? menuKey : prev === menuKey ? null : prev);
29464
30271
  },
30272
+ contentClassName: "p-2",
29465
30273
  items: getRowHandleMenuItems(rowHandle),
29466
30274
  trigger: /* @__PURE__ */ jsx82(
29467
30275
  "button",
@@ -29490,8 +30298,13 @@ function TableControls({ editor, containerRef }) {
29490
30298
  className: cn(
29491
30299
  "inline-flex h-6 w-6 items-center justify-center rounded-full",
29492
30300
  "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
30301
+ "cursor-grab active:cursor-grabbing",
29493
30302
  "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29494
30303
  ),
30304
+ style: {
30305
+ opacity: visible ? 1 : Number(IDLE_HANDLE_OPACITY),
30306
+ transform: visible ? "scale(1)" : `scale(${IDLE_HANDLE_SCALE})`
30307
+ },
29495
30308
  children: /* @__PURE__ */ jsx82(GripVertical3, { className: "h-3.5 w-3.5" })
29496
30309
  }
29497
30310
  )
@@ -29506,7 +30319,6 @@ function TableControls({ editor, containerRef }) {
29506
30319
  layout.columnHandles.map((columnHandle) => {
29507
30320
  const menuKey = getColumnMenuKey(columnHandle.index);
29508
30321
  const visible = controlsVisible || hoverState.columnHandleIndex === columnHandle.index || openMenuKey === menuKey;
29509
- if (!visible) return null;
29510
30322
  return /* @__PURE__ */ jsx82(
29511
30323
  "div",
29512
30324
  {
@@ -29520,6 +30332,7 @@ function TableControls({ editor, containerRef }) {
29520
30332
  Tooltip,
29521
30333
  {
29522
30334
  placement: "top",
30335
+ disabled: openMenuKey === menuKey,
29523
30336
  content: /* @__PURE__ */ jsx82("span", { className: "text-xs font-medium", children: `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}` }),
29524
30337
  children: /* @__PURE__ */ jsx82("span", { className: "inline-flex", children: /* @__PURE__ */ jsx82(
29525
30338
  DropdownMenu,
@@ -29529,6 +30342,7 @@ function TableControls({ editor, containerRef }) {
29529
30342
  onOpenChange: (open) => {
29530
30343
  setOpenMenuKey((prev) => open ? menuKey : prev === menuKey ? null : prev);
29531
30344
  },
30345
+ contentClassName: "p-2",
29532
30346
  items: getColumnHandleMenuItems(columnHandle),
29533
30347
  trigger: /* @__PURE__ */ jsx82(
29534
30348
  "button",
@@ -29557,8 +30371,13 @@ function TableControls({ editor, containerRef }) {
29557
30371
  className: cn(
29558
30372
  "inline-flex h-6 w-6 items-center justify-center rounded-full",
29559
30373
  "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
30374
+ "cursor-grab active:cursor-grabbing",
29560
30375
  "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29561
30376
  ),
30377
+ style: {
30378
+ opacity: visible ? 1 : Number(IDLE_HANDLE_OPACITY),
30379
+ transform: visible ? "scale(1)" : `scale(${IDLE_HANDLE_SCALE})`
30380
+ },
29562
30381
  children: /* @__PURE__ */ jsx82(GripHorizontal, { className: "h-3.5 w-3.5" })
29563
30382
  }
29564
30383
  )
@@ -29570,7 +30389,7 @@ function TableControls({ editor, containerRef }) {
29570
30389
  `column-handle-${columnHandle.index}`
29571
30390
  );
29572
30391
  }),
29573
- (controlsVisible || hoverState.menuVisible || tableMenuOpen) && /* @__PURE__ */ jsx82(
30392
+ /* @__PURE__ */ jsx82(
29574
30393
  "div",
29575
30394
  {
29576
30395
  className: "absolute z-30",
@@ -29583,6 +30402,7 @@ function TableControls({ editor, containerRef }) {
29583
30402
  Tooltip,
29584
30403
  {
29585
30404
  placement: "top",
30405
+ disabled: tableMenuOpen,
29586
30406
  content: /* @__PURE__ */ jsx82("span", { className: "text-xs font-medium", children: t("tableMenu.openControls") }),
29587
30407
  children: /* @__PURE__ */ jsx82("span", { className: "inline-flex", children: /* @__PURE__ */ jsx82(
29588
30408
  DropdownMenu,
@@ -29592,6 +30412,7 @@ function TableControls({ editor, containerRef }) {
29592
30412
  onOpenChange: (open) => {
29593
30413
  setOpenMenuKey((prev) => open ? "table" : prev === "table" ? null : prev);
29594
30414
  },
30415
+ contentClassName: "p-2",
29595
30416
  items: menuItems,
29596
30417
  trigger: /* @__PURE__ */ jsx82(
29597
30418
  "button",
@@ -29604,6 +30425,10 @@ function TableControls({ editor, containerRef }) {
29604
30425
  "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29605
30426
  "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29606
30427
  ),
30428
+ style: {
30429
+ opacity: controlsVisible || hoverState.menuVisible || tableMenuOpen ? 1 : 0.5,
30430
+ transform: controlsVisible || hoverState.menuVisible || tableMenuOpen ? "scale(1)" : "scale(0.82)"
30431
+ },
29607
30432
  children: /* @__PURE__ */ jsx82(MoreHorizontal2, { className: "h-4 w-4" })
29608
30433
  }
29609
30434
  )
@@ -29613,7 +30438,7 @@ function TableControls({ editor, containerRef }) {
29613
30438
  )
29614
30439
  }
29615
30440
  ),
29616
- (controlsVisible || hoverState.addColumnVisible) && /* @__PURE__ */ jsx82(
30441
+ /* @__PURE__ */ jsx82(
29617
30442
  Tooltip,
29618
30443
  {
29619
30444
  placement: "right",
@@ -29640,17 +30465,19 @@ function TableControls({ editor, containerRef }) {
29640
30465
  "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29641
30466
  ),
29642
30467
  style: {
29643
- top: columnRailTop,
30468
+ top: controlsVisible || hoverState.addColumnVisible ? columnRailTop : columnRailTop + Math.max(0, visibleTableHeight / 2 - 24),
29644
30469
  left: columnRailLeft,
29645
- width: 18,
29646
- height: visibleTableHeight
30470
+ width: controlsVisible || hoverState.addColumnVisible ? 18 : 12,
30471
+ height: controlsVisible || hoverState.addColumnVisible ? visibleTableHeight : 48,
30472
+ opacity: controlsVisible || hoverState.addColumnVisible ? 1 : 0.45,
30473
+ transform: controlsVisible || hoverState.addColumnVisible ? "scale(1)" : "scale(0.92)"
29647
30474
  },
29648
30475
  children: /* @__PURE__ */ jsx82("span", { className: "text-sm font-medium leading-none", children: "+" })
29649
30476
  }
29650
30477
  )
29651
30478
  }
29652
30479
  ),
29653
- (controlsVisible || hoverState.addRowVisible) && /* @__PURE__ */ jsx82(
30480
+ /* @__PURE__ */ jsx82(
29654
30481
  Tooltip,
29655
30482
  {
29656
30483
  placement: "bottom",
@@ -29678,9 +30505,11 @@ function TableControls({ editor, containerRef }) {
29678
30505
  ),
29679
30506
  style: {
29680
30507
  top: rowRailTop,
29681
- left: rowRailLeft,
29682
- width: visibleTableWidth,
29683
- height: 16
30508
+ left: controlsVisible || hoverState.addRowVisible ? rowRailLeft : rowRailLeft + Math.max(0, visibleTableWidth / 2 - 24),
30509
+ width: controlsVisible || hoverState.addRowVisible ? visibleTableWidth : 48,
30510
+ height: controlsVisible || hoverState.addRowVisible ? 16 : 12,
30511
+ opacity: controlsVisible || hoverState.addRowVisible ? 1 : 0.45,
30512
+ transform: controlsVisible || hoverState.addRowVisible ? "scale(1)" : "scale(0.92)"
29684
30513
  },
29685
30514
  children: /* @__PURE__ */ jsx82("span", { className: "text-sm font-medium leading-none", children: "+" })
29686
30515
  }
@@ -29867,6 +30696,32 @@ function getRelativeCellMetrics(surface, cell) {
29867
30696
  height: cellRect.height
29868
30697
  };
29869
30698
  }
30699
+ function getRelativeSelectedCellsMetrics(surface) {
30700
+ const selectedCells = Array.from(
30701
+ surface.querySelectorAll("td.selectedCell, th.selectedCell")
30702
+ );
30703
+ if (selectedCells.length === 0) {
30704
+ return null;
30705
+ }
30706
+ const surfaceRect = surface.getBoundingClientRect();
30707
+ let left = Number.POSITIVE_INFINITY;
30708
+ let top = Number.POSITIVE_INFINITY;
30709
+ let right = Number.NEGATIVE_INFINITY;
30710
+ let bottom = Number.NEGATIVE_INFINITY;
30711
+ selectedCells.forEach((cell) => {
30712
+ const rect = cell.getBoundingClientRect();
30713
+ left = Math.min(left, rect.left);
30714
+ top = Math.min(top, rect.top);
30715
+ right = Math.max(right, rect.right);
30716
+ bottom = Math.max(bottom, rect.bottom);
30717
+ });
30718
+ return {
30719
+ left: left - surfaceRect.left + surface.scrollLeft,
30720
+ top: top - surfaceRect.top + surface.scrollTop,
30721
+ width: right - left,
30722
+ height: bottom - top
30723
+ };
30724
+ }
29870
30725
  var UEditor = React74.forwardRef(({
29871
30726
  content = "",
29872
30727
  onChange,
@@ -29886,7 +30741,11 @@ var UEditor = React74.forwardRef(({
29886
30741
  maxCharacters,
29887
30742
  minHeight = "200px",
29888
30743
  maxHeight = "auto",
29889
- variant = "default"
30744
+ variant = "default",
30745
+ fontFamilies,
30746
+ fontSizes,
30747
+ lineHeights,
30748
+ letterSpacings
29890
30749
  }, ref) => {
29891
30750
  const t = useSmartTranslations("UEditor");
29892
30751
  const effectivePlaceholder = placeholder ?? t("placeholder");
@@ -29931,7 +30790,7 @@ var UEditor = React74.forwardRef(({
29931
30790
  highlight.style.display = "none";
29932
30791
  return;
29933
30792
  }
29934
- const metrics = getRelativeCellMetrics(surface, cell);
30793
+ const metrics = getRelativeSelectedCellsMetrics(surface) ?? getRelativeCellMetrics(surface, cell);
29935
30794
  highlight.style.display = "block";
29936
30795
  highlight.style.left = `${metrics.left}px`;
29937
30796
  highlight.style.top = `${metrics.top}px`;
@@ -30034,8 +30893,10 @@ var UEditor = React74.forwardRef(({
30034
30893
  "[&_ul[data-type='taskList']_li>label>input]:border-2",
30035
30894
  "[&_ul[data-type='taskList']_li>label>input]:border-primary/50",
30036
30895
  "[&_ul[data-type='taskList']_li>label>input]:accent-primary",
30037
- "[&_pre]:bg-[#1e1e1e]!",
30038
- "[&_pre]:text-[#d4d4d4]!",
30896
+ "[&_pre]:bg-muted/40!",
30897
+ "[&_pre]:text-foreground!",
30898
+ "[&_pre]:border!",
30899
+ "[&_pre]:border-border/60!",
30039
30900
  "[&_pre_code]:bg-transparent!",
30040
30901
  "[&_.tableWrapper]:overflow-x-auto",
30041
30902
  "[&_.tableWrapper]:pb-1.5",
@@ -30055,6 +30916,11 @@ var UEditor = React74.forwardRef(({
30055
30916
  "[&_table]:table-fixed",
30056
30917
  "[&_table]:overflow-hidden",
30057
30918
  "[&_table]:select-text",
30919
+ "[&_table[data-table-align]]:w-max",
30920
+ "[&_table[data-table-align]]:max-w-full",
30921
+ "[&_table[data-table-align='center']]:mx-auto",
30922
+ "[&_table[data-table-align='right']]:ml-auto",
30923
+ "[&_table[data-table-align='right']]:mr-0",
30058
30924
  "[&_td]:relative",
30059
30925
  "[&_td]:align-top",
30060
30926
  "[&_td]:box-border",
@@ -30417,8 +31283,27 @@ var UEditor = React74.forwardRef(({
30417
31283
  className
30418
31284
  ),
30419
31285
  children: [
30420
- editable && showToolbar && /* @__PURE__ */ jsx83(EditorToolbar, { editor, variant, uploadImage, imageInsertMode }),
30421
- editable && showBubbleMenu && /* @__PURE__ */ jsx83(CustomBubbleMenu, { editor }),
31286
+ editable && showToolbar && /* @__PURE__ */ jsx83(
31287
+ EditorToolbar,
31288
+ {
31289
+ editor,
31290
+ variant,
31291
+ uploadImage,
31292
+ imageInsertMode,
31293
+ fontFamilies,
31294
+ fontSizes,
31295
+ lineHeights,
31296
+ letterSpacings
31297
+ }
31298
+ ),
31299
+ editable && showBubbleMenu && /* @__PURE__ */ jsx83(
31300
+ CustomBubbleMenu,
31301
+ {
31302
+ editor,
31303
+ fontSizes,
31304
+ lineHeights
31305
+ }
31306
+ ),
30422
31307
  editable && showFloatingMenu && /* @__PURE__ */ jsx83(CustomFloatingMenu, { editor }),
30423
31308
  /* @__PURE__ */ jsxs71(
30424
31309
  "div",
@@ -30451,7 +31336,7 @@ var UEditor = React74.forwardRef(({
30451
31336
  {
30452
31337
  ref: activeTableCellHighlightRef,
30453
31338
  "aria-hidden": "true",
30454
- className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-[#2383e2] bg-[#2383e2]/[0.06] transition-[left,top,width,height] duration-100"
31339
+ className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10 transition-[left,top,width,height] duration-100"
30455
31340
  }
30456
31341
  ),
30457
31342
  editable && /* @__PURE__ */ jsx83(TableControls, { editor, containerRef: editorContentRef }),