@beppla/tapas-ui 1.0.54 → 1.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/components/DataCell/DataCell.tsx +186 -14
  2. package/components/Grid/StaticFixedSizeGrid.tsx +21 -10
  3. package/package/commonjs/DataCell/DataCell.js +172 -14
  4. package/package/commonjs/DataCell/DataCell.js.map +1 -1
  5. package/package/commonjs/Grid/StaticFixedSizeGrid.js +23 -11
  6. package/package/commonjs/Grid/StaticFixedSizeGrid.js.map +1 -1
  7. package/package/module/DataCell/DataCell.js +172 -15
  8. package/package/module/DataCell/DataCell.js.map +1 -1
  9. package/package/module/Grid/StaticFixedSizeGrid.js +23 -11
  10. package/package/module/Grid/StaticFixedSizeGrid.js.map +1 -1
  11. package/package/typescript/DataCell/DataCell.d.ts +10 -1
  12. package/package/typescript/DataCell/DataCell.d.ts.map +1 -1
  13. package/package/typescript/Grid/StaticFixedSizeGrid.d.ts.map +1 -1
  14. package/package.json +1 -1
  15. package/package/CHANGELOG.md +0 -351
  16. package/package/README.md +0 -103
  17. package/package/assets/assets/adaptive-icon.png +0 -0
  18. package/package/assets/assets/favicon.png +0 -0
  19. package/package/assets/assets/fonts/customfont.ttf +0 -0
  20. package/package/assets/assets/icon.png +0 -0
  21. package/package/assets/assets/logo.png +0 -0
  22. package/package/assets/assets/splash.png +0 -0
  23. package/package/assets/assets/svg/customfont.svg +0 -332
  24. package/package/assets/assets/svg/logo.svg +0 -9
  25. package/package/assets/assets/tapas/favicon.png +0 -0
  26. package/package/assets/assets/tapas/logo.png +0 -0
  27. package/package/assets/assets/tapas/logo_no_word.png +0 -0
  28. package/package/assets/assets/tapas/logo_transparent_white.png +0 -0
  29. package/package/init.js +0 -179
  30. package/package/package.json +0 -84
@@ -1,9 +1,50 @@
1
- import React, { useCallback, useMemo, useState } from "react";
1
+ import React, { useCallback, useMemo, useState, useEffect } from "react";
2
2
  import { View, Text, Pressable, ViewProps, TextStyle, StyleProp } from "react-native";
3
3
  import { withTheme, makeStyles } from "@rneui/themed";
4
4
  import TapasIcon from "../Icons/TapasIcon";
5
5
  // import { TapasDropdown } from "../Dropdown/Dropdown";
6
6
 
7
+ // 全局下拉菜单状态管理
8
+ const globalDropdownState: {
9
+ activeColumn: number | null;
10
+ activeRow: number | null;
11
+ closeAll: () => void;
12
+ onDropdownStateChange?: (columnIndex: number | null, rowIndex: number | null) => void;
13
+ } = {
14
+ activeColumn: null,
15
+ activeRow: null,
16
+ closeAll: () => {},
17
+ onDropdownStateChange: undefined,
18
+ };
19
+
20
+ // 注册和注销下拉菜单的函数
21
+ const registerDropdown = (columnIndex: number, rowIndex: number, closeCallback: () => void) => {
22
+ globalDropdownState.activeColumn = columnIndex;
23
+ globalDropdownState.activeRow = rowIndex;
24
+ globalDropdownState.closeAll = closeCallback;
25
+ // 通知状态变化
26
+ globalDropdownState.onDropdownStateChange?.(columnIndex, rowIndex);
27
+ };
28
+
29
+ const unregisterDropdown = () => {
30
+ globalDropdownState.activeColumn = null;
31
+ globalDropdownState.activeRow = null;
32
+ globalDropdownState.closeAll = () => {};
33
+ // 通知状态变化
34
+ globalDropdownState.onDropdownStateChange?.(null, null);
35
+ };
36
+
37
+ const closeAllDropdowns = () => {
38
+ if (globalDropdownState.closeAll) {
39
+ globalDropdownState.closeAll();
40
+ }
41
+ };
42
+
43
+ // 设置下拉菜单状态变化监听器
44
+ const setDropdownStateChangeListener = (callback: (columnIndex: number | null, rowIndex: number | null) => void) => {
45
+ globalDropdownState.onDropdownStateChange = callback;
46
+ };
47
+
7
48
  export type DataType =
8
49
  | "text"
9
50
  | "number"
@@ -90,6 +131,14 @@ export interface TapasDataCellProps extends ViewProps {
90
131
  minHeight?: number;
91
132
  /** 是否为空白单元格 */
92
133
  isBlank?: boolean;
134
+ /** 下拉菜单状态变化回调 */
135
+ onDropdownStateChange?: (isOpen: boolean) => void;
136
+ /** Grid 相关信息,用于计算下拉菜单位置 */
137
+ gridInfo?: {
138
+ totalRows?: number;
139
+ rowHeight?: number;
140
+ gridHeight?: number;
141
+ };
93
142
  }
94
143
 
95
144
  const TapasDataCell: React.FC<TapasDataCellProps> = ({
@@ -122,6 +171,8 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
122
171
  disabled = false,
123
172
  minHeight = 40,
124
173
  isBlank = false,
174
+ onDropdownStateChange,
175
+ gridInfo,
125
176
  style,
126
177
  ...otherProps
127
178
  }) => {
@@ -224,6 +275,111 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
224
275
  // 下拉菜单状态
225
276
  const [dropdownVisible, setDropdownVisible] = useState(false);
226
277
  const [dropdownPosition, setDropdownPosition] = useState({ top: 32, right: 0 });
278
+
279
+ // 计算下拉菜单的最佳位置
280
+ const calculateDropdownPosition = useCallback(() => {
281
+ // 更准确地计算下拉菜单的实际高度
282
+ const itemHeight = 32; // 每个选项的高度
283
+ const borderWidth = 2; // 边框宽度
284
+ const padding = 8; // 内边距
285
+ const shadowHeight = 4; // 阴影高度
286
+
287
+ // 考虑文本长度对高度的影响
288
+ const maxTextLength = Math.max(...actions.map(action => action.label.length));
289
+ const textHeightAdjustment = maxTextLength > 10 ? 4 : 0; // 长文本可能需要更多高度
290
+
291
+ // 计算下拉菜单的宽度(考虑文本长度)
292
+ // const minWidth = 120; // 最小宽度
293
+ // const textWidth = maxTextLength * 8; // 估算文本宽度
294
+ // const _actualWidth = Math.max(minWidth, textWidth + 24); // 24px 为内边距和图标空间
295
+
296
+ const actualHeight = actions.length * itemHeight + borderWidth + padding + shadowHeight + textHeightAdjustment;
297
+
298
+ const buttonHeight = 32; // 按钮高度
299
+ const cellHeight = gridInfo?.rowHeight || 56; // 使用传入的 rowHeight 或默认值
300
+ const gridHeight = gridInfo?.gridHeight || 400; // 使用传入的 gridHeight 或默认值
301
+
302
+ // 根据行索引估算当前单元格在 Grid 中的位置
303
+ const currentRowIndex = rowIndex || 0;
304
+
305
+ // 计算当前单元格距离 Grid 底部的距离
306
+ const currentCellBottom = (currentRowIndex + 1) * cellHeight;
307
+ const spaceBelow = gridHeight - currentCellBottom;
308
+
309
+ // 计算上方可用空间
310
+ const currentCellTop = currentRowIndex * cellHeight;
311
+ const spaceAbove = currentCellTop;
312
+
313
+ // 添加安全边距,确保下拉菜单不会紧贴边界
314
+ const safetyMargin = 8;
315
+ const requiredSpace = actualHeight + safetyMargin;
316
+
317
+ // 智能选择显示位置
318
+ if (requiredSpace > spaceBelow && requiredSpace <= spaceAbove) {
319
+ // 下方空间不够,但上方空间足够,显示在上方
320
+ return {
321
+ top: -actualHeight - 4, // 按钮上方,留 4px 间距
322
+ right: 0,
323
+ };
324
+ } else if (requiredSpace > spaceBelow && requiredSpace > spaceAbove) {
325
+ // 上下空间都不够,选择空间较大的一侧
326
+ if (spaceAbove > spaceBelow) {
327
+ return {
328
+ top: -actualHeight - 4, // 按钮上方
329
+ right: 0,
330
+ };
331
+ } else {
332
+ return {
333
+ top: buttonHeight + 4, // 按钮下方
334
+ right: 0,
335
+ };
336
+ }
337
+ } else {
338
+ // 下方空间足够,显示在下方
339
+ return {
340
+ top: buttonHeight + 4, // 按钮下方,留 4px 间距
341
+ right: 0,
342
+ };
343
+ }
344
+ }, [actions.length, rowIndex, gridInfo]);
345
+
346
+ // 全局下拉菜单管理
347
+ useEffect(() => {
348
+ const closeDropdown = () => {
349
+ setDropdownVisible(false);
350
+ unregisterDropdown();
351
+ };
352
+
353
+ // 注册当前下拉菜单
354
+ if (dropdownVisible) {
355
+ registerDropdown(columnIndex || 0, rowIndex || 0, closeDropdown);
356
+ } else {
357
+ unregisterDropdown();
358
+ }
359
+
360
+ // 清理函数
361
+ return () => {
362
+ unregisterDropdown();
363
+ };
364
+ }, [dropdownVisible, columnIndex, rowIndex]);
365
+
366
+ // 通知父组件下拉菜单状态变化
367
+ useEffect(() => {
368
+ onDropdownStateChange?.(dropdownVisible);
369
+ }, [dropdownVisible, onDropdownStateChange]);
370
+
371
+ // 监听全局关闭事件
372
+ useEffect(() => {
373
+ // const _handleGlobalClose = () => {
374
+ // if (globalDropdownState.activeColumn !== columnIndex ||
375
+ // globalDropdownState.activeRow !== rowIndex) {
376
+ // setDropdownVisible(false);
377
+ // }
378
+ // };
379
+
380
+ // 这里可以添加全局事件监听器
381
+ // 为了简化,我们在点击其他单元格时关闭当前下拉菜单
382
+ }, [columnIndex, rowIndex]);
227
383
 
228
384
  // 渲染操作按钮
229
385
  const renderActions = () => {
@@ -267,23 +423,34 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
267
423
 
268
424
  // 多个操作显示下拉菜单
269
425
  return (
270
- <View style={styles.dropdownContainer}>
426
+ <View style={[
427
+ styles.dropdownContainer,
428
+ {
429
+ // 只有当前激活的下拉菜单容器才有高 z-index
430
+ zIndex: globalDropdownState.activeColumn === columnIndex && globalDropdownState.activeRow === rowIndex ? 2147483646 : 1,
431
+ }
432
+ ]}>
271
433
  <Pressable
272
434
  style={styles.actionButton}
273
435
  onPress={(event) => {
274
436
  // 阻止事件冒泡,避免触发外层的 attachCellPress
275
437
  event.stopPropagation();
276
438
 
277
- if (!dropdownVisible) {
278
- // 在 React Native 中,我们使用相对定位
279
- // 由于 Grid 的 overflow: hidden 限制,我们使用更高的 z-index 和绝对定位
280
- setDropdownPosition({
281
- top: 32, // 按钮下方 32px
282
- right: 0, // 从右边缘对齐
283
- });
439
+ if (dropdownVisible) {
440
+ // 如果当前下拉菜单已经打开,直接关闭
441
+ setDropdownVisible(false);
442
+ } else {
443
+ // 如果当前下拉菜单关闭,先关闭其他所有下拉菜单,然后打开当前菜单
444
+ closeAllDropdowns();
445
+
446
+ // 计算并设置下拉菜单位置
447
+ setDropdownPosition(calculateDropdownPosition());
448
+
449
+ // 延迟打开当前下拉菜单,确保其他菜单已关闭
450
+ setTimeout(() => {
451
+ setDropdownVisible(true);
452
+ }, 0);
284
453
  }
285
-
286
- setDropdownVisible(!dropdownVisible);
287
454
  }}
288
455
  disabled={disabled}
289
456
  >
@@ -450,7 +617,10 @@ const useStyles = makeStyles((theme, props?: {
450
617
  },
451
618
  dropdownContainer: {
452
619
  position: "relative",
453
- zIndex: 1000,
620
+ // 默认使用较低的 z-index,只有激活的下拉菜单容器才有高 z-index
621
+ zIndex: 1,
622
+ // 确保容器本身不会创建新的 stacking context
623
+ isolation: "auto",
454
624
  },
455
625
  dropdownMenu: {
456
626
  position: "absolute", // 使用绝对定位
@@ -467,9 +637,11 @@ const useStyles = makeStyles((theme, props?: {
467
637
  shadowRadius: 3.84,
468
638
  elevation: 5,
469
639
  minWidth: 120,
470
- zIndex: 9999,
640
+ zIndex: 2147483647, // 更高的 z-index,确保显示在所有元素之上
471
641
  // 确保下拉菜单不被父容器的 overflow 隐藏
472
642
  overflow: "visible",
643
+ // 确保下拉菜单在正确的层级上
644
+ isolation: "isolate",
473
645
  },
474
646
  dropdownItem: {
475
647
  paddingHorizontal: 12,
@@ -495,4 +667,4 @@ export default withTheme(TapasDataCell);
495
667
 
496
668
  // Export aliases for compatibility
497
669
  export const DataCell = withTheme(TapasDataCell);
498
- export { TapasDataCell };
670
+ export { TapasDataCell, setDropdownStateChangeListener };
@@ -58,6 +58,7 @@ const ItemWrapper: React.FC<any> = ({ data, columnIndex, rowIndex, style }) => {
58
58
  columnHeaderHeight,
59
59
  border,
60
60
  theme,
61
+ hasActions,
61
62
  } = data;
62
63
 
63
64
  if (
@@ -68,13 +69,17 @@ const ItemWrapper: React.FC<any> = ({ data, columnIndex, rowIndex, style }) => {
68
69
  return null;
69
70
  }
70
71
 
72
+ // 检测当前列是否有 actions 按钮
73
+ const shouldShowActions = hasActions && hasActions(columnIndex ?? 0, rowIndex ?? 0);
74
+
71
75
  // 确保传递正确的参数给children函数
72
76
  const childrenProps: ChildrenProps = {
73
77
  columnIndex: columnIndex ?? 0,
74
78
  rowIndex: rowIndex ?? 0,
75
79
  style: {
76
80
  ...style,
77
- overflow: "visible",
81
+ // 根据 hasActions 决定是否允许 overflow: "visible"
82
+ overflow: shouldShowActions ? "visible" : "hidden",
78
83
  borderBottom: border
79
84
  ? `1px solid ${theme.grey3 ?? "rgba(0, 0, 0, 0.12)"}`
80
85
  : "none",
@@ -210,6 +215,7 @@ const InnerElementType = forwardRef(
210
215
  columnHeaderHeight,
211
216
  }}
212
217
  style={{
218
+ // 保持列头的 overflow: "hidden" 以确保正确的滚动行为
213
219
  overflow: "hidden",
214
220
  // borderTopLeftRadius: theme?.radius?.mini ?? 4,
215
221
  backgroundColor:
@@ -223,7 +229,11 @@ const InnerElementType = forwardRef(
223
229
  )}
224
230
  <div ref={ref} {...rest} style={{
225
231
  ...style,
226
- width: rest.width - stickyColumnsWidth // 使用正确的 grid 宽度减去 sticky 列宽度
232
+ width: totalWidth,
233
+ // width: rest.width, // 使用正确的 grid 宽度减去 sticky 列宽度
234
+ // width: rest.width - stickyColumnsWidth, // 使用正确的 grid 宽度减去 sticky 列宽度
235
+ // position: "sticky", // 固定容器位置,不随滚动移动
236
+ // left: 0, // 固定在左侧
227
237
  }}>
228
238
  {scrollLeft > 0 && (
229
239
  <StickyColumn
@@ -231,7 +241,7 @@ const InnerElementType = forwardRef(
231
241
  backgroundColor: theme?.background ?? "#F9F2E8",
232
242
  zIndex: 5,
233
243
  top: 0,
234
- width: stickyColumnsWidth,
244
+ width: 1, // 左侧阴影条宽度应该是 1
235
245
  height: height,
236
246
  left: 0,
237
247
  marginTop: headersRender ? -1 * (columnHeaderHeight || 40) : 0,
@@ -268,7 +278,7 @@ const InnerElementType = forwardRef(
268
278
  top: 0,
269
279
  width: stickyColumnsWidth,
270
280
  height: columnHeaderHeight || 40,
271
- left: width - stickyColumnsWidth - (border ? 1 : 0),
281
+ left: width - stickyColumnsWidth - (border ? 1 : 0), // 使用总宽度计算位置
272
282
  marginTop:
273
283
  scrollLeft === 0
274
284
  ? -1 * (columnHeaderHeight || 40)
@@ -278,7 +288,6 @@ const InnerElementType = forwardRef(
278
288
  borderLeft: border
279
289
  ? `1px solid ${theme?.grey3 ?? "rgba(0, 0, 0, 0.12)"}`
280
290
  : "none",
281
- // borderTopRightRadius: theme?.radius?.mini ?? 4,
282
291
  }}
283
292
  >
284
293
  <VariableSizeGrid
@@ -292,8 +301,7 @@ const InnerElementType = forwardRef(
292
301
  width={stickyColumnsWidth}
293
302
  itemData={{ ItemRenderer: headersRender, stickyColumnIndices }}
294
303
  style={{
295
- overflow: "visible",
296
- // borderTopRightRadius: theme?.radius?.mini ?? 4,
304
+ overflow: "hidden",
297
305
  backgroundColor:
298
306
  columnHeaderBackgroundColor ||
299
307
  (theme?.colors?.grey4 ?? "rgba(0, 0, 0, 0.08)"),
@@ -309,7 +317,7 @@ const InnerElementType = forwardRef(
309
317
  backgroundColor: theme?.background ?? "#F9F2E8",
310
318
  zIndex: 2,
311
319
  top: headersRender ? columnHeaderHeight || 40 : 0,
312
- left: `calc(100% - ${stickyColumnsWidth + (border ? 1 : 0)}px)`,
320
+ left: width - stickyColumnsWidth - (border ? 1 : 0), // 使用总宽度计算位置
313
321
  width: stickyColumnsWidth,
314
322
  height: "100%",
315
323
  position: "sticky",
@@ -329,7 +337,9 @@ const InnerElementType = forwardRef(
329
337
  rowHeight={rowHeight}
330
338
  width={stickyColumnsWidth}
331
339
  itemData={{ ItemRenderer, stickyColumnIndices, border, hasActions: hasActionsFn }}
332
- style={{ overflow: "visible" }}
340
+ style={{
341
+ overflow: hasActions ? "visible": "hidden"
342
+ }}
333
343
  >
334
344
  {StickyColumnCell}
335
345
  </VariableSizeGrid>
@@ -433,7 +443,8 @@ const StickyList = ({
433
443
  : rest.theme.radius.mini ?? 4,
434
444
  scrollbarWidth: "none",
435
445
  msOverflowStyle: "none",
436
- overflow: "visible", // 允许下拉菜单显示
446
+ // 移除 overflow: "visible",恢复 Grid 的正常滚动功能
447
+ // Modal 下拉菜单不需要这个设置
437
448
  }}
438
449
  itemData={{
439
450
  ItemRenderer: children,
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = exports.TapasDataCell = exports.DataCell = void 0;
6
+ exports.setDropdownStateChangeListener = exports.default = exports.TapasDataCell = exports.DataCell = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _themed = require("@rneui/themed");
@@ -14,6 +14,40 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
14
14
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
15
15
  // import { TapasDropdown } from "../Dropdown/Dropdown";
16
16
 
17
+ // 全局下拉菜单状态管理
18
+ const globalDropdownState = {
19
+ activeColumn: null,
20
+ activeRow: null,
21
+ closeAll: () => {},
22
+ onDropdownStateChange: undefined
23
+ };
24
+
25
+ // 注册和注销下拉菜单的函数
26
+ const registerDropdown = (columnIndex, rowIndex, closeCallback) => {
27
+ globalDropdownState.activeColumn = columnIndex;
28
+ globalDropdownState.activeRow = rowIndex;
29
+ globalDropdownState.closeAll = closeCallback;
30
+ // 通知状态变化
31
+ globalDropdownState.onDropdownStateChange?.(columnIndex, rowIndex);
32
+ };
33
+ const unregisterDropdown = () => {
34
+ globalDropdownState.activeColumn = null;
35
+ globalDropdownState.activeRow = null;
36
+ globalDropdownState.closeAll = () => {};
37
+ // 通知状态变化
38
+ globalDropdownState.onDropdownStateChange?.(null, null);
39
+ };
40
+ const closeAllDropdowns = () => {
41
+ if (globalDropdownState.closeAll) {
42
+ globalDropdownState.closeAll();
43
+ }
44
+ };
45
+
46
+ // 设置下拉菜单状态变化监听器
47
+ const setDropdownStateChangeListener = callback => {
48
+ globalDropdownState.onDropdownStateChange = callback;
49
+ };
50
+ exports.setDropdownStateChangeListener = setDropdownStateChangeListener;
17
51
  const TapasDataCell = ({
18
52
  value,
19
53
  dataType = "text",
@@ -47,6 +81,8 @@ const TapasDataCell = ({
47
81
  disabled = false,
48
82
  minHeight = 40,
49
83
  isBlank = false,
84
+ onDropdownStateChange,
85
+ gridInfo,
50
86
  style,
51
87
  ...otherProps
52
88
  }) => {
@@ -148,6 +184,114 @@ const TapasDataCell = ({
148
184
  right: 0
149
185
  });
150
186
 
187
+ // 计算下拉菜单的最佳位置
188
+ const calculateDropdownPosition = (0, _react.useCallback)(() => {
189
+ // 更准确地计算下拉菜单的实际高度
190
+ const itemHeight = 32; // 每个选项的高度
191
+ const borderWidth = 2; // 边框宽度
192
+ const padding = 8; // 内边距
193
+ const shadowHeight = 4; // 阴影高度
194
+
195
+ // 考虑文本长度对高度的影响
196
+ const maxTextLength = Math.max(...actions.map(action => action.label.length));
197
+ const textHeightAdjustment = maxTextLength > 10 ? 4 : 0; // 长文本可能需要更多高度
198
+
199
+ // 计算下拉菜单的宽度(考虑文本长度)
200
+ // const minWidth = 120; // 最小宽度
201
+ // const textWidth = maxTextLength * 8; // 估算文本宽度
202
+ // const _actualWidth = Math.max(minWidth, textWidth + 24); // 24px 为内边距和图标空间
203
+
204
+ const actualHeight = actions.length * itemHeight + borderWidth + padding + shadowHeight + textHeightAdjustment;
205
+ const buttonHeight = 32; // 按钮高度
206
+ const cellHeight = gridInfo?.rowHeight || 56; // 使用传入的 rowHeight 或默认值
207
+ const gridHeight = gridInfo?.gridHeight || 400; // 使用传入的 gridHeight 或默认值
208
+
209
+ // 根据行索引估算当前单元格在 Grid 中的位置
210
+ const currentRowIndex = rowIndex || 0;
211
+
212
+ // 计算当前单元格距离 Grid 底部的距离
213
+ const currentCellBottom = (currentRowIndex + 1) * cellHeight;
214
+ const spaceBelow = gridHeight - currentCellBottom;
215
+
216
+ // 计算上方可用空间
217
+ const currentCellTop = currentRowIndex * cellHeight;
218
+ const spaceAbove = currentCellTop;
219
+
220
+ // 添加安全边距,确保下拉菜单不会紧贴边界
221
+ const safetyMargin = 8;
222
+ const requiredSpace = actualHeight + safetyMargin;
223
+
224
+ // 智能选择显示位置
225
+ if (requiredSpace > spaceBelow && requiredSpace <= spaceAbove) {
226
+ // 下方空间不够,但上方空间足够,显示在上方
227
+ return {
228
+ top: -actualHeight - 4,
229
+ // 按钮上方,留 4px 间距
230
+ right: 0
231
+ };
232
+ } else if (requiredSpace > spaceBelow && requiredSpace > spaceAbove) {
233
+ // 上下空间都不够,选择空间较大的一侧
234
+ if (spaceAbove > spaceBelow) {
235
+ return {
236
+ top: -actualHeight - 4,
237
+ // 按钮上方
238
+ right: 0
239
+ };
240
+ } else {
241
+ return {
242
+ top: buttonHeight + 4,
243
+ // 按钮下方
244
+ right: 0
245
+ };
246
+ }
247
+ } else {
248
+ // 下方空间足够,显示在下方
249
+ return {
250
+ top: buttonHeight + 4,
251
+ // 按钮下方,留 4px 间距
252
+ right: 0
253
+ };
254
+ }
255
+ }, [actions.length, rowIndex, gridInfo]);
256
+
257
+ // 全局下拉菜单管理
258
+ (0, _react.useEffect)(() => {
259
+ const closeDropdown = () => {
260
+ setDropdownVisible(false);
261
+ unregisterDropdown();
262
+ };
263
+
264
+ // 注册当前下拉菜单
265
+ if (dropdownVisible) {
266
+ registerDropdown(columnIndex || 0, rowIndex || 0, closeDropdown);
267
+ } else {
268
+ unregisterDropdown();
269
+ }
270
+
271
+ // 清理函数
272
+ return () => {
273
+ unregisterDropdown();
274
+ };
275
+ }, [dropdownVisible, columnIndex, rowIndex]);
276
+
277
+ // 通知父组件下拉菜单状态变化
278
+ (0, _react.useEffect)(() => {
279
+ onDropdownStateChange?.(dropdownVisible);
280
+ }, [dropdownVisible, onDropdownStateChange]);
281
+
282
+ // 监听全局关闭事件
283
+ (0, _react.useEffect)(() => {
284
+ // const _handleGlobalClose = () => {
285
+ // if (globalDropdownState.activeColumn !== columnIndex ||
286
+ // globalDropdownState.activeRow !== rowIndex) {
287
+ // setDropdownVisible(false);
288
+ // }
289
+ // };
290
+
291
+ // 这里可以添加全局事件监听器
292
+ // 为了简化,我们在点击其他单元格时关闭当前下拉菜单
293
+ }, [columnIndex, rowIndex]);
294
+
151
295
  // 渲染操作按钮
152
296
  const renderActions = () => {
153
297
  if (!showActions || actions.length === 0 || isBlank) {
@@ -185,22 +329,30 @@ const TapasDataCell = ({
185
329
 
186
330
  // 多个操作显示下拉菜单
187
331
  return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
188
- style: styles.dropdownContainer
332
+ style: [styles.dropdownContainer, {
333
+ // 只有当前激活的下拉菜单容器才有高 z-index
334
+ zIndex: globalDropdownState.activeColumn === columnIndex && globalDropdownState.activeRow === rowIndex ? 2147483646 : 1
335
+ }]
189
336
  }, /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
190
337
  style: styles.actionButton,
191
338
  onPress: event => {
192
339
  // 阻止事件冒泡,避免触发外层的 attachCellPress
193
340
  event.stopPropagation();
194
- if (!dropdownVisible) {
195
- // 在 React Native 中,我们使用相对定位
196
- // 由于 Grid 的 overflow: hidden 限制,我们使用更高的 z-index 和绝对定位
197
- setDropdownPosition({
198
- top: 32,
199
- // 按钮下方 32px
200
- right: 0 // 从右边缘对齐
201
- });
341
+ if (dropdownVisible) {
342
+ // 如果当前下拉菜单已经打开,直接关闭
343
+ setDropdownVisible(false);
344
+ } else {
345
+ // 如果当前下拉菜单关闭,先关闭其他所有下拉菜单,然后打开当前菜单
346
+ closeAllDropdowns();
347
+
348
+ // 计算并设置下拉菜单位置
349
+ setDropdownPosition(calculateDropdownPosition());
350
+
351
+ // 延迟打开当前下拉菜单,确保其他菜单已关闭
352
+ setTimeout(() => {
353
+ setDropdownVisible(true);
354
+ }, 0);
202
355
  }
203
- setDropdownVisible(!dropdownVisible);
204
356
  },
205
357
  disabled: disabled
206
358
  }, /*#__PURE__*/_react.default.createElement(_TapasIcon.default, {
@@ -321,7 +473,10 @@ const useStyles = (0, _themed.makeStyles)((theme, props) => {
321
473
  },
322
474
  dropdownContainer: {
323
475
  position: "relative",
324
- zIndex: 1000
476
+ // 默认使用较低的 z-index,只有激活的下拉菜单容器才有高 z-index
477
+ zIndex: 1,
478
+ // 确保容器本身不会创建新的 stacking context
479
+ isolation: "auto"
325
480
  },
326
481
  dropdownMenu: {
327
482
  position: "absolute",
@@ -339,9 +494,12 @@ const useStyles = (0, _themed.makeStyles)((theme, props) => {
339
494
  shadowRadius: 3.84,
340
495
  elevation: 5,
341
496
  minWidth: 120,
342
- zIndex: 9999,
497
+ zIndex: 2147483647,
498
+ // 更高的 z-index,确保显示在所有元素之上
343
499
  // 确保下拉菜单不被父容器的 overflow 隐藏
344
- overflow: "visible"
500
+ overflow: "visible",
501
+ // 确保下拉菜单在正确的层级上
502
+ isolation: "isolate"
345
503
  },
346
504
  dropdownItem: {
347
505
  paddingHorizontal: 12,