@beppla/tapas-ui 1.0.55 → 1.0.57

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 (49) hide show
  1. package/components/DataCell/DataCell.tsx +129 -16
  2. package/components/Dropdown/Dropdown.tsx +24 -2
  3. package/components/Dropdown/InputDropdown.tsx +7 -0
  4. package/components/Grid/StaticFixedSizeGrid.tsx +21 -10
  5. package/components/ListItem/ListItem.tsx +16 -0
  6. package/package/CHANGELOG.md +383 -0
  7. package/package/README.md +103 -0
  8. package/package/assets/assets/adaptive-icon.png +0 -0
  9. package/package/assets/assets/favicon.png +0 -0
  10. package/package/assets/assets/fonts/customfont.ttf +0 -0
  11. package/package/assets/assets/icon.png +0 -0
  12. package/package/assets/assets/logo.png +0 -0
  13. package/package/assets/assets/splash.png +0 -0
  14. package/package/assets/assets/svg/customfont.svg +332 -0
  15. package/package/assets/assets/svg/logo.svg +9 -0
  16. package/package/assets/assets/tapas/favicon.png +0 -0
  17. package/package/assets/assets/tapas/logo.png +0 -0
  18. package/package/assets/assets/tapas/logo_no_word.png +0 -0
  19. package/package/assets/assets/tapas/logo_transparent_white.png +0 -0
  20. package/package/commonjs/DataCell/DataCell.js +122 -17
  21. package/package/commonjs/DataCell/DataCell.js.map +1 -1
  22. package/package/commonjs/Dropdown/Dropdown.js +32 -6
  23. package/package/commonjs/Dropdown/Dropdown.js.map +1 -1
  24. package/package/commonjs/Dropdown/InputDropdown.js +7 -1
  25. package/package/commonjs/Dropdown/InputDropdown.js.map +1 -1
  26. package/package/commonjs/Grid/StaticFixedSizeGrid.js +23 -11
  27. package/package/commonjs/Grid/StaticFixedSizeGrid.js.map +1 -1
  28. package/package/commonjs/ListItem/ListItem.js +13 -1
  29. package/package/commonjs/ListItem/ListItem.js.map +1 -1
  30. package/package/init.js +179 -0
  31. package/package/module/DataCell/DataCell.js +121 -17
  32. package/package/module/DataCell/DataCell.js.map +1 -1
  33. package/package/module/Dropdown/Dropdown.js +32 -6
  34. package/package/module/Dropdown/Dropdown.js.map +1 -1
  35. package/package/module/Dropdown/InputDropdown.js +7 -1
  36. package/package/module/Dropdown/InputDropdown.js.map +1 -1
  37. package/package/module/Grid/StaticFixedSizeGrid.js +23 -11
  38. package/package/module/Grid/StaticFixedSizeGrid.js.map +1 -1
  39. package/package/module/ListItem/ListItem.js +13 -1
  40. package/package/module/ListItem/ListItem.js.map +1 -1
  41. package/package/package.json +84 -0
  42. package/package/typescript/DataCell/DataCell.d.ts +10 -1
  43. package/package/typescript/DataCell/DataCell.d.ts.map +1 -1
  44. package/package/typescript/Dropdown/Dropdown.d.ts.map +1 -1
  45. package/package/typescript/Dropdown/InputDropdown.d.ts.map +1 -1
  46. package/package/typescript/Grid/StaticFixedSizeGrid.d.ts.map +1 -1
  47. package/package/typescript/ListItem/ListItem.d.ts +4 -0
  48. package/package/typescript/ListItem/ListItem.d.ts.map +1 -1
  49. package/package.json +1 -1
@@ -9,10 +9,12 @@ const globalDropdownState: {
9
9
  activeColumn: number | null;
10
10
  activeRow: number | null;
11
11
  closeAll: () => void;
12
+ onDropdownStateChange?: (columnIndex: number | null, rowIndex: number | null) => void;
12
13
  } = {
13
14
  activeColumn: null,
14
15
  activeRow: null,
15
16
  closeAll: () => {},
17
+ onDropdownStateChange: undefined,
16
18
  };
17
19
 
18
20
  // 注册和注销下拉菜单的函数
@@ -20,12 +22,16 @@ const registerDropdown = (columnIndex: number, rowIndex: number, closeCallback:
20
22
  globalDropdownState.activeColumn = columnIndex;
21
23
  globalDropdownState.activeRow = rowIndex;
22
24
  globalDropdownState.closeAll = closeCallback;
25
+ // 通知状态变化
26
+ globalDropdownState.onDropdownStateChange?.(columnIndex, rowIndex);
23
27
  };
24
28
 
25
29
  const unregisterDropdown = () => {
26
30
  globalDropdownState.activeColumn = null;
27
31
  globalDropdownState.activeRow = null;
28
32
  globalDropdownState.closeAll = () => {};
33
+ // 通知状态变化
34
+ globalDropdownState.onDropdownStateChange?.(null, null);
29
35
  };
30
36
 
31
37
  const closeAllDropdowns = () => {
@@ -34,6 +40,11 @@ const closeAllDropdowns = () => {
34
40
  }
35
41
  };
36
42
 
43
+ // 设置下拉菜单状态变化监听器
44
+ const setDropdownStateChangeListener = (callback: (columnIndex: number | null, rowIndex: number | null) => void) => {
45
+ globalDropdownState.onDropdownStateChange = callback;
46
+ };
47
+
37
48
  export type DataType =
38
49
  | "text"
39
50
  | "number"
@@ -120,6 +131,14 @@ export interface TapasDataCellProps extends ViewProps {
120
131
  minHeight?: number;
121
132
  /** 是否为空白单元格 */
122
133
  isBlank?: boolean;
134
+ /** 下拉菜单状态变化回调 */
135
+ onDropdownStateChange?: (isOpen: boolean) => void;
136
+ /** Grid 相关信息,用于计算下拉菜单位置 */
137
+ gridInfo?: {
138
+ totalRows?: number;
139
+ rowHeight?: number;
140
+ gridHeight?: number;
141
+ };
123
142
  }
124
143
 
125
144
  const TapasDataCell: React.FC<TapasDataCellProps> = ({
@@ -152,6 +171,8 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
152
171
  disabled = false,
153
172
  minHeight = 40,
154
173
  isBlank = false,
174
+ onDropdownStateChange,
175
+ gridInfo,
155
176
  style,
156
177
  ...otherProps
157
178
  }) => {
@@ -254,6 +275,73 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
254
275
  // 下拉菜单状态
255
276
  const [dropdownVisible, setDropdownVisible] = useState(false);
256
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]);
257
345
 
258
346
  // 全局下拉菜单管理
259
347
  useEffect(() => {
@@ -275,8 +363,20 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
275
363
  };
276
364
  }, [dropdownVisible, columnIndex, rowIndex]);
277
365
 
366
+ // 通知父组件下拉菜单状态变化
367
+ useEffect(() => {
368
+ onDropdownStateChange?.(dropdownVisible);
369
+ }, [dropdownVisible, onDropdownStateChange]);
370
+
278
371
  // 监听全局关闭事件
279
372
  useEffect(() => {
373
+ // const _handleGlobalClose = () => {
374
+ // if (globalDropdownState.activeColumn !== columnIndex ||
375
+ // globalDropdownState.activeRow !== rowIndex) {
376
+ // setDropdownVisible(false);
377
+ // }
378
+ // };
379
+
280
380
  // 这里可以添加全局事件监听器
281
381
  // 为了简化,我们在点击其他单元格时关闭当前下拉菜单
282
382
  }, [columnIndex, rowIndex]);
@@ -323,26 +423,34 @@ const TapasDataCell: React.FC<TapasDataCellProps> = ({
323
423
 
324
424
  // 多个操作显示下拉菜单
325
425
  return (
326
- <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
+ ]}>
327
433
  <Pressable
328
434
  style={styles.actionButton}
329
435
  onPress={(event) => {
330
436
  // 阻止事件冒泡,避免触发外层的 attachCellPress
331
437
  event.stopPropagation();
332
438
 
333
- // 关闭其他所有下拉菜单
334
- closeAllDropdowns();
335
-
336
- if (!dropdownVisible) {
337
- // 在 React Native 中,我们使用相对定位
338
- // 由于 Grid 的 overflow: hidden 限制,我们使用更高的 z-index 和绝对定位
339
- setDropdownPosition({
340
- top: 32, // 按钮下方 32px
341
- right: 0, // 从右边缘对齐
342
- });
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);
343
453
  }
344
-
345
- setDropdownVisible(!dropdownVisible);
346
454
  }}
347
455
  disabled={disabled}
348
456
  >
@@ -509,7 +617,10 @@ const useStyles = makeStyles((theme, props?: {
509
617
  },
510
618
  dropdownContainer: {
511
619
  position: "relative",
512
- zIndex: 99999, // 更高的 z-index,确保容器也在最上层
620
+ // 默认使用较低的 z-index,只有激活的下拉菜单容器才有高 z-index
621
+ zIndex: 1,
622
+ // 确保容器本身不会创建新的 stacking context
623
+ isolation: "auto",
513
624
  },
514
625
  dropdownMenu: {
515
626
  position: "absolute", // 使用绝对定位
@@ -526,9 +637,11 @@ const useStyles = makeStyles((theme, props?: {
526
637
  shadowRadius: 3.84,
527
638
  elevation: 5,
528
639
  minWidth: 120,
529
- zIndex: 99999, // 更高的 z-index,确保显示在所有元素之上
640
+ zIndex: 2147483647, // 更高的 z-index,确保显示在所有元素之上
530
641
  // 确保下拉菜单不被父容器的 overflow 隐藏
531
642
  overflow: "visible",
643
+ // 确保下拉菜单在正确的层级上
644
+ isolation: "isolate",
532
645
  },
533
646
  dropdownItem: {
534
647
  paddingHorizontal: 12,
@@ -554,4 +667,4 @@ export default withTheme(TapasDataCell);
554
667
 
555
668
  // Export aliases for compatibility
556
669
  export const DataCell = withTheme(TapasDataCell);
557
- export { TapasDataCell };
670
+ export { TapasDataCell, setDropdownStateChangeListener };
@@ -136,8 +136,8 @@ const useStyles = makeStyles((theme) => ({
136
136
  // Modal 模式样式
137
137
  modalContainer: {
138
138
  flex: 1,
139
- justifyContent: "center",
140
- alignItems: "center",
139
+ justifyContent: "flex-start", // 改为顶部对齐,与 CustomDropdown 保持一致
140
+ alignItems: "stretch", // 改为拉伸对齐,与 CustomDropdown 保持一致
141
141
  },
142
142
  modalIcon: {
143
143
  color: theme.colors.primary,
@@ -198,6 +198,7 @@ const useStyles = makeStyles((theme) => ({
198
198
  display: "flex",
199
199
  flexDirection: "row",
200
200
  justifyContent: "space-between",
201
+ alignItems: "center", // 确保垂直居中对齐
201
202
  minHeight: 40,
202
203
  width: "100%",
203
204
  overflow: "hidden",
@@ -212,6 +213,7 @@ const useStyles = makeStyles((theme) => ({
212
213
  paddingRight: 12,
213
214
  paddingTop: 9,
214
215
  paddingBottom: 9,
216
+ alignItems: "center", // 确保垂直居中对齐
215
217
  },
216
218
  alignCenter: {
217
219
  alignSelf: "center",
@@ -471,10 +473,13 @@ const Dropdown: React.FC<DropdownProps> = ({
471
473
  (showSelectedValue || (noLabelAnim && label)) ? styles.modalBtn : null,
472
474
  dropdownType === "solid" ? styles.modalSolidBtn : null,
473
475
  dropdownType === "solid" && radius ? { borderRadius: radius } : null,
476
+ // 统一主体容器的位置,无论是否使用 customPopoverContent
474
477
  label && !noLabelAnim ? { marginTop: 7 } : null,
475
478
  noLabelAnim && label && backgroundColor ? { backgroundColor } : null,
476
479
  state === "error" ? { borderColor: theme.theme.colors.error } : null,
477
480
  props.disabled ? { borderColor: theme.theme.colors.grey3 } : null,
481
+ // 确保主体容器始终有统一的垂直对齐
482
+ { alignItems: "center" },
478
483
  ]}
479
484
  disabled={props.disabled}
480
485
  onPress={openDropdown}
@@ -581,6 +586,16 @@ const Dropdown: React.FC<DropdownProps> = ({
581
586
  ? theme.theme.colors.grey4 || "#f0f0f0"
582
587
  : "transparent",
583
588
  },
589
+ // 第一个 item 添加左上和右上圆角
590
+ index === 0 && {
591
+ borderTopLeftRadius: 12,
592
+ borderTopRightRadius: 12,
593
+ },
594
+ // 最后一个 item 添加左下和右下圆角
595
+ index === dropdownItems.length - 1 && {
596
+ borderBottomLeftRadius: 12,
597
+ borderBottomRightRadius: 12,
598
+ },
584
599
  showCheckedStatusInList && selectedItemKey === item.key ? {
585
600
  backgroundColor: theme.theme.colors.grey4 || "#f0f0f0",
586
601
  } : null,
@@ -758,6 +773,11 @@ const Dropdown: React.FC<DropdownProps> = ({
758
773
  </Pressable>
759
774
  <ScrollView style={{width: subWidth, height: subHeight}}>
760
775
  {options?.map((item, index) => {
776
+ const visibleItems = options.filter(item => !item.hide);
777
+ const currentVisibleIndex = visibleItems.findIndex(visibleItem => visibleItem === item);
778
+ const isFirst = currentVisibleIndex === 0;
779
+ const isLast = currentVisibleIndex === visibleItems.length - 1;
780
+
761
781
  return (
762
782
  !item.hide && (
763
783
  <CustomListItem
@@ -773,6 +793,8 @@ const Dropdown: React.FC<DropdownProps> = ({
773
793
  key={index}
774
794
  item={item}
775
795
  selected={selected_old}
796
+ isFirst={isFirst}
797
+ isLast={isLast}
776
798
  />
777
799
  )
778
800
  );
@@ -152,6 +152,11 @@ const InputDropdown: React.FC<InputDropdownProps> = ({
152
152
  {Array.isArray(list) ? (
153
153
  <ScrollView style={{width: subWidth, maxHeight: subHeight}}>
154
154
  {list?.map((item, index) => {
155
+ const visibleItems = list.filter(item => !item.hide);
156
+ const currentVisibleIndex = visibleItems.findIndex(visibleItem => visibleItem === item);
157
+ const isFirst = currentVisibleIndex === 0;
158
+ const isLast = currentVisibleIndex === visibleItems.length - 1;
159
+
155
160
  return (
156
161
  !item.hide && (
157
162
  <CustomListItem
@@ -164,6 +169,8 @@ const InputDropdown: React.FC<InputDropdownProps> = ({
164
169
  key={index}
165
170
  item={item}
166
171
  selected={selected}
172
+ isFirst={isFirst}
173
+ isLast={isLast}
167
174
  />
168
175
  )
169
176
  );
@@ -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,
@@ -32,6 +32,10 @@ export interface Props extends ListItemProps {
32
32
  searchHighlightStyle?: StyleProp<TextStyle>;
33
33
  titleStyle?: StyleProp<TextStyle>;
34
34
  descStyle?: StyleProp<TextStyle>;
35
+ /** 是否为第一个 item */
36
+ isFirst?: boolean;
37
+ /** 是否为最后一个 item */
38
+ isLast?: boolean;
35
39
  search?: string;
36
40
  testID?: string;
37
41
  }
@@ -140,6 +144,8 @@ const CustomListItem: React.FC<Props> = ({
140
144
  searchHighlightStyle,
141
145
  titleStyle,
142
146
  descStyle,
147
+ isFirst,
148
+ isLast,
143
149
  testID,
144
150
  ...props
145
151
  }) => {
@@ -184,6 +190,16 @@ const CustomListItem: React.FC<Props> = ({
184
190
  selected?.value === item?.value
185
191
  ? styles.selectedItem
186
192
  : isHovered && styles.hovered,
193
+ // 第一个 item 添加左上和右上圆角
194
+ isFirst && {
195
+ borderTopLeftRadius: 12,
196
+ borderTopRightRadius: 12,
197
+ },
198
+ // 最后一个 item 添加左下和右下圆角
199
+ isLast && {
200
+ borderBottomLeftRadius: 12,
201
+ borderBottomRightRadius: 12,
202
+ },
187
203
  ]}
188
204
  >
189
205
  <Hoverable