@underverse-ui/underverse 1.0.191 → 1.0.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1107,6 +1107,19 @@ var en_default = {
1107
1107
  borderStyle: "Border Style",
1108
1108
  borderWidth: "Border Width",
1109
1109
  borderColor: "Border Color",
1110
+ borderPosition: "Border placement",
1111
+ borderMode: "Border mode",
1112
+ borderDraw: "Draw borders",
1113
+ borderErase: "Hide borders",
1114
+ borderAll: "All borders",
1115
+ borderOuter: "Outer borders",
1116
+ borderInner: "Inner borders",
1117
+ borderHorizontal: "Inner horizontal borders",
1118
+ borderVertical: "Inner vertical borders",
1119
+ borderTop: "Top border",
1120
+ borderRight: "Right border",
1121
+ borderBottom: "Bottom border",
1122
+ borderLeft: "Left border",
1110
1123
  clearBorder: "Clear Border",
1111
1124
  formula: "Formula",
1112
1125
  formulaBar: "Formula bar",
@@ -1540,6 +1553,19 @@ var vi_default = {
1540
1553
  borderStyle: "Ki\u1EC3u vi\u1EC1n",
1541
1554
  borderWidth: "\u0110\u1ED9 d\xE0y vi\u1EC1n",
1542
1555
  borderColor: "M\xE0u vi\u1EC1n",
1556
+ borderPosition: "V\u1ECB tr\xED vi\u1EC1n",
1557
+ borderMode: "Ch\u1EBF \u0111\u1ED9 vi\u1EC1n",
1558
+ borderDraw: "V\u1EBD vi\u1EC1n",
1559
+ borderErase: "\u1EA8n c\u1EA1nh",
1560
+ borderAll: "T\u1EA5t c\u1EA3 vi\u1EC1n",
1561
+ borderOuter: "Vi\u1EC1n ngo\xE0i",
1562
+ borderInner: "Vi\u1EC1n trong",
1563
+ borderHorizontal: "Vi\u1EC1n ngang b\xEAn trong",
1564
+ borderVertical: "Vi\u1EC1n d\u1ECDc b\xEAn trong",
1565
+ borderTop: "Vi\u1EC1n tr\xEAn",
1566
+ borderRight: "Vi\u1EC1n ph\u1EA3i",
1567
+ borderBottom: "Vi\u1EC1n d\u01B0\u1EDBi",
1568
+ borderLeft: "Vi\u1EC1n tr\xE1i",
1543
1569
  clearBorder: "X\xF3a vi\u1EC1n",
1544
1570
  formula: "C\xF4ng th\u1EE9c",
1545
1571
  formulaBar: "Thanh c\xF4ng th\u1EE9c",
@@ -1973,6 +1999,19 @@ var ko_default = {
1973
1999
  borderStyle: "\uD14C\uB450\uB9AC \uC2A4\uD0C0\uC77C",
1974
2000
  borderWidth: "\uD14C\uB450\uB9AC \uB450\uAED8",
1975
2001
  borderColor: "\uD14C\uB450\uB9AC \uC0C9\uC0C1",
2002
+ borderPosition: "\uD14C\uB450\uB9AC \uC704\uCE58",
2003
+ borderMode: "\uD14C\uB450\uB9AC \uBAA8\uB4DC",
2004
+ borderDraw: "\uD14C\uB450\uB9AC \uADF8\uB9AC\uAE30",
2005
+ borderErase: "\uD14C\uB450\uB9AC \uC228\uAE30\uAE30",
2006
+ borderAll: "\uBAA8\uB4E0 \uD14C\uB450\uB9AC",
2007
+ borderOuter: "\uBC14\uAE65\uCABD \uD14C\uB450\uB9AC",
2008
+ borderInner: "\uC548\uCABD \uD14C\uB450\uB9AC",
2009
+ borderHorizontal: "\uC548\uCABD \uAC00\uB85C \uD14C\uB450\uB9AC",
2010
+ borderVertical: "\uC548\uCABD \uC138\uB85C \uD14C\uB450\uB9AC",
2011
+ borderTop: "\uC704\uCABD \uD14C\uB450\uB9AC",
2012
+ borderRight: "\uC624\uB978\uCABD \uD14C\uB450\uB9AC",
2013
+ borderBottom: "\uC544\uB798\uCABD \uD14C\uB450\uB9AC",
2014
+ borderLeft: "\uC67C\uCABD \uD14C\uB450\uB9AC",
1976
2015
  clearBorder: "\uD14C\uB450\uB9AC \uC9C0\uC6B0\uAE30",
1977
2016
  formula: "\uC218\uC2DD",
1978
2017
  formulaBar: "\uC218\uC2DD \uC785\uB825\uC904",
@@ -2406,6 +2445,19 @@ var ja_default = {
2406
2445
  borderStyle: "\u67A0\u7DDA\u30B9\u30BF\u30A4\u30EB",
2407
2446
  borderWidth: "\u67A0\u7DDA\u306E\u592A\u3055",
2408
2447
  borderColor: "\u67A0\u7DDA\u306E\u8272",
2448
+ borderPosition: "\u67A0\u7DDA\u306E\u4F4D\u7F6E",
2449
+ borderMode: "\u67A0\u7DDA\u30E2\u30FC\u30C9",
2450
+ borderDraw: "\u67A0\u7DDA\u3092\u5F15\u304F",
2451
+ borderErase: "\u67A0\u7DDA\u3092\u975E\u8868\u793A",
2452
+ borderAll: "\u3059\u3079\u3066\u306E\u67A0\u7DDA",
2453
+ borderOuter: "\u5916\u67A0",
2454
+ borderInner: "\u5185\u5074\u306E\u67A0\u7DDA",
2455
+ borderHorizontal: "\u5185\u5074\u306E\u6A2A\u7F6B\u7DDA",
2456
+ borderVertical: "\u5185\u5074\u306E\u7E26\u7F6B\u7DDA",
2457
+ borderTop: "\u4E0A\u7F6B\u7DDA",
2458
+ borderRight: "\u53F3\u7F6B\u7DDA",
2459
+ borderBottom: "\u4E0B\u7F6B\u7DDA",
2460
+ borderLeft: "\u5DE6\u7F6B\u7DDA",
2409
2461
  clearBorder: "\u67A0\u7DDA\u3092\u30AF\u30EA\u30A2",
2410
2462
  formula: "\u6570\u5F0F",
2411
2463
  formulaBar: "\u6570\u5F0F\u30D0\u30FC",
@@ -3562,7 +3614,7 @@ var Textarea = (0, import_react4.forwardRef)(
3562
3614
  required,
3563
3615
  value,
3564
3616
  maxLength,
3565
- borderMode = "2xl",
3617
+ borderMode,
3566
3618
  ...props
3567
3619
  }, ref) => {
3568
3620
  const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
@@ -6971,9 +7023,12 @@ var Modal = ({
6971
7023
  noPadding = false,
6972
7024
  fullWidth = false,
6973
7025
  width,
6974
- height
7026
+ height,
7027
+ borderMode
6975
7028
  }) => {
6976
7029
  const gi18n = useGlobalI18n();
7030
+ const globalConfig = useUnderverseUIConfig();
7031
+ const resolvedBorderMode = borderMode ?? globalConfig.borderMode;
6977
7032
  const [isMounted, setIsMounted] = React22.useState(false);
6978
7033
  const [isVisible, setIsVisible] = React22.useState(false);
6979
7034
  const [isAnimating, setIsAnimating] = React22.useState(true);
@@ -7079,7 +7134,8 @@ var Modal = ({
7079
7134
  {
7080
7135
  ref: modalContentRef,
7081
7136
  className: cn(
7082
- "relative w-full rounded-2xl md:rounded-3xl border border-border/40 bg-card text-card-foreground shadow-xl",
7137
+ "relative w-full border border-border/40 bg-card text-card-foreground shadow-xl",
7138
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-2xl md:rounded-3xl",
7083
7139
  "transition-all duration-200 ease-out",
7084
7140
  maxWidthClass,
7085
7141
  fullWidth && "mx-0",
@@ -7587,7 +7643,8 @@ var Popover = ({
7587
7643
  open,
7588
7644
  onOpenChange,
7589
7645
  matchTriggerWidth = false,
7590
- contentWidth
7646
+ contentWidth,
7647
+ borderMode
7591
7648
  }) => {
7592
7649
  const isControlled = open !== void 0;
7593
7650
  const [internalOpen, setInternalOpen] = React24.useState(false);
@@ -7596,6 +7653,8 @@ var Popover = ({
7596
7653
  const panelRef = React24.useRef(null);
7597
7654
  const lastAppliedRef = React24.useRef(null);
7598
7655
  useShadCNAnimations();
7656
+ const globalConfig = useUnderverseUIConfig();
7657
+ const resolvedBorderMode = borderMode ?? globalConfig.popover?.borderMode ?? globalConfig.borderMode;
7599
7658
  const isOpen = isControlled ? open : internalOpen;
7600
7659
  const setIsOpen = React24.useCallback(
7601
7660
  (next) => {
@@ -7776,7 +7835,8 @@ var Popover = ({
7776
7835
  {
7777
7836
  ...contentProps,
7778
7837
  className: cn(
7779
- "rounded-2xl md:rounded-3xl border bg-popover text-popover-foreground shadow-md",
7838
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-2xl md:rounded-3xl",
7839
+ "border bg-popover text-popover-foreground shadow-md",
7780
7840
  "backdrop-blur-sm bg-popover/95 border-border/60 p-4",
7781
7841
  contentProps?.className,
7782
7842
  contentClassName
@@ -8115,7 +8175,9 @@ var SlideOver = (props) => {
8115
8175
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Sheet, { ...props, side: "right", variant: "overlay", size: "lg" });
8116
8176
  };
8117
8177
  var BottomSheet = ({ snapPoints = ["25%", "50%", "90%"], defaultSnap = 1, ...props }) => {
8118
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Sheet, { ...props, side: "bottom", variant: "overlay", className: cn("rounded-t-3xl", props.className) });
8178
+ const globalConfig = useUnderverseUIConfig();
8179
+ const isSquare = globalConfig.borderMode === "daewoo" || globalConfig.borderMode === "none";
8180
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Sheet, { ...props, side: "bottom", variant: "overlay", className: cn(isSquare ? "" : "rounded-t-3xl", props.className) });
8119
8181
  };
8120
8182
  var SidebarSheet = ({ navigation, children, ...props }) => {
8121
8183
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Sheet, { ...props, side: "left", variant: "push", size: "md", children: [
@@ -8787,7 +8849,8 @@ var DropdownMenu = ({
8787
8849
  disabled = false,
8788
8850
  isOpen,
8789
8851
  onOpenChange,
8790
- items
8852
+ items,
8853
+ borderMode
8791
8854
  }) => {
8792
8855
  const [internalOpen, setInternalOpen] = (0, import_react17.useState)(false);
8793
8856
  const open = isOpen !== void 0 ? isOpen : internalOpen;
@@ -8823,6 +8886,8 @@ var DropdownMenu = ({
8823
8886
  item.scrollIntoView({ block: "nearest" });
8824
8887
  }, [getEnabledMenuItems, setActiveIndex]);
8825
8888
  useShadCNAnimations();
8889
+ const globalConfig = useUnderverseUIConfig();
8890
+ const resolvedBorderMode = borderMode ?? globalConfig.dropdownMenu?.borderMode ?? globalConfig.borderMode;
8826
8891
  import_react17.default.useEffect(() => {
8827
8892
  if (!open) return;
8828
8893
  const handleKeyNav = (e) => {
@@ -8890,7 +8955,8 @@ var DropdownMenu = ({
8890
8955
  animationDelay: open ? `${Math.min(index * 20, 200)}ms` : "0ms"
8891
8956
  },
8892
8957
  className: cn(
8893
- "dropdown-item flex w-full items-center gap-2 px-2.5 py-1.5 text-sm rounded-lg",
8958
+ "dropdown-item flex w-full items-center gap-2 px-2.5 py-1.5 text-sm",
8959
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-lg",
8894
8960
  "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
8895
8961
  "hover:bg-accent hover:text-accent-foreground",
8896
8962
  "focus:bg-accent focus:text-accent-foreground",
@@ -8946,6 +9012,7 @@ var DropdownMenu = ({
8946
9012
  trigger: enhancedTrigger,
8947
9013
  placement,
8948
9014
  disabled,
9015
+ borderMode: resolvedBorderMode,
8949
9016
  contentClassName: cn("p-1", contentClassName),
8950
9017
  children: menuBody
8951
9018
  }
@@ -8962,10 +9029,13 @@ var DropdownMenuItem = ({
8962
9029
  active,
8963
9030
  shortcut,
8964
9031
  className,
8965
- closeOnSelect
9032
+ closeOnSelect,
9033
+ borderMode
8966
9034
  }) => {
8967
9035
  const menu = import_react17.default.useContext(DropdownMenuContext);
8968
9036
  const shouldCloseOnSelect = closeOnSelect ?? menu?.closeOnSelect ?? false;
9037
+ const globalConfig = useUnderverseUIConfig();
9038
+ const resolvedBorderMode = borderMode ?? globalConfig.dropdownMenu?.borderMode ?? globalConfig.borderMode;
8969
9039
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
8970
9040
  "button",
8971
9041
  {
@@ -8980,7 +9050,8 @@ var DropdownMenuItem = ({
8980
9050
  "data-dropdown-menu-item": "",
8981
9051
  tabIndex: -1,
8982
9052
  className: cn(
8983
- "flex w-full items-center gap-2 px-3 py-2 text-sm rounded-lg transition-colors group cursor-pointer",
9053
+ "flex w-full items-center gap-2 px-3 py-2 text-sm transition-colors group cursor-pointer",
9054
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-lg",
8984
9055
  "hover:bg-accent hover:text-accent-foreground",
8985
9056
  "focus:bg-accent focus:text-accent-foreground focus:outline-none",
8986
9057
  "disabled:opacity-50 disabled:cursor-not-allowed",
@@ -9002,56 +9073,67 @@ var DropdownMenuItem = ({
9002
9073
  );
9003
9074
  };
9004
9075
  var DropdownMenuSeparator = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn("h-px bg-border my-1", className) });
9005
- var DropdownMenuSub = ({ label, icon: Icon, disabled, children }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
9006
- DropdownMenu,
9007
- {
9008
- trigger: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
9009
- "button",
9010
- {
9011
- type: "button",
9012
- disabled,
9013
- onMouseDown: (e) => e.preventDefault(),
9014
- className: cn(
9015
- "flex w-full items-center gap-2 px-3 py-2 text-sm rounded-lg transition-colors cursor-pointer",
9016
- "hover:bg-accent hover:text-accent-foreground",
9017
- "focus:bg-accent focus:text-accent-foreground focus:outline-none",
9018
- "disabled:opacity-50 disabled:cursor-not-allowed"
9019
- ),
9020
- children: [
9021
- Icon && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Icon, { className: "w-4 h-4 shrink-0 opacity-60" }),
9022
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "flex-1 text-left", children: label }),
9023
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react14.ChevronRight, { className: "w-3 h-3 opacity-50" })
9024
- ]
9025
- }
9026
- ),
9027
- placement: "right",
9028
- children
9029
- }
9030
- );
9031
- var SelectDropdown = ({ options, value, onChange, placeholder = "Select...", className }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
9032
- DropdownMenu,
9033
- {
9034
- trigger: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
9035
- "button",
9036
- {
9037
- className: cn(
9038
- "inline-flex items-center justify-between gap-2 px-3 py-2 text-sm rounded-2xl border bg-background border-border/60",
9039
- "hover:bg-accent/50",
9040
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
9041
- className
9042
- ),
9043
- children: [
9044
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "truncate max-w-64 text-foreground/90", children: value || placeholder }),
9045
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", className: "opacity-70", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("path", { d: "M6 8l4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
9046
- ]
9047
- }
9048
- ),
9049
- items: options.map((option) => ({
9050
- label: option,
9051
- onClick: () => onChange(option)
9052
- }))
9053
- }
9054
- );
9076
+ var DropdownMenuSub = ({ label, icon: Icon, disabled, borderMode, children }) => {
9077
+ const globalConfig = useUnderverseUIConfig();
9078
+ const resolvedBorderMode = borderMode ?? globalConfig.dropdownMenu?.borderMode ?? globalConfig.borderMode;
9079
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
9080
+ DropdownMenu,
9081
+ {
9082
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
9083
+ "button",
9084
+ {
9085
+ type: "button",
9086
+ disabled,
9087
+ onMouseDown: (e) => e.preventDefault(),
9088
+ className: cn(
9089
+ "flex w-full items-center gap-2 px-3 py-2 text-sm transition-colors cursor-pointer",
9090
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-lg",
9091
+ "hover:bg-accent hover:text-accent-foreground",
9092
+ "focus:bg-accent focus:text-accent-foreground focus:outline-none",
9093
+ "disabled:opacity-50 disabled:cursor-not-allowed"
9094
+ ),
9095
+ children: [
9096
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Icon, { className: "w-4 h-4 shrink-0 opacity-60" }),
9097
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "flex-1 text-left", children: label }),
9098
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react14.ChevronRight, { className: "w-3 h-3 opacity-50" })
9099
+ ]
9100
+ }
9101
+ ),
9102
+ placement: "right",
9103
+ children
9104
+ }
9105
+ );
9106
+ };
9107
+ var SelectDropdown = ({ options, value, onChange, placeholder = "Select...", className, borderMode }) => {
9108
+ const globalConfig = useUnderverseUIConfig();
9109
+ const resolvedBorderMode = borderMode ?? globalConfig.dropdownMenu?.borderMode ?? globalConfig.borderMode;
9110
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
9111
+ DropdownMenu,
9112
+ {
9113
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
9114
+ "button",
9115
+ {
9116
+ className: cn(
9117
+ "inline-flex items-center justify-between gap-2 px-3 py-2 text-sm border bg-background border-border/60",
9118
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-2xl",
9119
+ "hover:bg-accent/50",
9120
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
9121
+ className
9122
+ ),
9123
+ children: [
9124
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "truncate max-w-64 text-foreground/90", children: value || placeholder }),
9125
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", className: "opacity-70", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("path", { d: "M6 8l4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
9126
+ ]
9127
+ }
9128
+ ),
9129
+ items: options.map((option) => ({
9130
+ label: option,
9131
+ onClick: () => onChange(option)
9132
+ })),
9133
+ borderMode: resolvedBorderMode
9134
+ }
9135
+ );
9136
+ };
9055
9137
  var DropdownMenu_default = DropdownMenu;
9056
9138
 
9057
9139
  // src/components/Pagination.tsx
@@ -9136,6 +9218,9 @@ var Combobox = ({
9136
9218
  maxInitialOptions,
9137
9219
  showSearchPromptWhenEmptyQuery = false
9138
9220
  }) => {
9221
+ const globalConfig = useUnderverseUIConfig();
9222
+ const resolvedBorderMode = borderMode ?? globalConfig.borderMode ?? "full";
9223
+ const radiusClass = getBorderRadiusClass(resolvedBorderMode);
9139
9224
  const tv = useSmartTranslations("ValidationInput");
9140
9225
  const gi18n = useGlobalI18n();
9141
9226
  const placeholder = placeholderProp ?? gi18n.selectPlaceholder ?? "Select\u2026";
@@ -9345,7 +9430,7 @@ var Combobox = ({
9345
9430
  {
9346
9431
  "data-combobox-dropdown": true,
9347
9432
  "data-state": open ? "open" : "closed",
9348
- className: "w-full rounded-2xl md:rounded-3xl overflow-hidden",
9433
+ className: cn("w-full overflow-hidden", getBorderRadiusClass(resolvedBorderMode)),
9349
9434
  children: [
9350
9435
  enableSearch && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn("relative border-b border-border/30", size === "sm" ? "p-2" : size === "lg" ? "p-3" : "p-2.5"), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "relative", children: [
9351
9436
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
@@ -9487,9 +9572,6 @@ var Combobox = ({
9487
9572
  filled: "border-0 bg-muted/50 hover:bg-muted/80"
9488
9573
  };
9489
9574
  const labelSize = size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm";
9490
- const globalConfig = useUnderverseUIConfig();
9491
- const resolvedBorderMode = borderMode ?? globalConfig.borderMode ?? "full";
9492
- const radiusClass = getBorderRadiusClass(resolvedBorderMode);
9493
9575
  const verticalGap = size === "sm" ? "space-y-1.5" : "space-y-2";
9494
9576
  const triggerButtonBaseProps = {
9495
9577
  ref: triggerRef,
@@ -9620,12 +9702,13 @@ var Combobox = ({
9620
9702
  placement: "bottom-start",
9621
9703
  matchTriggerWidth: true,
9622
9704
  className: "z-9999",
9623
- contentClassName: "p-0 overflow-hidden rounded-2xl md:rounded-3xl",
9705
+ borderMode: resolvedBorderMode,
9706
+ contentClassName: "p-0 overflow-hidden",
9624
9707
  children: dropdownBody
9625
9708
  }
9626
9709
  ) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "relative", children: [
9627
9710
  triggerButtonInline,
9628
- open && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "absolute left-0 top-full mt-1 z-50 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "rounded-2xl md:rounded-3xl overflow-hidden border text-popover-foreground shadow-md backdrop-blur-sm bg-popover/95 border-border/60", children: dropdownBody }) })
9711
+ open && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "absolute left-0 top-full mt-1 z-50 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn("overflow-hidden border text-popover-foreground shadow-md backdrop-blur-sm bg-popover/95 border-border/60", getBorderRadiusClass(resolvedBorderMode)), children: dropdownBody }) })
9629
9712
  ] }),
9630
9713
  (helperText || effectiveError) && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
9631
9714
  "p",
@@ -10899,10 +10982,10 @@ var DatePicker = ({
10899
10982
  placement: "bottom-start",
10900
10983
  disabled,
10901
10984
  contentWidth: sizeStyles8[size].contentWidth,
10985
+ borderMode: resolvedBorderMode,
10902
10986
  contentClassName: cn(
10903
10987
  "p-0",
10904
10988
  "backdrop-blur-xl bg-popover/95 border-border/40 shadow-2xl",
10905
- "rounded-2xl md:rounded-3xl",
10906
10989
  // Keep usable on small viewports (wheel scroll should stay within the popover if it overflows)
10907
10990
  "max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto overscroll-contain",
10908
10991
  sizeStyles8[size].contentPadding,
@@ -11654,10 +11737,10 @@ var DateRangePicker = ({
11654
11737
  placement: "bottom-start",
11655
11738
  disabled,
11656
11739
  contentWidth: sizeStyles8[size].contentWidth,
11740
+ borderMode: resolvedBorderMode,
11657
11741
  contentClassName: cn(
11658
11742
  "p-0",
11659
11743
  "backdrop-blur-xl bg-popover/95 border-border/40 shadow-2xl",
11660
- "rounded-2xl md:rounded-3xl",
11661
11744
  "max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto overscroll-contain",
11662
11745
  sizeStyles8[size].contentPadding,
11663
11746
  "animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-300"
@@ -12057,6 +12140,8 @@ var LunarDatePicker = ({
12057
12140
  maxDate,
12058
12141
  borderMode
12059
12142
  }) => {
12143
+ const globalConfig = useUnderverseUIConfig();
12144
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
12060
12145
  const t = useSmartTranslations("DatePicker");
12061
12146
  const tv = useSmartTranslations("ValidationInput");
12062
12147
  const locale = useSmartLocale();
@@ -12581,12 +12666,12 @@ var LunarDatePicker = ({
12581
12666
  open: isOpen,
12582
12667
  onOpenChange: setIsOpen,
12583
12668
  placement: "bottom-start",
12669
+ borderMode: resolvedBorderMode,
12584
12670
  disabled,
12585
12671
  contentWidth: sizeStyles8[size].contentWidth,
12586
12672
  contentClassName: cn(
12587
12673
  "p-0",
12588
12674
  "backdrop-blur-xl bg-popover/95 border-border/40 shadow-2xl",
12589
- "rounded-2xl md:rounded-3xl",
12590
12675
  // Keep usable on small viewports (wheel scroll should stay within the popover if it overflows)
12591
12676
  "max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto overscroll-contain",
12592
12677
  sizeStyles8[size].contentPadding,
@@ -12604,7 +12689,7 @@ var LunarDatePicker = ({
12604
12689
  "aria-invalid": !!effectiveError,
12605
12690
  className: cn(
12606
12691
  "group flex w-full items-center justify-between border bg-background/80 backdrop-blur-sm",
12607
- getBorderRadiusClass(borderMode ?? "full"),
12692
+ getBorderRadiusClass(resolvedBorderMode),
12608
12693
  sizeStyles8[size].trigger,
12609
12694
  disabled ? "border-border/40 opacity-50 cursor-not-allowed" : [
12610
12695
  "border-border/60 hover:border-primary/40",
@@ -13747,6 +13832,8 @@ function MonthYearPicker({
13747
13832
  borderMode,
13748
13833
  ...rest
13749
13834
  }) {
13835
+ const globalConfig = useUnderverseUIConfig();
13836
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
13750
13837
  const gi18n = useGlobalI18n();
13751
13838
  const tv = useSmartTranslations("ValidationInput");
13752
13839
  const now = /* @__PURE__ */ new Date();
@@ -13905,7 +13992,7 @@ function MonthYearPicker({
13905
13992
  "aria-invalid": !!effectiveError,
13906
13993
  className: cn(
13907
13994
  "group flex w-full items-center justify-between border bg-background/80 backdrop-blur-sm",
13908
- getBorderRadiusClass(borderMode ?? "full"),
13995
+ getBorderRadiusClass(resolvedBorderMode),
13909
13996
  sz.height,
13910
13997
  sz.padding,
13911
13998
  sz.text,
@@ -14087,7 +14174,8 @@ function MonthYearPicker({
14087
14174
  {
14088
14175
  className: cn(
14089
14176
  panelSz.contentPadding,
14090
- "rounded-2xl border bg-background/80 backdrop-blur-sm",
14177
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-2xl md:rounded-3xl",
14178
+ "border bg-background/80 backdrop-blur-sm",
14091
14179
  effectiveError ? "border-destructive/60 bg-destructive/5" : "border-border/50"
14092
14180
  ),
14093
14181
  children: pickerContent
@@ -14128,7 +14216,8 @@ function MonthYearPicker({
14128
14216
  contentWidth,
14129
14217
  matchTriggerWidth,
14130
14218
  disabled,
14131
- contentClassName: cn(panelSz.contentPadding, compactPanel && "max-w-[calc(100vw-2rem)] p-4 rounded-2xl", "rounded-2xl"),
14219
+ borderMode: resolvedBorderMode,
14220
+ contentClassName: cn(panelSz.contentPadding, compactPanel && "max-w-[calc(100vw-2rem)] p-4"),
14132
14221
  children: pickerContent
14133
14222
  }
14134
14223
  ),
@@ -15275,6 +15364,8 @@ function TimePicker({
15275
15364
  }) {
15276
15365
  const tv = useSmartTranslations("ValidationInput");
15277
15366
  const gi18n = useGlobalI18n();
15367
+ const globalConfig = useUnderverseUIConfig();
15368
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
15278
15369
  const autoId = React38.useId();
15279
15370
  const isControlled = value !== void 0;
15280
15371
  const now = /* @__PURE__ */ new Date();
@@ -15612,7 +15703,7 @@ function TimePicker({
15612
15703
  "aria-invalid": !!effectiveError,
15613
15704
  className: cn(
15614
15705
  "group flex w-full items-center justify-between border bg-background/80 backdrop-blur-sm",
15615
- getBorderRadiusClass(borderMode ?? "full"),
15706
+ getBorderRadiusClass(resolvedBorderMode),
15616
15707
  sz.height,
15617
15708
  sz.padding,
15618
15709
  sz.text,
@@ -15993,7 +16084,8 @@ function TimePicker({
15993
16084
  {
15994
16085
  className: cn(
15995
16086
  panelSz.contentPadding,
15996
- "rounded-2xl md:rounded-3xl border bg-card/95 backdrop-blur-sm shadow-xl",
16087
+ resolvedBorderMode ? getBorderRadiusClass(resolvedBorderMode) : "rounded-2xl md:rounded-3xl",
16088
+ "border bg-card/95 backdrop-blur-sm shadow-xl",
15997
16089
  effectiveError ? "border-destructive/60 bg-destructive/5" : "border-border/60",
15998
16090
  className
15999
16091
  ),
@@ -16049,10 +16141,11 @@ function TimePicker({
16049
16141
  placement: "bottom-start",
16050
16142
  matchTriggerWidth: shouldMatchTriggerWidth,
16051
16143
  contentWidth: shouldMatchTriggerWidth ? void 0 : contentWidth,
16144
+ borderMode: resolvedBorderMode,
16052
16145
  contentClassName: cn(
16053
16146
  panelSz.contentPadding,
16054
- compactPanel && "max-w-[calc(100vw-2rem)] p-4 rounded-2xl",
16055
- "rounded-2xl md:rounded-3xl border bg-popover/98 backdrop-blur-md shadow-2xl",
16147
+ compactPanel && "max-w-[calc(100vw-2rem)] p-4",
16148
+ "border bg-popover/98 backdrop-blur-md shadow-2xl",
16056
16149
  effectiveError && "border-destructive/40",
16057
16150
  success && !effectiveError && "border-success/40",
16058
16151
  !effectiveError && !success && "border-border/60",
@@ -16095,6 +16188,8 @@ var DateTimePicker = ({
16095
16188
  size = "md",
16096
16189
  borderMode
16097
16190
  }) => {
16191
+ const globalConfig = useUnderverseUIConfig();
16192
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
16098
16193
  const t = useSmartTranslations("DateTimePicker");
16099
16194
  const tv = useSmartTranslations("ValidationInput");
16100
16195
  const locale = useSmartLocale();
@@ -16274,7 +16369,7 @@ var DateTimePicker = ({
16274
16369
  "aria-invalid": !!effectiveError,
16275
16370
  className: cn(
16276
16371
  "flex w-full items-center justify-between border border-input bg-background",
16277
- getBorderRadiusClass(borderMode ?? "full"),
16372
+ getBorderRadiusClass(resolvedBorderMode),
16278
16373
  sizeStyles8[size].trigger,
16279
16374
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
16280
16375
  disabled && "opacity-50 cursor-not-allowed",
@@ -16303,12 +16398,9 @@ var DateTimePicker = ({
16303
16398
  ]
16304
16399
  }
16305
16400
  ),
16306
- contentClassName: cn(
16307
- "w-auto p-0 rounded-2xl md:rounded-3xl",
16308
- // Keep the popover usable on small viewports
16309
- "max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto"
16310
- ),
16311
- placement: "bottom-end",
16401
+ placement: "bottom-start",
16402
+ borderMode: resolvedBorderMode,
16403
+ contentClassName: "p-0 overflow-hidden w-auto flex flex-col md:flex-row max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto",
16312
16404
  children: [
16313
16405
  /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-col lg:flex-row divide-y lg:divide-y-0 lg:divide-x divide-border", children: [
16314
16406
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: sizeStyles8[size].padding, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
@@ -19340,6 +19432,8 @@ var MultiCombobox = ({
19340
19432
  maxInitialOptions,
19341
19433
  showSearchPromptWhenEmptyQuery = false
19342
19434
  }) => {
19435
+ const globalConfig = useUnderverseUIConfig();
19436
+ const resolvedBorderMode = borderMode ?? globalConfig.borderMode ?? "full";
19343
19437
  const tv = useSmartTranslations("ValidationInput");
19344
19438
  const gi18n = useGlobalI18n();
19345
19439
  const placeholder = placeholderProp ?? gi18n.selectPlaceholder ?? "Select...";
@@ -19600,7 +19694,7 @@ var MultiCombobox = ({
19600
19694
  item.value
19601
19695
  );
19602
19696
  };
19603
- const dropdownBody = /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { "data-combobox-dropdown": true, "data-state": open ? "open" : "closed", className: "w-full rounded-2xl md:rounded-3xl overflow-hidden", children: [
19697
+ const dropdownBody = /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { "data-combobox-dropdown": true, "data-state": open ? "open" : "closed", className: cn("w-full overflow-hidden", getBorderRadiusClass(resolvedBorderMode)), children: [
19604
19698
  value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "px-3 py-2 border-b border-border/40 flex items-center justify-between bg-muted/30", children: [
19605
19699
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: maxSelected ? gi18n.selectedCountWithMax ? gi18n.selectedCountWithMax(value.length, maxSelected) : `${value.length} / ${maxSelected} max` : gi18n.itemSelectedCount ? gi18n.itemSelectedCount(value.length) : `${value.length} selected` }),
19606
19700
  showClear && /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
@@ -19718,8 +19812,6 @@ var MultiCombobox = ({
19718
19812
  const selectedOptions = value.map((v) => normalizedOptions.find((o) => o.value === v) ?? selectedOptionFallbackMap.get(v)).filter(Boolean);
19719
19813
  const visibleTags = maxTagsVisible ? selectedOptions.slice(0, maxTagsVisible) : selectedOptions;
19720
19814
  const hiddenCount = maxTagsVisible ? Math.max(0, selectedOptions.length - maxTagsVisible) : 0;
19721
- const globalConfig = useUnderverseUIConfig();
19722
- const resolvedBorderMode = borderMode ?? globalConfig.borderMode ?? "full";
19723
19815
  const triggerButton = /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
19724
19816
  "button",
19725
19817
  {
@@ -19882,7 +19974,8 @@ var MultiCombobox = ({
19882
19974
  placement: "bottom-start",
19883
19975
  matchTriggerWidth: true,
19884
19976
  className: "z-9999",
19885
- contentClassName: "p-0 overflow-hidden rounded-2xl md:rounded-3xl",
19977
+ borderMode: resolvedBorderMode,
19978
+ contentClassName: "p-0 overflow-hidden",
19886
19979
  children: dropdownBody
19887
19980
  }
19888
19981
  ),
@@ -19937,6 +20030,8 @@ var RadioGroup = React47.forwardRef(
19937
20030
  error = false,
19938
20031
  errorMessage
19939
20032
  }, ref) => {
20033
+ const globalConfig = useUnderverseUIConfig();
20034
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
19940
20035
  const [internalValue, setInternalValue] = React47.useState(defaultValue || "");
19941
20036
  const isControlled = value !== void 0;
19942
20037
  const currentValue = isControlled ? value : internalValue;
@@ -19960,7 +20055,7 @@ var RadioGroup = React47.forwardRef(
19960
20055
  disabled,
19961
20056
  size,
19962
20057
  variant,
19963
- borderMode
20058
+ borderMode: resolvedBorderMode
19964
20059
  },
19965
20060
  children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "space-y-2", children: [
19966
20061
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
@@ -21214,6 +21309,8 @@ function CategoryTreeSelect(props) {
21214
21309
  singleSelect = false,
21215
21310
  borderMode
21216
21311
  } = props;
21312
+ const globalConfig = useUnderverseUIConfig();
21313
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
21217
21314
  const [isOpen, setIsOpen] = (0, import_react26.useState)(false);
21218
21315
  const [expandedNodes, setExpandedNodes] = (0, import_react26.useState)(
21219
21316
  () => getInitialExpandedNodes(categories, { defaultExpanded, defaultExpandedIds, expandToId, viewOnly, inline })
@@ -21871,10 +21968,11 @@ function CategoryTreeSelect(props) {
21871
21968
  matchTriggerWidth: true,
21872
21969
  className: "z-9999",
21873
21970
  contentClassName: cn(
21874
- "p-0 overflow-hidden rounded-2xl md:rounded-3xl",
21971
+ "p-0 overflow-hidden",
21875
21972
  "border-border/40 bg-popover/95 text-popover-foreground",
21876
21973
  "shadow-2xl backdrop-blur-xl"
21877
21974
  ),
21975
+ borderMode: resolvedBorderMode,
21878
21976
  trigger: /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
21879
21977
  "div",
21880
21978
  {
@@ -21901,7 +21999,7 @@ function CategoryTreeSelect(props) {
21901
21999
  },
21902
22000
  className: cn(
21903
22001
  "group flex w-full items-center justify-between transition-all duration-200",
21904
- getBorderRadiusClass(borderMode ?? "full"),
22002
+ getBorderRadiusClass(resolvedBorderMode ?? "full"),
21905
22003
  "backdrop-blur-sm",
21906
22004
  triggerSizeStyles[size].button,
21907
22005
  triggerVariantStyles[variant],
@@ -24492,6 +24590,8 @@ function ColorPicker({
24492
24590
  borderMode,
24493
24591
  ...rest
24494
24592
  }) {
24593
+ const globalConfig = useUnderverseUIConfig();
24594
+ const resolvedBorderMode = borderMode ?? globalConfig.input?.borderMode ?? globalConfig.borderMode ?? "full";
24495
24595
  const gi18n = useGlobalI18n();
24496
24596
  const isControlled = value !== void 0;
24497
24597
  const initial = parseAnyColor(isControlled ? value : defaultValue) || { r: 79, g: 70, b: 229, a: 1 };
@@ -24589,7 +24689,7 @@ function ColorPicker({
24589
24689
  disabled,
24590
24690
  className: cn(
24591
24691
  "w-full px-3 border border-input bg-background flex items-center justify-between",
24592
- getBorderRadiusClass(borderMode ?? "full"),
24692
+ getBorderRadiusClass(resolvedBorderMode),
24593
24693
  sizeClasses2[size],
24594
24694
  "hover:border-accent-foreground/30 transition-colors",
24595
24695
  disabled && "opacity-50 cursor-not-allowed",
@@ -24625,8 +24725,9 @@ function ColorPicker({
24625
24725
  onOpenChange: setOpen,
24626
24726
  placement: "bottom-start",
24627
24727
  matchTriggerWidth: variant === "minimal",
24728
+ borderMode: resolvedBorderMode,
24628
24729
  contentWidth: contentWidthByVariant[variant],
24629
- contentClassName: cn("p-3 rounded-2xl md:rounded-3xl border border-border/50 bg-card shadow-lg", contentClassName),
24730
+ contentClassName: cn("p-3 border border-border/50 bg-card shadow-lg", contentClassName),
24630
24731
  children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "space-y-3", children: [
24631
24732
  variant !== "minimal" && /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center gap-2", children: [
24632
24733
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
@@ -31921,7 +32022,7 @@ var CustomTableCell = import_extension_table_cell.default.extend({
31921
32022
  },
31922
32023
  textDirection: {
31923
32024
  default: null,
31924
- parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || element.style.writingMode === "vertical-rl" ? "vertical" : null,
32025
+ parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || ["sideways-lr", "vertical-lr", "vertical-rl"].includes(element.style.writingMode) ? "vertical" : null,
31925
32026
  renderHTML: (attributes) => attributes.textDirection === "vertical" ? { "data-text-direction": "vertical" } : {}
31926
32027
  }
31927
32028
  };
@@ -31940,7 +32041,7 @@ var CustomTableCell = import_extension_table_cell.default.extend({
31940
32041
  if (borderStyle) mergedStyle += `; border-style: ${borderStyle}`;
31941
32042
  if (borderWidth) mergedStyle += `; border-width: ${borderWidth}`;
31942
32043
  if (verticalAlign) mergedStyle += `; vertical-align: ${verticalAlign}`;
31943
- if (textDirection === "vertical") mergedStyle += "; writing-mode: vertical-rl; text-orientation: mixed";
32044
+ if (textDirection === "vertical") mergedStyle += "; writing-mode: sideways-lr; text-orientation: mixed";
31944
32045
  mergedStyle = mergedStyle.replace(/^;/, "").trim();
31945
32046
  return [
31946
32047
  "td",
@@ -32047,7 +32148,7 @@ var CustomTableHeader = import_extension_table_header.default.extend({
32047
32148
  },
32048
32149
  textDirection: {
32049
32150
  default: null,
32050
- parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || element.style.writingMode === "vertical-rl" ? "vertical" : null,
32151
+ parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || ["sideways-lr", "vertical-lr", "vertical-rl"].includes(element.style.writingMode) ? "vertical" : null,
32051
32152
  renderHTML: (attributes) => attributes.textDirection === "vertical" ? { "data-text-direction": "vertical" } : {}
32052
32153
  }
32053
32154
  };
@@ -32066,7 +32167,7 @@ var CustomTableHeader = import_extension_table_header.default.extend({
32066
32167
  if (borderStyle) mergedStyle += `; border-style: ${borderStyle}`;
32067
32168
  if (borderWidth) mergedStyle += `; border-width: ${borderWidth}`;
32068
32169
  if (verticalAlign) mergedStyle += `; vertical-align: ${verticalAlign}`;
32069
- if (textDirection === "vertical") mergedStyle += "; writing-mode: vertical-rl; text-orientation: mixed";
32170
+ if (textDirection === "vertical") mergedStyle += "; writing-mode: sideways-lr; text-orientation: mixed";
32070
32171
  mergedStyle = mergedStyle.replace(/^;/, "").trim();
32071
32172
  return [
32072
32173
  "th",
@@ -34256,13 +34357,141 @@ var EditorToolbar = ({
34256
34357
  // src/components/UEditor/menus.tsx
34257
34358
  var import_react72 = require("react");
34258
34359
  var import_react73 = require("@tiptap/react");
34259
- var import_tables6 = require("@tiptap/pm/tables");
34360
+ var import_tables7 = require("@tiptap/pm/tables");
34260
34361
  var import_react_dom8 = require("react-dom");
34261
34362
  var import_lucide_react54 = require("lucide-react");
34262
34363
 
34364
+ // src/components/UEditor/table-border-commands.ts
34365
+ var import_tables5 = require("@tiptap/pm/tables");
34366
+ var SIDES = ["top", "right", "bottom", "left"];
34367
+ var OPPOSITE_SIDE = {
34368
+ top: "bottom",
34369
+ right: "left",
34370
+ bottom: "top",
34371
+ left: "right"
34372
+ };
34373
+ function splitCssValues(value) {
34374
+ const values = [];
34375
+ let token = "";
34376
+ let parentheses = 0;
34377
+ for (const character of value.trim()) {
34378
+ if (/\s/.test(character) && parentheses === 0) {
34379
+ if (token) values.push(token);
34380
+ token = "";
34381
+ continue;
34382
+ }
34383
+ if (character === "(") parentheses += 1;
34384
+ if (character === ")") parentheses = Math.max(0, parentheses - 1);
34385
+ token += character;
34386
+ }
34387
+ if (token) values.push(token);
34388
+ return values;
34389
+ }
34390
+ function expandCssQuad(value, fallback) {
34391
+ const values = typeof value === "string" ? splitCssValues(value) : [];
34392
+ const [top = fallback, right = top, bottom = top, left = right] = values;
34393
+ return { top, right, bottom, left };
34394
+ }
34395
+ function serializeCssQuad({ top, right, bottom, left }) {
34396
+ if (top === right && top === bottom && top === left) return top;
34397
+ if (top === bottom && right === left) return `${top} ${right}`;
34398
+ if (right === left) return `${top} ${right} ${bottom}`;
34399
+ return `${top} ${right} ${bottom} ${left}`;
34400
+ }
34401
+ function getAppliedSides(position, cell, selection) {
34402
+ const outer = {
34403
+ top: cell.top === selection.top,
34404
+ right: cell.right === selection.right,
34405
+ bottom: cell.bottom === selection.bottom,
34406
+ left: cell.left === selection.left
34407
+ };
34408
+ const inner = {
34409
+ top: cell.top > selection.top,
34410
+ right: cell.right < selection.right,
34411
+ bottom: cell.bottom < selection.bottom,
34412
+ left: cell.left > selection.left
34413
+ };
34414
+ switch (position) {
34415
+ case "all":
34416
+ return { top: true, right: true, bottom: true, left: true };
34417
+ case "outer":
34418
+ return outer;
34419
+ case "inner":
34420
+ return inner;
34421
+ case "horizontal":
34422
+ return { top: inner.top, right: false, bottom: inner.bottom, left: false };
34423
+ case "vertical":
34424
+ return { top: false, right: inner.right, bottom: false, left: inner.left };
34425
+ default:
34426
+ return {
34427
+ top: position === "top" && outer.top,
34428
+ right: position === "right" && outer.right,
34429
+ bottom: position === "bottom" && outer.bottom,
34430
+ left: position === "left" && outer.left
34431
+ };
34432
+ }
34433
+ }
34434
+ function applyTableCellBorders(editor, position, format, options = {}) {
34435
+ const { state, view } = editor;
34436
+ const selection = (0, import_tables5.selectedRect)(state);
34437
+ const transaction = state.tr;
34438
+ const cellPositions = new Set(selection.map.cellsInRect(selection));
34439
+ const sidesByCell = /* @__PURE__ */ new Map();
34440
+ const addSide = (cellPos, side) => {
34441
+ const sides = sidesByCell.get(cellPos) ?? /* @__PURE__ */ new Set();
34442
+ sides.add(side);
34443
+ sidesByCell.set(cellPos, sides);
34444
+ };
34445
+ const addAdjacentSides = (cell, side) => {
34446
+ const adjacentPositions = /* @__PURE__ */ new Set();
34447
+ if (side === "top" && cell.top > 0) {
34448
+ for (let col = cell.left; col < cell.right; col += 1) adjacentPositions.add(selection.map.map[(cell.top - 1) * selection.map.width + col]);
34449
+ } else if (side === "bottom" && cell.bottom < selection.map.height) {
34450
+ for (let col = cell.left; col < cell.right; col += 1) adjacentPositions.add(selection.map.map[cell.bottom * selection.map.width + col]);
34451
+ } else if (side === "left" && cell.left > 0) {
34452
+ for (let row = cell.top; row < cell.bottom; row += 1) adjacentPositions.add(selection.map.map[row * selection.map.width + cell.left - 1]);
34453
+ } else if (side === "right" && cell.right < selection.map.width) {
34454
+ for (let row = cell.top; row < cell.bottom; row += 1) adjacentPositions.add(selection.map.map[row * selection.map.width + cell.right]);
34455
+ }
34456
+ for (const adjacentPos of adjacentPositions) addSide(adjacentPos, OPPOSITE_SIDE[side]);
34457
+ };
34458
+ for (const relativePos of cellPositions) {
34459
+ const cell = selection.map.findCell(relativePos);
34460
+ const appliedSides = getAppliedSides(position, cell, selection);
34461
+ for (const side of SIDES) {
34462
+ if (!appliedSides[side]) continue;
34463
+ addSide(relativePos, side);
34464
+ addAdjacentSides(cell, side);
34465
+ }
34466
+ }
34467
+ for (const [relativePos, appliedSides] of sidesByCell) {
34468
+ const absolutePos = selection.tableStart + relativePos;
34469
+ const node = state.doc.nodeAt(absolutePos);
34470
+ if (!node) continue;
34471
+ const styles = expandCssQuad(node.attrs.borderStyle, "solid");
34472
+ const widths = expandCssQuad(node.attrs.borderWidth, "1px");
34473
+ const colors = expandCssQuad(node.attrs.borderColor, "#000000");
34474
+ for (const side of SIDES) {
34475
+ if (!appliedSides.has(side)) continue;
34476
+ styles[side] = format.style;
34477
+ widths[side] = format.width;
34478
+ colors[side] = format.color || "currentColor";
34479
+ }
34480
+ transaction.setNodeMarkup(absolutePos, void 0, {
34481
+ ...node.attrs,
34482
+ borderStyle: serializeCssQuad(styles),
34483
+ borderWidth: serializeCssQuad(widths),
34484
+ borderColor: serializeCssQuad(colors)
34485
+ });
34486
+ }
34487
+ if (transaction.docChanged) view.dispatch(transaction);
34488
+ if (options.focus ?? true) view.focus();
34489
+ return transaction.docChanged;
34490
+ }
34491
+
34263
34492
  // src/components/UEditor/table-formula-commands.ts
34264
34493
  var import_state11 = require("@tiptap/pm/state");
34265
- var import_tables5 = require("@tiptap/pm/tables");
34494
+ var import_tables6 = require("@tiptap/pm/tables");
34266
34495
 
34267
34496
  // src/components/UEditor/table-formula.ts
34268
34497
  var CELL_ADDRESS_RE = /^([A-Z]+)([1-9]\d*)$/i;
@@ -34853,7 +35082,7 @@ function getSelectionTableCellAnchor(editor) {
34853
35082
  const tableNode = $cell.node(depth);
34854
35083
  if (tableNode.type.name !== "table") continue;
34855
35084
  const tableStart = $cell.start(depth);
34856
- const rect = safeFindCell2(import_tables5.TableMap.get(tableNode), cellPos - tableStart);
35085
+ const rect = safeFindCell2(import_tables6.TableMap.get(tableNode), cellPos - tableStart);
34857
35086
  if (!rect) return null;
34858
35087
  return {
34859
35088
  cellPos,
@@ -34869,7 +35098,7 @@ function getSelectionTableCellAnchor(editor) {
34869
35098
  function restoreSelectionAtTableCell(editor, anchor) {
34870
35099
  const tableNode = editor.state.doc.nodeAt(anchor.tablePos);
34871
35100
  if (!tableNode || tableNode.type.name !== "table") return false;
34872
- const map = import_tables5.TableMap.get(tableNode);
35101
+ const map = import_tables6.TableMap.get(tableNode);
34873
35102
  if (anchor.row >= map.height || anchor.column >= map.width) return false;
34874
35103
  const relativeCellPos = map.positionAt(anchor.row, anchor.column, tableNode);
34875
35104
  const cellPos = anchor.tablePos + 1 + relativeCellPos;
@@ -34925,7 +35154,7 @@ function getSelectionTableCellLabel(editor) {
34925
35154
  const tableNode = $from.node(tableDepth);
34926
35155
  const tableStart = $from.start(tableDepth);
34927
35156
  const relativeCellPos = $from.before(cellDepth) - tableStart;
34928
- const rect = safeFindCell2(import_tables5.TableMap.get(tableNode), relativeCellPos);
35157
+ const rect = safeFindCell2(import_tables6.TableMap.get(tableNode), relativeCellPos);
34929
35158
  if (!rect) return null;
34930
35159
  return `${indexToColumnName(rect.left)}${rect.top + 1}`;
34931
35160
  }
@@ -34963,7 +35192,7 @@ function removeSelectedTableCellFormula(editor, clearContent) {
34963
35192
  return true;
34964
35193
  }
34965
35194
  function buildTableValueMap(tableNode) {
34966
- const map = import_tables5.TableMap.get(tableNode);
35195
+ const map = import_tables6.TableMap.get(tableNode);
34967
35196
  const values = /* @__PURE__ */ new Map();
34968
35197
  for (const rowInfo of getTableRows2(tableNode)) {
34969
35198
  for (const entry of rowInfo.cells) {
@@ -34988,8 +35217,8 @@ function setSelectedTableCellFormula(editor, formula) {
34988
35217
  if (!normalized) {
34989
35218
  return clearSelectedTableCellFormula(editor);
34990
35219
  }
34991
- const appliedFormula = (0, import_tables5.setCellAttr)("formula", normalized)(state, view.dispatch.bind(view));
34992
- const clearedValue = (0, import_tables5.setCellAttr)("computedValue", null)(editor.state, view.dispatch.bind(view));
35220
+ const appliedFormula = (0, import_tables6.setCellAttr)("formula", normalized)(state, view.dispatch.bind(view));
35221
+ const clearedValue = (0, import_tables6.setCellAttr)("computedValue", null)(editor.state, view.dispatch.bind(view));
34993
35222
  if (appliedFormula || clearedValue) {
34994
35223
  recalculateActiveTableFormulas(editor);
34995
35224
  if (selectionAnchor) restoreSelectionAtTableCell(editor, selectionAnchor);
@@ -35008,7 +35237,7 @@ function convertSelectedTableCellFormulaToValue(editor) {
35008
35237
  function setSelectedTableCellNumberFormat(editor, numberFormat) {
35009
35238
  const value = numberFormat && numberFormat !== "text" ? numberFormat : null;
35010
35239
  const { state, view } = editor;
35011
- const applied = (0, import_tables5.setCellAttr)("numberFormat", value)(state, view.dispatch.bind(view));
35240
+ const applied = (0, import_tables6.setCellAttr)("numberFormat", value)(state, view.dispatch.bind(view));
35012
35241
  if (!applied) return false;
35013
35242
  recalculateSelectedTable(editor);
35014
35243
  view.focus();
@@ -35080,7 +35309,7 @@ function promoteFormulaTextInTableNode(tableNode) {
35080
35309
  function recalculateTableNode(tableNode, options) {
35081
35310
  const promoted = promoteFormulaTextInTableNode(tableNode);
35082
35311
  tableNode = promoted.tableNode;
35083
- const map = import_tables5.TableMap.get(tableNode);
35312
+ const map = import_tables6.TableMap.get(tableNode);
35084
35313
  const values = buildTableValueMap(tableNode);
35085
35314
  const formulaEntries = /* @__PURE__ */ new Map();
35086
35315
  let changed = false;
@@ -35151,7 +35380,7 @@ function recalculateTableNode(tableNode, options) {
35151
35380
  return tableNode.type.create(tableNode.attrs, rows);
35152
35381
  }
35153
35382
  function recalculateSelectedTable(editor) {
35154
- const rect = (0, import_tables5.selectedRect)(editor.state);
35383
+ const rect = (0, import_tables6.selectedRect)(editor.state);
35155
35384
  const tableNode = rect.table;
35156
35385
  const nextTable = recalculateTableNode(tableNode);
35157
35386
  if (!nextTable) return false;
@@ -35258,7 +35487,7 @@ var FloatingMenuContent = ({ editor }) => {
35258
35487
  function applyTableCellBackground(editor, color) {
35259
35488
  const value = color || null;
35260
35489
  const { state, view } = editor;
35261
- const applied = (0, import_tables6.setCellAttr)("backgroundColor", value)(state, view.dispatch.bind(view));
35490
+ const applied = (0, import_tables7.setCellAttr)("backgroundColor", value)(state, view.dispatch.bind(view));
35262
35491
  if (applied) {
35263
35492
  view.focus();
35264
35493
  return;
@@ -35268,7 +35497,7 @@ function applyTableCellBackground(editor, color) {
35268
35497
  function applyTableCellAttribute2(editor, name, value, options = {}) {
35269
35498
  const shouldFocus = options.focus ?? true;
35270
35499
  const { state, view } = editor;
35271
- const applied = (0, import_tables6.setCellAttr)(name, value)(state, view.dispatch.bind(view));
35500
+ const applied = (0, import_tables7.setCellAttr)(name, value)(state, view.dispatch.bind(view));
35272
35501
  if (applied) {
35273
35502
  if (shouldFocus) view.focus();
35274
35503
  return;
@@ -35295,6 +35524,32 @@ function BorderStylePreviewIcon({ style }) {
35295
35524
  }
35296
35525
  );
35297
35526
  }
35527
+ function BorderPositionPreviewIcon({ position }) {
35528
+ const showTop = position === "all" || position === "outer" || position === "top";
35529
+ const showRight = position === "all" || position === "outer" || position === "right";
35530
+ const showBottom = position === "all" || position === "outer" || position === "bottom";
35531
+ const showLeft = position === "all" || position === "outer" || position === "left";
35532
+ const showHorizontal = position === "all" || position === "inner" || position === "horizontal";
35533
+ const showVertical = position === "all" || position === "inner" || position === "vertical";
35534
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("svg", { "aria-hidden": "true", viewBox: "0 0 20 20", className: "h-5 w-5 fill-none stroke-current", children: [
35535
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35536
+ "path",
35537
+ {
35538
+ d: "M2 2H18V18H2Z M2 10H18 M10 2V18",
35539
+ className: "text-foreground opacity-70",
35540
+ stroke: "currentColor",
35541
+ strokeDasharray: "2 1.5",
35542
+ strokeWidth: "1.25"
35543
+ }
35544
+ ),
35545
+ showTop && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("path", { d: "M2 2H18", strokeWidth: "2" }),
35546
+ showRight && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("path", { d: "M18 2V18", strokeWidth: "2" }),
35547
+ showBottom && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("path", { d: "M2 18H18", strokeWidth: "2" }),
35548
+ showLeft && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("path", { d: "M2 2V18", strokeWidth: "2" }),
35549
+ showHorizontal && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("path", { d: "M2 10H18", strokeWidth: "2" }),
35550
+ showVertical && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("path", { d: "M10 2V18", strokeWidth: "2" })
35551
+ ] });
35552
+ }
35298
35553
  var BubbleMenuContent = ({
35299
35554
  editor,
35300
35555
  onKeepOpenChange,
@@ -35302,7 +35557,8 @@ var BubbleMenuContent = ({
35302
35557
  onRequestClose,
35303
35558
  fontSizes,
35304
35559
  lineHeights,
35305
- initialShowLinkInput = false
35560
+ initialShowLinkInput = false,
35561
+ cellBorderOpenRequest = 0
35306
35562
  }) => {
35307
35563
  const t = useSmartTranslations("UEditor");
35308
35564
  (0, import_react73.useEditorState)({
@@ -35315,6 +35571,11 @@ var BubbleMenuContent = ({
35315
35571
  (0, import_react72.useEffect)(() => {
35316
35572
  setShowLinkInput(initialShowLinkInput);
35317
35573
  }, [initialShowLinkInput]);
35574
+ (0, import_react72.useEffect)(() => {
35575
+ if (!cellBorderOpenRequest) return;
35576
+ setActiveColorPalette("cell-border");
35577
+ onKeepOpenChange?.(true);
35578
+ }, [cellBorderOpenRequest, onKeepOpenChange]);
35318
35579
  const [showTypographyPanel, setShowTypographyPanel] = (0, import_react72.useState)(false);
35319
35580
  const [showFormulaPanel, setShowFormulaPanel] = (0, import_react72.useState)(false);
35320
35581
  const [formulaDraft, setFormulaDraft] = (0, import_react72.useState)("");
@@ -35332,9 +35593,17 @@ var BubbleMenuContent = ({
35332
35593
  const currentCellNumberFormat = normalizeStyleValue(editor.getAttributes("tableCell").numberFormat || editor.getAttributes("tableHeader").numberFormat) || "text";
35333
35594
  const currentCellBorderStyle = editor.getAttributes("tableCell").borderStyle || editor.getAttributes("tableHeader").borderStyle || "solid";
35334
35595
  const currentCellBorderWidth = editor.getAttributes("tableCell").borderWidth || editor.getAttributes("tableHeader").borderWidth || "1px";
35596
+ const currentCellBorderColor = normalizeStyleValue(editor.getAttributes("tableCell").borderColor || editor.getAttributes("tableHeader").borderColor) || "#000000";
35597
+ const [borderStyleDraft, setBorderStyleDraft] = (0, import_react72.useState)(
35598
+ ["solid", "dashed", "dotted", "double"].includes(currentCellBorderStyle) ? currentCellBorderStyle : "solid"
35599
+ );
35600
+ const [borderWidthDraft, setBorderWidthDraft] = (0, import_react72.useState)(currentCellBorderWidth);
35601
+ const [borderColorDraft, setBorderColorDraft] = (0, import_react72.useState)(currentCellBorderColor);
35602
+ const [borderEditMode, setBorderEditMode] = (0, import_react72.useState)("draw");
35603
+ const [activeBorderPosition, setActiveBorderPosition] = (0, import_react72.useState)("all");
35335
35604
  const currentCellVerticalAlign = normalizeStyleValue(editor.getAttributes("tableCell").verticalAlign || editor.getAttributes("tableHeader").verticalAlign) || "";
35336
35605
  const currentCellTextDirection = normalizeStyleValue(editor.getAttributes("tableCell").textDirection || editor.getAttributes("tableHeader").textDirection) || "horizontal";
35337
- const isInTable2 = (0, import_tables6.isInTable)(editor.state);
35606
+ const isInTable2 = (0, import_tables7.isInTable)(editor.state);
35338
35607
  const canMergeCells = isInTable2 && editor.can().mergeCells();
35339
35608
  const canSplitCell = isInTable2 && editor.can().splitCell();
35340
35609
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
@@ -35388,21 +35657,60 @@ var BubbleMenuContent = ({
35388
35657
  onLinkInputOpenChange?.(false);
35389
35658
  onRequestClose?.();
35390
35659
  }, [onKeepOpenChange, onLinkInputOpenChange, onRequestClose]);
35391
- const applyTableCellAttributeAndClose = (0, import_react72.useCallback)((name, value) => {
35392
- applyTableCellAttribute2(editor, name, value, { focus: false });
35393
- closeTransientPanels();
35394
- }, [closeTransientPanels, editor]);
35395
- const clearTableCellBorderAndClose = (0, import_react72.useCallback)(() => {
35396
- applyTableCellAttribute2(editor, "borderColor", null, { focus: false });
35397
- applyTableCellAttribute2(editor, "borderStyle", null, { focus: false });
35398
- applyTableCellAttribute2(editor, "borderWidth", null, { focus: false });
35399
- closeTransientPanels();
35400
- }, [closeTransientPanels, editor]);
35401
- const applyTableCellBorderColorAndClose = (0, import_react72.useCallback)((color) => {
35402
- const value = color || null;
35403
- applyTableCellAttribute2(editor, "borderColor", value, { focus: false });
35404
- closeTransientPanels();
35405
- }, [closeTransientPanels, editor]);
35660
+ const selectTableCellBorderColor = (0, import_react72.useCallback)((color) => {
35661
+ const value = color || "currentColor";
35662
+ setBorderColorDraft(value);
35663
+ setBorderEditMode("draw");
35664
+ setActiveBorderPosition("all");
35665
+ applyTableCellBorders(editor, "all", {
35666
+ color: value,
35667
+ style: borderStyleDraft,
35668
+ width: borderWidthDraft
35669
+ }, { focus: false });
35670
+ setActiveColorPalette("cell-border");
35671
+ onKeepOpenChange?.(true);
35672
+ }, [borderStyleDraft, borderWidthDraft, editor, onKeepOpenChange]);
35673
+ const applyTableCellBorderPosition = (0, import_react72.useCallback)((position) => {
35674
+ setActiveBorderPosition(position);
35675
+ applyTableCellBorders(editor, position, {
35676
+ color: borderColorDraft,
35677
+ style: borderEditMode === "erase" ? "none" : borderStyleDraft,
35678
+ width: borderWidthDraft
35679
+ }, { focus: false });
35680
+ onKeepOpenChange?.(true);
35681
+ }, [borderColorDraft, borderEditMode, borderStyleDraft, borderWidthDraft, editor, onKeepOpenChange]);
35682
+ const applyTableCellBorderStyle = (0, import_react72.useCallback)((style) => {
35683
+ setBorderStyleDraft(style);
35684
+ setBorderEditMode("draw");
35685
+ setActiveBorderPosition("all");
35686
+ applyTableCellBorders(editor, "all", {
35687
+ color: borderColorDraft,
35688
+ style,
35689
+ width: borderWidthDraft
35690
+ }, { focus: false });
35691
+ onKeepOpenChange?.(true);
35692
+ }, [borderColorDraft, borderWidthDraft, editor, onKeepOpenChange]);
35693
+ const applyTableCellBorderWidth = (0, import_react72.useCallback)((width) => {
35694
+ setBorderWidthDraft(width);
35695
+ setBorderEditMode("draw");
35696
+ setActiveBorderPosition("all");
35697
+ applyTableCellBorders(editor, "all", {
35698
+ color: borderColorDraft,
35699
+ style: borderStyleDraft,
35700
+ width
35701
+ }, { focus: false });
35702
+ onKeepOpenChange?.(true);
35703
+ }, [borderColorDraft, borderStyleDraft, editor, onKeepOpenChange]);
35704
+ const clearTableCellBorders = (0, import_react72.useCallback)(() => {
35705
+ setActiveBorderPosition("all");
35706
+ setBorderEditMode("erase");
35707
+ applyTableCellBorders(editor, "all", {
35708
+ color: borderColorDraft,
35709
+ style: "none",
35710
+ width: borderWidthDraft
35711
+ }, { focus: false });
35712
+ onKeepOpenChange?.(true);
35713
+ }, [borderColorDraft, borderWidthDraft, editor, onKeepOpenChange]);
35406
35714
  const closeColorPalette = (0, import_react72.useCallback)(() => {
35407
35715
  setActiveColorPalette(null);
35408
35716
  onKeepOpenChange?.(false);
@@ -35456,27 +35764,104 @@ var BubbleMenuContent = ({
35456
35764
  const isTextPalette = activeColorPalette === "text";
35457
35765
  const isHighlightPalette = activeColorPalette === "highlight";
35458
35766
  if (activeColorPalette === "cell-border") {
35459
- const currentBorderColor = editor.getAttributes("tableCell").borderColor || editor.getAttributes("tableHeader").borderColor || "currentColor";
35460
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "flex flex-col gap-2 p-2 w-56 text-sm", "data-ueditor-keep-open": true, children: [
35767
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "flex w-72 flex-col gap-2 p-2 text-sm", "data-ueditor-keep-open": true, children: [
35461
35768
  /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { className: "font-semibold text-xs text-muted-foreground uppercase tracking-wider mb-1", children: t("tableMenu.cellBorder") || "Cell Borders" }),
35769
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "flex gap-2", children: [
35770
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "min-w-0 flex-1", children: [
35771
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("label", { className: "mb-1 block text-xs text-muted-foreground", children: t("tableMenu.borderPosition") || "Border placement" }),
35772
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "grid grid-cols-5 gap-1", role: "group", "aria-label": t("tableMenu.borderPosition") || "Border placement", children: [
35773
+ [
35774
+ ["all", "borderAll"],
35775
+ ["outer", "borderOuter"],
35776
+ ["inner", "borderInner"],
35777
+ ["horizontal", "borderHorizontal"],
35778
+ ["vertical", "borderVertical"],
35779
+ ["top", "borderTop"],
35780
+ ["right", "borderRight"],
35781
+ ["bottom", "borderBottom"],
35782
+ ["left", "borderLeft"]
35783
+ ].map(([position, labelKey]) => {
35784
+ const label = t(`tableMenu.${labelKey}`) || position;
35785
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35786
+ "button",
35787
+ {
35788
+ type: "button",
35789
+ "aria-label": label,
35790
+ title: label,
35791
+ onMouseDown: (event) => event.preventDefault(),
35792
+ onClick: () => applyTableCellBorderPosition(position),
35793
+ className: cn(
35794
+ "inline-flex h-8 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted hover:text-primary",
35795
+ activeBorderPosition === position ? "bg-primary/10 text-primary" : "bg-muted/40"
35796
+ ),
35797
+ children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(BorderPositionPreviewIcon, { position })
35798
+ },
35799
+ position
35800
+ );
35801
+ }),
35802
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35803
+ "button",
35804
+ {
35805
+ type: "button",
35806
+ "aria-label": t("tableMenu.clearBorder") || "Clear borders",
35807
+ title: t("tableMenu.clearBorder") || "Clear borders",
35808
+ onMouseDown: (event) => event.preventDefault(),
35809
+ onClick: clearTableCellBorders,
35810
+ className: "inline-flex h-8 items-center justify-center rounded-md bg-muted/40 text-destructive transition-colors hover:bg-destructive/10",
35811
+ children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(BorderStylePreviewIcon, { style: "none" })
35812
+ }
35813
+ )
35814
+ ] })
35815
+ ] }),
35816
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "flex flex-col gap-1 border-l border-border pl-2 pt-5", role: "group", "aria-label": t("tableMenu.borderMode") || "Border mode", children: [
35817
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35818
+ "button",
35819
+ {
35820
+ type: "button",
35821
+ "aria-label": t("tableMenu.borderDraw") || "Draw borders",
35822
+ title: t("tableMenu.borderDraw") || "Draw borders",
35823
+ onMouseDown: (event) => event.preventDefault(),
35824
+ onClick: () => setBorderEditMode("draw"),
35825
+ className: cn(
35826
+ "inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted",
35827
+ borderEditMode === "draw" ? "bg-primary/10 text-primary" : "text-muted-foreground"
35828
+ ),
35829
+ children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(import_lucide_react54.Edit2, { className: "h-4 w-4" })
35830
+ }
35831
+ ),
35832
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35833
+ "button",
35834
+ {
35835
+ type: "button",
35836
+ "aria-label": t("tableMenu.borderErase") || "Hide borders",
35837
+ title: t("tableMenu.borderErase") || "Hide borders",
35838
+ onMouseDown: (event) => event.preventDefault(),
35839
+ onClick: () => setBorderEditMode("erase"),
35840
+ className: cn(
35841
+ "inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted",
35842
+ borderEditMode === "erase" ? "bg-destructive/10 text-destructive" : "text-muted-foreground"
35843
+ ),
35844
+ children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(import_lucide_react54.Eraser, { className: "h-4 w-4" })
35845
+ }
35846
+ )
35847
+ ] })
35848
+ ] }),
35462
35849
  /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "flex flex-col gap-1", children: [
35463
35850
  /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("label", { className: "text-xs text-muted-foreground", children: t("tableMenu.borderStyle") || "Border Style" }),
35464
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { className: "grid grid-cols-3 gap-1", role: "group", "aria-label": t("tableMenu.borderStyle") || "Border Style", children: [
35851
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { className: "grid grid-cols-4 gap-1.5", role: "group", "aria-label": t("tableMenu.borderStyle") || "Border Style", children: [
35465
35852
  ["solid", "Solid"],
35466
35853
  ["dashed", "Dashed"],
35467
35854
  ["dotted", "Dotted"],
35468
- ["double", "Double"],
35469
- ["none", "None"]
35855
+ ["double", "Double"]
35470
35856
  ].map(([style, label]) => /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
35471
35857
  "button",
35472
35858
  {
35473
35859
  type: "button",
35474
- "data-ueditor-close-on-select": true,
35475
35860
  onMouseDown: (event) => event.preventDefault(),
35476
- onClick: () => applyTableCellAttributeAndClose("borderStyle", style),
35861
+ onClick: () => applyTableCellBorderStyle(style),
35477
35862
  className: cn(
35478
- "inline-flex h-8 items-center justify-center gap-1.5 rounded-md px-2 text-xs font-medium transition-colors hover:bg-muted",
35479
- currentCellBorderStyle === style ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35863
+ "inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition-colors hover:bg-muted",
35864
+ borderStyleDraft === style ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35480
35865
  ),
35481
35866
  children: [
35482
35867
  /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(BorderStylePreviewIcon, { style }),
@@ -35492,12 +35877,11 @@ var BubbleMenuContent = ({
35492
35877
  "button",
35493
35878
  {
35494
35879
  type: "button",
35495
- "data-ueditor-close-on-select": true,
35496
35880
  onMouseDown: (event) => event.preventDefault(),
35497
- onClick: () => applyTableCellAttributeAndClose("borderWidth", width),
35881
+ onClick: () => applyTableCellBorderWidth(width),
35498
35882
  className: cn(
35499
35883
  "h-8 rounded-md px-2 text-xs font-medium transition-colors hover:bg-muted",
35500
- currentCellBorderWidth === width ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35884
+ borderWidthDraft === width ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35501
35885
  ),
35502
35886
  children: width
35503
35887
  },
@@ -35517,33 +35901,22 @@ var BubbleMenuContent = ({
35517
35901
  {
35518
35902
  className: "w-4 h-4 rounded-full border border-border",
35519
35903
  style: {
35520
- backgroundColor: currentBorderColor
35904
+ backgroundColor: borderColorDraft
35521
35905
  }
35522
35906
  }
35523
35907
  )
35524
35908
  ]
35525
35909
  }
35526
- ),
35527
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { className: "flex items-center justify-between gap-2 mt-2 pt-2 border-t border-border", children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35528
- "button",
35529
- {
35530
- type: "button",
35531
- "data-ueditor-close-on-select": true,
35532
- onClick: clearTableCellBorderAndClose,
35533
- className: "text-xs text-destructive hover:underline",
35534
- children: t("tableMenu.clearBorder") || "Clear Border"
35535
- }
35536
- ) })
35910
+ )
35537
35911
  ] });
35538
35912
  }
35539
35913
  if (activeColorPalette === "cell-border-color") {
35540
- const currentBorderColor = normalizeStyleValue(editor.getAttributes("tableCell").borderColor || editor.getAttributes("tableHeader").borderColor) || "";
35541
35914
  return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { className: "w-56", "data-ueditor-keep-open": true, children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
35542
35915
  EditorColorPalette,
35543
35916
  {
35544
35917
  colors: borderColors,
35545
- currentColor: currentBorderColor,
35546
- onSelect: applyTableCellBorderColorAndClose,
35918
+ currentColor: borderColorDraft,
35919
+ onSelect: selectTableCellBorderColor,
35547
35920
  label: t("tableMenu.borderColor") || "Border Color"
35548
35921
  }
35549
35922
  ) });
@@ -36061,6 +36434,7 @@ var CustomBubbleMenu = ({
36061
36434
  const BUBBLE_MENU_ESTIMATED_HEIGHT = 44;
36062
36435
  const [isVisible, setIsVisible] = (0, import_react72.useState)(false);
36063
36436
  const [linkInputOpen, setLinkInputOpen] = (0, import_react72.useState)(false);
36437
+ const [cellBorderOpenRequest, setCellBorderOpenRequest] = (0, import_react72.useState)(0);
36064
36438
  const [position, setPosition2] = (0, import_react72.useState)({
36065
36439
  top: 0,
36066
36440
  left: 0,
@@ -36077,8 +36451,8 @@ var CustomBubbleMenu = ({
36077
36451
  if (!next) setLinkInputOpen(false);
36078
36452
  if (next) setIsVisible(true);
36079
36453
  }, []);
36080
- const closeBubbleMenu = (0, import_react72.useCallback)(() => {
36081
- suppressShowUntilRef.current = Date.now() + 1e3;
36454
+ const closeBubbleMenu = (0, import_react72.useCallback)((suppressShow = true) => {
36455
+ suppressShowUntilRef.current = suppressShow ? Date.now() + 1e3 : 0;
36082
36456
  keepOpenRef.current = false;
36083
36457
  setKeepOpenState(false);
36084
36458
  setLinkInputOpen(false);
@@ -36170,6 +36544,41 @@ var CustomBubbleMenu = ({
36170
36544
  editor.off("update", updatePosition);
36171
36545
  };
36172
36546
  }, [editor]);
36547
+ (0, import_react72.useEffect)(() => {
36548
+ if (!isVisible) return;
36549
+ const handlePointerDown = (event) => {
36550
+ const target = event.target;
36551
+ if (target && (menuRef.current?.contains(target) || target.closest("[data-ueditor-keep-open]"))) return;
36552
+ const table = target?.closest("table");
36553
+ if (table && editor.view.dom.contains(table)) return;
36554
+ closeBubbleMenu(false);
36555
+ };
36556
+ const handleKeyDown2 = (event) => {
36557
+ if (event.key === "Escape") closeBubbleMenu();
36558
+ };
36559
+ document.addEventListener("pointerdown", handlePointerDown, true);
36560
+ document.addEventListener("keydown", handleKeyDown2);
36561
+ return () => {
36562
+ document.removeEventListener("pointerdown", handlePointerDown, true);
36563
+ document.removeEventListener("keydown", handleKeyDown2);
36564
+ };
36565
+ }, [closeBubbleMenu, editor, isVisible]);
36566
+ (0, import_react72.useEffect)(() => {
36567
+ const handleTableDoubleClick = (event) => {
36568
+ const target = event.target;
36569
+ const cell = target?.closest("td,th");
36570
+ if (!cell || !editor.view.dom.contains(cell)) return;
36571
+ suppressShowUntilRef.current = 0;
36572
+ keepOpenRef.current = true;
36573
+ setKeepOpenState(true);
36574
+ setLinkInputOpen(false);
36575
+ setCellBorderOpenRequest((request) => request + 1);
36576
+ setIsVisible(true);
36577
+ requestAnimationFrame(() => editor.view.focus());
36578
+ };
36579
+ editor.view.dom.addEventListener("dblclick", handleTableDoubleClick);
36580
+ return () => editor.view.dom.removeEventListener("dblclick", handleTableDoubleClick);
36581
+ }, [editor]);
36173
36582
  if (!isVisible) return null;
36174
36583
  return (0, import_react_dom8.createPortal)(
36175
36584
  /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
@@ -36210,7 +36619,8 @@ var CustomBubbleMenu = ({
36210
36619
  onRequestClose: closeBubbleMenu,
36211
36620
  fontSizes,
36212
36621
  lineHeights,
36213
- initialShowLinkInput: linkInputOpen
36622
+ initialShowLinkInput: linkInputOpen,
36623
+ cellBorderOpenRequest
36214
36624
  }
36215
36625
  )
36216
36626
  }
@@ -40662,7 +41072,7 @@ function moveTableRow$1(table, indexesOrigin, indexesTarget, direction) {
40662
41072
  rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction);
40663
41073
  return convertArrayOfRowsToTableNode(table, rows);
40664
41074
  }
40665
- function selectedRect3(state) {
41075
+ function selectedRect4(state) {
40666
41076
  const sel = state.selection;
40667
41077
  const $pos = selectionCell(state);
40668
41078
  const table = $pos.node(-1);
@@ -40680,7 +41090,7 @@ function deprecated_toggleHeader(type) {
40680
41090
  if (!isInTable(state)) return false;
40681
41091
  if (dispatch) {
40682
41092
  const types = tableNodeTypes2(state.schema);
40683
- const rect = selectedRect3(state), tr = state.tr;
41093
+ const rect = selectedRect4(state), tr = state.tr;
40684
41094
  const cells = rect.map.cellsInRect(type == "column" ? {
40685
41095
  left: rect.left,
40686
41096
  top: 0,
@@ -40720,7 +41130,7 @@ function toggleHeader(type, options) {
40720
41130
  if (!isInTable(state)) return false;
40721
41131
  if (dispatch) {
40722
41132
  const types = tableNodeTypes2(state.schema);
40723
- const rect = selectedRect3(state), tr = state.tr;
41133
+ const rect = selectedRect4(state), tr = state.tr;
40724
41134
  const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
40725
41135
  const isHeaderColumnEnabled = isHeaderEnabledByType("column", rect, types);
40726
41136
  const selectionStartsAt = (type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false) ? 1 : 0;
@@ -42740,11 +43150,11 @@ function useUEditorTableInteractions(editor, editable = true) {
42740
43150
 
42741
43151
  // src/components/UEditor/use-formula-coordinate-overlay.ts
42742
43152
  var import_react77 = require("react");
42743
- var import_tables8 = require("@tiptap/pm/tables");
43153
+ var import_tables9 = require("@tiptap/pm/tables");
42744
43154
 
42745
43155
  // src/components/UEditor/table-formula-range-picker.ts
42746
43156
  var import_state12 = require("@tiptap/pm/state");
42747
- var import_tables7 = require("@tiptap/pm/tables");
43157
+ var import_tables8 = require("@tiptap/pm/tables");
42748
43158
  function getCellText2(cellNode) {
42749
43159
  return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
42750
43160
  }
@@ -42762,7 +43172,7 @@ function getFormulaEditingTableContext(view) {
42762
43172
  if (!tableNode || tableNode.type.name !== "table") return null;
42763
43173
  const tableDom = cellDom.closest("table");
42764
43174
  if (!(tableDom instanceof HTMLTableElement)) return null;
42765
- const tableMap = import_tables7.TableMap.get(tableNode);
43175
+ const tableMap = import_tables8.TableMap.get(tableNode);
42766
43176
  const tableStart = $from.start(tableDepth);
42767
43177
  const formulaCellRect = tableMap.findCell(cellPos - tableStart);
42768
43178
  return {
@@ -42779,7 +43189,7 @@ function getFormulaEditingTableContext(view) {
42779
43189
  return null;
42780
43190
  }
42781
43191
  function collectTableFormulaCells(tableNode) {
42782
- const tableMap = import_tables7.TableMap.get(tableNode);
43192
+ const tableMap = import_tables8.TableMap.get(tableNode);
42783
43193
  const formulas = [];
42784
43194
  tableNode.forEach((rowNode, rowOffset) => {
42785
43195
  rowNode.forEach((cellNode, cellOffset) => {
@@ -42865,7 +43275,7 @@ function getFormulaTableCellInfo(view, target, tablePos) {
42865
43275
  const domPos = view.posAtDOM(cell, 0);
42866
43276
  const tableInfo = findTableForPos(view, domPos);
42867
43277
  if (!tableInfo || tableInfo.pos !== tablePos) return null;
42868
- const map = import_tables7.TableMap.get(tableInfo.node);
43278
+ const map = import_tables8.TableMap.get(tableInfo.node);
42869
43279
  const relativeCellPos = getCellRelativePosFromDomPos2(map, tableInfo.start, domPos);
42870
43280
  if (relativeCellPos == null) return null;
42871
43281
  const rect = map.findCell(relativeCellPos);
@@ -43039,7 +43449,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
43039
43449
  const tableRect = context.tableDom.getBoundingClientRect();
43040
43450
  const tableLeft = tableRect.left - containerRect.left + container.scrollLeft;
43041
43451
  const tableTop = tableRect.top - containerRect.top + container.scrollTop;
43042
- const map = import_tables8.TableMap.get(context.tableNode);
43452
+ const map = import_tables9.TableMap.get(context.tableNode);
43043
43453
  const columnSegments = Array(map.width);
43044
43454
  const rowSegments = Array(map.height);
43045
43455
  const cellInfos = [];