@univerjs/design 0.22.1 → 0.23.0-insiders.20260522-e8f2a3b

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/lib/cjs/index.js CHANGED
@@ -6,6 +6,7 @@ let tailwind_merge = require("tailwind-merge");
6
6
  let react_jsx_runtime = require("react/jsx-runtime");
7
7
  let class_variance_authority = require("class-variance-authority");
8
8
  let _radix_ui_react_slot = require("@radix-ui/react-slot");
9
+ let _radix_ui_react_direction = require("@radix-ui/react-direction");
9
10
  let _radix_ui_react_dialog = require("@radix-ui/react-dialog");
10
11
  let _radix_ui_react_popover = require("@radix-ui/react-popover");
11
12
  let react_dom = require("react-dom");
@@ -261,16 +262,24 @@ function isBrowser() {
261
262
  //#region src/components/config-provider/ConfigProvider.tsx
262
263
  const ConfigContext = (0, react.createContext)({ mountContainer: isBrowser() ? document.body : null });
263
264
  function ConfigProvider(props) {
264
- const { children, locale, mountContainer } = props;
265
+ const { children, locale, mountContainer, direction } = props;
265
266
  const value = (0, react.useMemo)(() => {
266
267
  return {
267
268
  locale,
269
+ direction,
268
270
  mountContainer
269
271
  };
270
- }, [locale, mountContainer]);
272
+ }, [
273
+ locale,
274
+ direction,
275
+ mountContainer
276
+ ]);
271
277
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigContext.Provider, {
272
278
  value,
273
- children
279
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_direction.DirectionProvider, {
280
+ dir: direction !== null && direction !== void 0 ? direction : "ltr",
281
+ children
282
+ })
274
283
  });
275
284
  }
276
285
 
@@ -910,6 +919,7 @@ function Dialog(props) {
910
919
  * limitations under the License.
911
920
  */
912
921
  const hsvToRgb = (h, s, v) => {
922
+ h = h % 360;
913
923
  s = s / 100;
914
924
  v = v / 100;
915
925
  const c = v * s;
@@ -1020,6 +1030,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1020
1030
  const [isDragging, setIsDragging] = (0, react.useState)(false);
1021
1031
  const sliderRef = (0, react.useRef)(null);
1022
1032
  const thumbRef = (0, react.useRef)(null);
1033
+ const alphaRef = (0, react.useRef)(alpha);
1023
1034
  const calculateAlpha = (0, react.useCallback)((clientX) => {
1024
1035
  var _thumbRef$current$cli, _thumbRef$current;
1025
1036
  const slider = sliderRef.current;
@@ -1038,10 +1049,13 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1038
1049
  if (!isDragging) return;
1039
1050
  calculateAlpha(e.clientX);
1040
1051
  }, [isDragging, calculateAlpha]);
1052
+ (0, react.useEffect)(() => {
1053
+ alphaRef.current = alpha;
1054
+ }, [alpha]);
1041
1055
  const handlePointerUp = (0, react.useCallback)(() => {
1042
1056
  setIsDragging(false);
1043
- onChanged === null || onChanged === void 0 || onChanged(alpha);
1044
- }, [alpha]);
1057
+ onChanged === null || onChanged === void 0 || onChanged(alphaRef.current);
1058
+ }, [onChanged]);
1045
1059
  (0, react.useEffect)(() => {
1046
1060
  if (isDragging) {
1047
1061
  window.addEventListener("pointermove", handlePointerMove);
@@ -1068,6 +1082,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1068
1082
  };
1069
1083
  const color = hsvToRgb(...hsv);
1070
1084
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1085
+ "data-u-comp": "color-picker-alpha-slider",
1071
1086
  className: "univer-relative univer-w-full univer-select-none",
1072
1087
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1073
1088
  className: "univer-absolute univer-inset-0 univer-rounded-full",
@@ -1078,6 +1093,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1078
1093
  }
1079
1094
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1080
1095
  ref: sliderRef,
1096
+ "data-u-comp": "color-picker-alpha-slider-track",
1081
1097
  className: "univer-relative univer-h-2 univer-w-full univer-cursor-pointer univer-rounded-full univer-shadow-inner",
1082
1098
  style: { background: `linear-gradient(to right, transparent, rgb(${color.join(",")}))` },
1083
1099
  onPointerDown: (e) => {
@@ -1086,6 +1102,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1086
1102
  },
1087
1103
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1088
1104
  ref: thumbRef,
1105
+ "data-u-comp": "color-picker-alpha-slider-thumb",
1089
1106
  className: "univer-absolute univer-top-1/2 univer-box-border univer-size-2 univer-rounded-full univer-bg-transparent univer-shadow-md univer-ring-2 univer-ring-white univer-transition-transform univer-duration-75 univer-will-change-transform",
1090
1107
  style: {
1091
1108
  left: getThumbPosition(),
@@ -1365,7 +1382,7 @@ function ColorSpectrum({ hsv, onChange, onChanged }) {
1365
1382
  gradientV.addColorStop(1, "rgba(0, 0, 0, 1)");
1366
1383
  ctx.fillStyle = gradientV;
1367
1384
  ctx.fillRect(0, 0, canvas.width, canvas.height);
1368
- }, [hsv]);
1385
+ }, [hsv[0]]);
1369
1386
  const handlePointerEvent = (e) => {
1370
1387
  e.stopPropagation();
1371
1388
  const canvas = canvasRef.current;
@@ -1379,7 +1396,7 @@ function ColorSpectrum({ hsv, onChange, onChanged }) {
1379
1396
  };
1380
1397
  const handlePointerUp = (0, react.useCallback)(() => {
1381
1398
  setIsDragging(false);
1382
- }, [hsv]);
1399
+ }, []);
1383
1400
  function handleChange() {
1384
1401
  onChanged === null || onChanged === void 0 || onChanged(hsv[0], hsv[1], hsv[2]);
1385
1402
  }
@@ -1422,6 +1439,7 @@ function ColorSpectrum({ hsv, onChange, onChanged }) {
1422
1439
  className: "univer-relative univer-overflow-hidden",
1423
1440
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("canvas", {
1424
1441
  ref: canvasRef,
1442
+ "data-u-comp": "color-picker-spectrum-canvas",
1425
1443
  className: "univer-size-full univer-cursor-crosshair univer-rounded",
1426
1444
  onPointerDown: (e) => {
1427
1445
  setIsDragging(true);
@@ -1456,6 +1474,7 @@ function HueSlider({ hsv, onChange, onChanged }) {
1456
1474
  const [isDragging, setIsDragging] = (0, react.useState)(false);
1457
1475
  const sliderRef = (0, react.useRef)(null);
1458
1476
  const thumbRef = (0, react.useRef)(null);
1477
+ const hsvRef = (0, react.useRef)(hsv);
1459
1478
  const calculateHue = (0, react.useCallback)((clientX) => {
1460
1479
  var _thumbRef$current$cli, _thumbRef$current;
1461
1480
  const slider = sliderRef.current;
@@ -1475,10 +1494,14 @@ function HueSlider({ hsv, onChange, onChanged }) {
1475
1494
  if (!isDragging) return;
1476
1495
  calculateHue(e.clientX);
1477
1496
  }, [isDragging, calculateHue]);
1497
+ (0, react.useEffect)(() => {
1498
+ hsvRef.current = hsv;
1499
+ }, [hsv]);
1478
1500
  const handlePointerUp = (0, react.useCallback)(() => {
1479
1501
  setIsDragging(false);
1480
- onChanged === null || onChanged === void 0 || onChanged(hsv[0], hsv[1], hsv[2]);
1481
- }, [hsv, onChanged]);
1502
+ const [h, s, v] = hsvRef.current;
1503
+ onChanged === null || onChanged === void 0 || onChanged(h, s, v);
1504
+ }, [onChanged]);
1482
1505
  (0, react.useEffect)(() => {
1483
1506
  if (isDragging) {
1484
1507
  window.addEventListener("pointermove", handlePointerMove);
@@ -1523,6 +1546,7 @@ function HueSlider({ hsv, onChange, onChanged }) {
1523
1546
  },
1524
1547
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1525
1548
  ref: thumbRef,
1549
+ "data-u-comp": "color-picker-hue-slider-thumb",
1526
1550
  className: "univer-absolute univer-top-1/2 univer-box-border univer-size-2 univer-rounded-full univer-bg-transparent univer-shadow-md univer-ring-2 univer-ring-white univer-transition-transform univer-duration-75 univer-will-change-transform",
1527
1551
  style: {
1528
1552
  left: getThumbPosition(),
@@ -1925,6 +1949,7 @@ function DraggableList(props) {
1925
1949
  const pressedHandleIdRef = (0, react.useRef)(null);
1926
1950
  const dragSourceIdRef = (0, react.useRef)(null);
1927
1951
  const dragStartIndexRef = (0, react.useRef)(-1);
1952
+ const { direction } = (0, react.useContext)(ConfigContext);
1928
1953
  (0, react.useEffect)(() => {
1929
1954
  if (!draggingId) {
1930
1955
  setDisplayList(list);
@@ -2057,6 +2082,7 @@ function DraggableList(props) {
2057
2082
  }, itemId);
2058
2083
  })
2059
2084
  }), canUsePortal && draggingItem && ghostPosition && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2085
+ dir: direction,
2060
2086
  className: clsx$1("univer-pointer-events-none univer-fixed univer-rounded-md univer-border univer-border-gray-200 univer-bg-white univer-shadow-lg dark:!univer-border-gray-700 dark:!univer-bg-gray-800"),
2061
2087
  style: {
2062
2088
  zIndex: 2147483647,
@@ -2389,6 +2415,7 @@ function Gallery(props) {
2389
2415
  const [isVisible, setIsVisible] = (0, react.useState)(false);
2390
2416
  const [activeImageIndex, setActiveImageIndex] = (0, react.useState)(0);
2391
2417
  const [zoomLevel, setZoomLevel] = (0, react.useState)(1);
2418
+ const { direction } = (0, react.useContext)(ConfigContext);
2392
2419
  const dialogRef = (0, react.useRef)(null);
2393
2420
  const activeImage = (0, react.useMemo)(() => images[activeImageIndex], [activeImageIndex, images]);
2394
2421
  (0, react.useEffect)(() => {
@@ -2436,6 +2463,7 @@ function Gallery(props) {
2436
2463
  }
2437
2464
  return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2438
2465
  "data-u-comp": "gallery",
2466
+ dir: direction,
2439
2467
  role: "dialog",
2440
2468
  "aria-modal": "true",
2441
2469
  "aria-label": "Image gallery",
@@ -2829,6 +2857,7 @@ function Segmented({ items, value, defaultValue, onChange, className = "" }) {
2829
2857
  //#region src/components/tooltip/Tooltip.tsx
2830
2858
  function Tooltip(props) {
2831
2859
  const { children, className, asChild = true, title, placement = "bottom", showIfEllipsis = false, visible: controlledVisible, onVisibleChange } = props;
2860
+ const { direction } = (0, react.useContext)(ConfigContext);
2832
2861
  const [uncontrolledVisible, setUncontrolledVisible] = (0, react.useState)(false);
2833
2862
  const isControlled = controlledVisible !== void 0;
2834
2863
  const visible = isControlled ? controlledVisible : uncontrolledVisible;
@@ -2971,6 +3000,7 @@ function Tooltip(props) {
2971
3000
  var _coords$top, _coords$left;
2972
3001
  tooltipNode = (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2973
3002
  ref: tooltipRef,
3003
+ dir: direction,
2974
3004
  role: "tooltip",
2975
3005
  className: clsx$1("univer-animate-in univer-fade-in-0 univer-zoom-in-95 univer-pointer-events-auto univer-absolute univer-z-[1081] univer-box-border univer-w-fit univer-max-w-sm univer-text-balance univer-rounded-lg univer-bg-gray-700 univer-px-2.5 univer-py-2 univer-text-xs univer-font-medium univer-text-white univer-shadow-lg univer-drop-shadow-sm dark:!univer-bg-gray-100 dark:!univer-text-gray-900", className),
2976
3006
  style: {
@@ -3047,6 +3077,19 @@ function GradientColorPicker(props) {
3047
3077
  const { locale } = (0, react.useContext)(ConfigContext);
3048
3078
  const [selectedIndex, setSelectedIndex] = (0, react.useState)(0);
3049
3079
  const barRef = (0, react.useRef)(null);
3080
+ const cleanupRef = (0, react.useRef)(null);
3081
+ (0, react.useEffect)(() => {
3082
+ setSelectedIndex((prev) => {
3083
+ if (prev >= value.stops.length) return Math.max(0, value.stops.length - 1);
3084
+ return prev;
3085
+ });
3086
+ }, [value.stops.length]);
3087
+ (0, react.useEffect)(() => {
3088
+ return () => {
3089
+ var _cleanupRef$current;
3090
+ (_cleanupRef$current = cleanupRef.current) === null || _cleanupRef$current === void 0 || _cleanupRef$current.call(cleanupRef);
3091
+ };
3092
+ }, []);
3050
3093
  const stops = (0, react.useMemo)(() => {
3051
3094
  return [...value.stops].sort((a, b) => a.offset - b.offset);
3052
3095
  }, [value.stops]);
@@ -3148,6 +3191,7 @@ function GradientColorPicker(props) {
3148
3191
  onChange: (v) => handleTypeChange(v)
3149
3192
  }),
3150
3193
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3194
+ "data-u-comp": "gradient-color-picker-preview",
3151
3195
  className: "univer-h-32 univer-w-full univer-rounded-md univer-border univer-border-gray-200 dark:!univer-border-gray-600",
3152
3196
  style: { background: mainPreview }
3153
3197
  }),
@@ -3155,10 +3199,13 @@ function GradientColorPicker(props) {
3155
3199
  className: "univer-relative univer-mt-4 univer-h-6",
3156
3200
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3157
3201
  ref: barRef,
3202
+ "data-u-comp": "gradient-color-picker-bar",
3158
3203
  className: "univer-absolute univer-inset-x-0 univer-top-1/2 univer-h-2 -univer-translate-y-1/2 univer-cursor-crosshair univer-rounded-full",
3159
3204
  style: { background: gradientPreview },
3160
3205
  onClick: handleAddStop
3161
3206
  }), value.stops.map((stop, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3207
+ "data-u-comp": "gradient-color-picker-stop",
3208
+ "data-selected": selectedIndex === index,
3162
3209
  className: clsx$1("univer-absolute univer-top-1/2 univer-size-4 -univer-translate-x-1/2 -univer-translate-y-1/2 univer-cursor-pointer univer-rounded-full univer-border-2 univer-border-white univer-shadow-md", selectedIndex === index ? "univer-z-10 univer-ring-2 univer-ring-primary-500" : "univer-z-0"),
3163
3210
  style: {
3164
3211
  left: `${stop.offset}%`,
@@ -3189,7 +3236,9 @@ function GradientColorPicker(props) {
3189
3236
  const handlePointerUp = () => {
3190
3237
  window.removeEventListener("pointermove", handlePointerMove);
3191
3238
  window.removeEventListener("pointerup", handlePointerUp);
3239
+ cleanupRef.current = null;
3192
3240
  };
3241
+ cleanupRef.current = handlePointerUp;
3193
3242
  window.addEventListener("pointermove", handlePointerMove);
3194
3243
  window.addEventListener("pointerup", handlePointerUp);
3195
3244
  }
@@ -3227,6 +3276,7 @@ function GradientColorPicker(props) {
3227
3276
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tooltip, {
3228
3277
  title: locale === null || locale === void 0 ? void 0 : locale.GradientColorPicker.delete,
3229
3278
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
3279
+ "data-u-comp": "gradient-color-picker-delete",
3230
3280
  variant: "danger",
3231
3281
  onClick: handleRemoveStop,
3232
3282
  disabled: value.stops.length <= 2,
@@ -3434,7 +3484,7 @@ function Popup(props) {
3434
3484
  const { children, visible = false, offset = [0, 0], overflowVisible = false, placementY = "below" } = props;
3435
3485
  const nodeRef = (0, react.useRef)(null);
3436
3486
  const [realOffset, setRealOffset] = (0, react.useState)(HIDDEN_POPUP_OFFSET);
3437
- const { mountContainer } = (0, react.useContext)(ConfigContext);
3487
+ const { mountContainer, direction } = (0, react.useContext)(ConfigContext);
3438
3488
  const calculateOffset = () => {
3439
3489
  const element = nodeRef.current;
3440
3490
  if (!element) return null;
@@ -3490,6 +3540,7 @@ function Popup(props) {
3490
3540
  },
3491
3541
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
3492
3542
  ref: nodeRef,
3543
+ dir: direction,
3493
3544
  className: "univer-popup",
3494
3545
  style: {
3495
3546
  left: realOffset[0] + POPUP_POINTER_OFFSET,
package/lib/es/index.js CHANGED
@@ -5,6 +5,7 @@ import { twMerge } from "tailwind-merge";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { cva } from "class-variance-authority";
7
7
  import { Slot } from "@radix-ui/react-slot";
8
+ import { DirectionProvider } from "@radix-ui/react-direction";
8
9
  import { Close, Content, Description, Overlay, Portal, Root, Title } from "@radix-ui/react-dialog";
9
10
  import { Content as Content$1, Portal as Portal$1, Root as Root$1, Trigger } from "@radix-ui/react-popover";
10
11
  import { createPortal } from "react-dom";
@@ -260,16 +261,24 @@ function isBrowser() {
260
261
  //#region src/components/config-provider/ConfigProvider.tsx
261
262
  const ConfigContext = createContext({ mountContainer: isBrowser() ? document.body : null });
262
263
  function ConfigProvider(props) {
263
- const { children, locale, mountContainer } = props;
264
+ const { children, locale, mountContainer, direction } = props;
264
265
  const value = useMemo(() => {
265
266
  return {
266
267
  locale,
268
+ direction,
267
269
  mountContainer
268
270
  };
269
- }, [locale, mountContainer]);
271
+ }, [
272
+ locale,
273
+ direction,
274
+ mountContainer
275
+ ]);
270
276
  return /* @__PURE__ */ jsx(ConfigContext.Provider, {
271
277
  value,
272
- children
278
+ children: /* @__PURE__ */ jsx(DirectionProvider, {
279
+ dir: direction !== null && direction !== void 0 ? direction : "ltr",
280
+ children
281
+ })
273
282
  });
274
283
  }
275
284
 
@@ -909,6 +918,7 @@ function Dialog(props) {
909
918
  * limitations under the License.
910
919
  */
911
920
  const hsvToRgb = (h, s, v) => {
921
+ h = h % 360;
912
922
  s = s / 100;
913
923
  v = v / 100;
914
924
  const c = v * s;
@@ -1019,6 +1029,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1019
1029
  const [isDragging, setIsDragging] = useState(false);
1020
1030
  const sliderRef = useRef(null);
1021
1031
  const thumbRef = useRef(null);
1032
+ const alphaRef = useRef(alpha);
1022
1033
  const calculateAlpha = useCallback((clientX) => {
1023
1034
  var _thumbRef$current$cli, _thumbRef$current;
1024
1035
  const slider = sliderRef.current;
@@ -1037,10 +1048,13 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1037
1048
  if (!isDragging) return;
1038
1049
  calculateAlpha(e.clientX);
1039
1050
  }, [isDragging, calculateAlpha]);
1051
+ useEffect(() => {
1052
+ alphaRef.current = alpha;
1053
+ }, [alpha]);
1040
1054
  const handlePointerUp = useCallback(() => {
1041
1055
  setIsDragging(false);
1042
- onChanged === null || onChanged === void 0 || onChanged(alpha);
1043
- }, [alpha]);
1056
+ onChanged === null || onChanged === void 0 || onChanged(alphaRef.current);
1057
+ }, [onChanged]);
1044
1058
  useEffect(() => {
1045
1059
  if (isDragging) {
1046
1060
  window.addEventListener("pointermove", handlePointerMove);
@@ -1067,6 +1081,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1067
1081
  };
1068
1082
  const color = hsvToRgb(...hsv);
1069
1083
  return /* @__PURE__ */ jsxs("div", {
1084
+ "data-u-comp": "color-picker-alpha-slider",
1070
1085
  className: "univer-relative univer-w-full univer-select-none",
1071
1086
  children: [/* @__PURE__ */ jsx("div", {
1072
1087
  className: "univer-absolute univer-inset-0 univer-rounded-full",
@@ -1077,6 +1092,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1077
1092
  }
1078
1093
  }), /* @__PURE__ */ jsx("div", {
1079
1094
  ref: sliderRef,
1095
+ "data-u-comp": "color-picker-alpha-slider-track",
1080
1096
  className: "univer-relative univer-h-2 univer-w-full univer-cursor-pointer univer-rounded-full univer-shadow-inner",
1081
1097
  style: { background: `linear-gradient(to right, transparent, rgb(${color.join(",")}))` },
1082
1098
  onPointerDown: (e) => {
@@ -1085,6 +1101,7 @@ function AlphaSlider({ hsv, alpha, onChange, onChanged }) {
1085
1101
  },
1086
1102
  children: /* @__PURE__ */ jsx("div", {
1087
1103
  ref: thumbRef,
1104
+ "data-u-comp": "color-picker-alpha-slider-thumb",
1088
1105
  className: "univer-absolute univer-top-1/2 univer-box-border univer-size-2 univer-rounded-full univer-bg-transparent univer-shadow-md univer-ring-2 univer-ring-white univer-transition-transform univer-duration-75 univer-will-change-transform",
1089
1106
  style: {
1090
1107
  left: getThumbPosition(),
@@ -1364,7 +1381,7 @@ function ColorSpectrum({ hsv, onChange, onChanged }) {
1364
1381
  gradientV.addColorStop(1, "rgba(0, 0, 0, 1)");
1365
1382
  ctx.fillStyle = gradientV;
1366
1383
  ctx.fillRect(0, 0, canvas.width, canvas.height);
1367
- }, [hsv]);
1384
+ }, [hsv[0]]);
1368
1385
  const handlePointerEvent = (e) => {
1369
1386
  e.stopPropagation();
1370
1387
  const canvas = canvasRef.current;
@@ -1378,7 +1395,7 @@ function ColorSpectrum({ hsv, onChange, onChanged }) {
1378
1395
  };
1379
1396
  const handlePointerUp = useCallback(() => {
1380
1397
  setIsDragging(false);
1381
- }, [hsv]);
1398
+ }, []);
1382
1399
  function handleChange() {
1383
1400
  onChanged === null || onChanged === void 0 || onChanged(hsv[0], hsv[1], hsv[2]);
1384
1401
  }
@@ -1421,6 +1438,7 @@ function ColorSpectrum({ hsv, onChange, onChanged }) {
1421
1438
  className: "univer-relative univer-overflow-hidden",
1422
1439
  children: [/* @__PURE__ */ jsx("canvas", {
1423
1440
  ref: canvasRef,
1441
+ "data-u-comp": "color-picker-spectrum-canvas",
1424
1442
  className: "univer-size-full univer-cursor-crosshair univer-rounded",
1425
1443
  onPointerDown: (e) => {
1426
1444
  setIsDragging(true);
@@ -1455,6 +1473,7 @@ function HueSlider({ hsv, onChange, onChanged }) {
1455
1473
  const [isDragging, setIsDragging] = useState(false);
1456
1474
  const sliderRef = useRef(null);
1457
1475
  const thumbRef = useRef(null);
1476
+ const hsvRef = useRef(hsv);
1458
1477
  const calculateHue = useCallback((clientX) => {
1459
1478
  var _thumbRef$current$cli, _thumbRef$current;
1460
1479
  const slider = sliderRef.current;
@@ -1474,10 +1493,14 @@ function HueSlider({ hsv, onChange, onChanged }) {
1474
1493
  if (!isDragging) return;
1475
1494
  calculateHue(e.clientX);
1476
1495
  }, [isDragging, calculateHue]);
1496
+ useEffect(() => {
1497
+ hsvRef.current = hsv;
1498
+ }, [hsv]);
1477
1499
  const handlePointerUp = useCallback(() => {
1478
1500
  setIsDragging(false);
1479
- onChanged === null || onChanged === void 0 || onChanged(hsv[0], hsv[1], hsv[2]);
1480
- }, [hsv, onChanged]);
1501
+ const [h, s, v] = hsvRef.current;
1502
+ onChanged === null || onChanged === void 0 || onChanged(h, s, v);
1503
+ }, [onChanged]);
1481
1504
  useEffect(() => {
1482
1505
  if (isDragging) {
1483
1506
  window.addEventListener("pointermove", handlePointerMove);
@@ -1522,6 +1545,7 @@ function HueSlider({ hsv, onChange, onChanged }) {
1522
1545
  },
1523
1546
  children: /* @__PURE__ */ jsx("div", {
1524
1547
  ref: thumbRef,
1548
+ "data-u-comp": "color-picker-hue-slider-thumb",
1525
1549
  className: "univer-absolute univer-top-1/2 univer-box-border univer-size-2 univer-rounded-full univer-bg-transparent univer-shadow-md univer-ring-2 univer-ring-white univer-transition-transform univer-duration-75 univer-will-change-transform",
1526
1550
  style: {
1527
1551
  left: getThumbPosition(),
@@ -1924,6 +1948,7 @@ function DraggableList(props) {
1924
1948
  const pressedHandleIdRef = useRef(null);
1925
1949
  const dragSourceIdRef = useRef(null);
1926
1950
  const dragStartIndexRef = useRef(-1);
1951
+ const { direction } = useContext(ConfigContext);
1927
1952
  useEffect(() => {
1928
1953
  if (!draggingId) {
1929
1954
  setDisplayList(list);
@@ -2056,6 +2081,7 @@ function DraggableList(props) {
2056
2081
  }, itemId);
2057
2082
  })
2058
2083
  }), canUsePortal && draggingItem && ghostPosition && createPortal(/* @__PURE__ */ jsx("div", {
2084
+ dir: direction,
2059
2085
  className: clsx("univer-pointer-events-none univer-fixed univer-rounded-md univer-border univer-border-gray-200 univer-bg-white univer-shadow-lg dark:!univer-border-gray-700 dark:!univer-bg-gray-800"),
2060
2086
  style: {
2061
2087
  zIndex: 2147483647,
@@ -2388,6 +2414,7 @@ function Gallery(props) {
2388
2414
  const [isVisible, setIsVisible] = useState(false);
2389
2415
  const [activeImageIndex, setActiveImageIndex] = useState(0);
2390
2416
  const [zoomLevel, setZoomLevel] = useState(1);
2417
+ const { direction } = useContext(ConfigContext);
2391
2418
  const dialogRef = useRef(null);
2392
2419
  const activeImage = useMemo(() => images[activeImageIndex], [activeImageIndex, images]);
2393
2420
  useEffect(() => {
@@ -2435,6 +2462,7 @@ function Gallery(props) {
2435
2462
  }
2436
2463
  return createPortal(/* @__PURE__ */ jsxs("div", {
2437
2464
  "data-u-comp": "gallery",
2465
+ dir: direction,
2438
2466
  role: "dialog",
2439
2467
  "aria-modal": "true",
2440
2468
  "aria-label": "Image gallery",
@@ -2828,6 +2856,7 @@ function Segmented({ items, value, defaultValue, onChange, className = "" }) {
2828
2856
  //#region src/components/tooltip/Tooltip.tsx
2829
2857
  function Tooltip(props) {
2830
2858
  const { children, className, asChild = true, title, placement = "bottom", showIfEllipsis = false, visible: controlledVisible, onVisibleChange } = props;
2859
+ const { direction } = useContext(ConfigContext);
2831
2860
  const [uncontrolledVisible, setUncontrolledVisible] = useState(false);
2832
2861
  const isControlled = controlledVisible !== void 0;
2833
2862
  const visible = isControlled ? controlledVisible : uncontrolledVisible;
@@ -2970,6 +2999,7 @@ function Tooltip(props) {
2970
2999
  var _coords$top, _coords$left;
2971
3000
  tooltipNode = createPortal(/* @__PURE__ */ jsxs("div", {
2972
3001
  ref: tooltipRef,
3002
+ dir: direction,
2973
3003
  role: "tooltip",
2974
3004
  className: clsx("univer-animate-in univer-fade-in-0 univer-zoom-in-95 univer-pointer-events-auto univer-absolute univer-z-[1081] univer-box-border univer-w-fit univer-max-w-sm univer-text-balance univer-rounded-lg univer-bg-gray-700 univer-px-2.5 univer-py-2 univer-text-xs univer-font-medium univer-text-white univer-shadow-lg univer-drop-shadow-sm dark:!univer-bg-gray-100 dark:!univer-text-gray-900", className),
2975
3005
  style: {
@@ -3046,6 +3076,19 @@ function GradientColorPicker(props) {
3046
3076
  const { locale } = useContext(ConfigContext);
3047
3077
  const [selectedIndex, setSelectedIndex] = useState(0);
3048
3078
  const barRef = useRef(null);
3079
+ const cleanupRef = useRef(null);
3080
+ useEffect(() => {
3081
+ setSelectedIndex((prev) => {
3082
+ if (prev >= value.stops.length) return Math.max(0, value.stops.length - 1);
3083
+ return prev;
3084
+ });
3085
+ }, [value.stops.length]);
3086
+ useEffect(() => {
3087
+ return () => {
3088
+ var _cleanupRef$current;
3089
+ (_cleanupRef$current = cleanupRef.current) === null || _cleanupRef$current === void 0 || _cleanupRef$current.call(cleanupRef);
3090
+ };
3091
+ }, []);
3049
3092
  const stops = useMemo(() => {
3050
3093
  return [...value.stops].sort((a, b) => a.offset - b.offset);
3051
3094
  }, [value.stops]);
@@ -3147,6 +3190,7 @@ function GradientColorPicker(props) {
3147
3190
  onChange: (v) => handleTypeChange(v)
3148
3191
  }),
3149
3192
  /* @__PURE__ */ jsx("div", {
3193
+ "data-u-comp": "gradient-color-picker-preview",
3150
3194
  className: "univer-h-32 univer-w-full univer-rounded-md univer-border univer-border-gray-200 dark:!univer-border-gray-600",
3151
3195
  style: { background: mainPreview }
3152
3196
  }),
@@ -3154,10 +3198,13 @@ function GradientColorPicker(props) {
3154
3198
  className: "univer-relative univer-mt-4 univer-h-6",
3155
3199
  children: [/* @__PURE__ */ jsx("div", {
3156
3200
  ref: barRef,
3201
+ "data-u-comp": "gradient-color-picker-bar",
3157
3202
  className: "univer-absolute univer-inset-x-0 univer-top-1/2 univer-h-2 -univer-translate-y-1/2 univer-cursor-crosshair univer-rounded-full",
3158
3203
  style: { background: gradientPreview },
3159
3204
  onClick: handleAddStop
3160
3205
  }), value.stops.map((stop, index) => /* @__PURE__ */ jsx("div", {
3206
+ "data-u-comp": "gradient-color-picker-stop",
3207
+ "data-selected": selectedIndex === index,
3161
3208
  className: clsx("univer-absolute univer-top-1/2 univer-size-4 -univer-translate-x-1/2 -univer-translate-y-1/2 univer-cursor-pointer univer-rounded-full univer-border-2 univer-border-white univer-shadow-md", selectedIndex === index ? "univer-z-10 univer-ring-2 univer-ring-primary-500" : "univer-z-0"),
3162
3209
  style: {
3163
3210
  left: `${stop.offset}%`,
@@ -3188,7 +3235,9 @@ function GradientColorPicker(props) {
3188
3235
  const handlePointerUp = () => {
3189
3236
  window.removeEventListener("pointermove", handlePointerMove);
3190
3237
  window.removeEventListener("pointerup", handlePointerUp);
3238
+ cleanupRef.current = null;
3191
3239
  };
3240
+ cleanupRef.current = handlePointerUp;
3192
3241
  window.addEventListener("pointermove", handlePointerMove);
3193
3242
  window.addEventListener("pointerup", handlePointerUp);
3194
3243
  }
@@ -3226,6 +3275,7 @@ function GradientColorPicker(props) {
3226
3275
  children: /* @__PURE__ */ jsx(Tooltip, {
3227
3276
  title: locale === null || locale === void 0 ? void 0 : locale.GradientColorPicker.delete,
3228
3277
  children: /* @__PURE__ */ jsx(Button, {
3278
+ "data-u-comp": "gradient-color-picker-delete",
3229
3279
  variant: "danger",
3230
3280
  onClick: handleRemoveStop,
3231
3281
  disabled: value.stops.length <= 2,
@@ -3433,7 +3483,7 @@ function Popup(props) {
3433
3483
  const { children, visible = false, offset = [0, 0], overflowVisible = false, placementY = "below" } = props;
3434
3484
  const nodeRef = useRef(null);
3435
3485
  const [realOffset, setRealOffset] = useState(HIDDEN_POPUP_OFFSET);
3436
- const { mountContainer } = useContext(ConfigContext);
3486
+ const { mountContainer, direction } = useContext(ConfigContext);
3437
3487
  const calculateOffset = () => {
3438
3488
  const element = nodeRef.current;
3439
3489
  if (!element) return null;
@@ -3489,6 +3539,7 @@ function Popup(props) {
3489
3539
  },
3490
3540
  children: /* @__PURE__ */ jsx("section", {
3491
3541
  ref: nodeRef,
3542
+ dir: direction,
3492
3543
  className: "univer-popup",
3493
3544
  style: {
3494
3545
  left: realOffset[0] + POPUP_POINTER_OFFSET,