@tarojs/components-advanced 4.1.12-beta.2 → 4.1.12-beta.21

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 (76) hide show
  1. package/dist/components/index.js +2 -0
  2. package/dist/components/index.js.map +1 -1
  3. package/dist/components/list/NoMore.d.ts +30 -0
  4. package/dist/components/list/NoMore.js +10 -0
  5. package/dist/components/list/NoMore.js.map +1 -0
  6. package/dist/components/list/hooks/useItemSizeCache.d.ts +13 -0
  7. package/dist/components/list/hooks/useItemSizeCache.js +40 -0
  8. package/dist/components/list/hooks/useItemSizeCache.js.map +1 -0
  9. package/dist/components/list/hooks/useListNestedScroll.d.ts +18 -0
  10. package/dist/components/list/hooks/useListNestedScroll.js +61 -0
  11. package/dist/components/list/hooks/useListNestedScroll.js.map +1 -0
  12. package/dist/components/list/hooks/useListScrollElementAttach.d.ts +25 -0
  13. package/dist/components/list/hooks/useListScrollElementAttach.js +88 -0
  14. package/dist/components/list/hooks/useListScrollElementAttach.js.map +1 -0
  15. package/dist/components/list/hooks/useListScrollElementAttachWeapp.d.ts +27 -0
  16. package/dist/components/list/hooks/useListScrollElementAttachWeapp.js +153 -0
  17. package/dist/components/list/hooks/useListScrollElementAttachWeapp.js.map +1 -0
  18. package/dist/components/list/hooks/useMeasureStartOffset.d.ts +12 -0
  19. package/dist/components/list/hooks/useMeasureStartOffset.js +84 -0
  20. package/dist/components/list/hooks/useMeasureStartOffset.js.map +1 -0
  21. package/dist/components/list/hooks/useMeasureStartOffsetWeapp.d.ts +13 -0
  22. package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js +85 -0
  23. package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js.map +1 -0
  24. package/dist/components/list/hooks/useRefresher.d.ts +74 -0
  25. package/dist/components/list/hooks/useRefresher.js +503 -0
  26. package/dist/components/list/hooks/useRefresher.js.map +1 -0
  27. package/dist/components/list/hooks/useResizeObserver.d.ts +26 -0
  28. package/dist/components/list/hooks/useResizeObserver.js +152 -0
  29. package/dist/components/list/hooks/useResizeObserver.js.map +1 -0
  30. package/dist/components/list/hooks/useScrollCorrection.d.ts +19 -0
  31. package/dist/components/list/hooks/useScrollCorrection.js +73 -0
  32. package/dist/components/list/hooks/useScrollCorrection.js.map +1 -0
  33. package/dist/components/list/hooks/useScrollParentAutoFind.d.ts +20 -0
  34. package/dist/components/list/hooks/useScrollParentAutoFind.js +81 -0
  35. package/dist/components/list/hooks/useScrollParentAutoFind.js.map +1 -0
  36. package/dist/components/list/index.d.ts +64 -7
  37. package/dist/components/list/index.js +1041 -162
  38. package/dist/components/list/index.js.map +1 -1
  39. package/dist/components/list/utils.d.ts +16 -0
  40. package/dist/components/list/utils.js +19 -0
  41. package/dist/components/list/utils.js.map +1 -0
  42. package/dist/components/virtual-list/vue/list.d.ts +12 -12
  43. package/dist/components/virtual-waterfall/vue/waterfall.d.ts +11 -11
  44. package/dist/components/water-flow/flow-item.js +6 -4
  45. package/dist/components/water-flow/flow-item.js.map +1 -1
  46. package/dist/components/water-flow/flow-section.js +1 -1
  47. package/dist/components/water-flow/flow-section.js.map +1 -1
  48. package/dist/components/water-flow/index.d.ts +1 -1
  49. package/dist/components/water-flow/interface.d.ts +18 -2
  50. package/dist/components/water-flow/root.d.ts +35 -4
  51. package/dist/components/water-flow/root.js +114 -42
  52. package/dist/components/water-flow/root.js.map +1 -1
  53. package/dist/components/water-flow/section.d.ts +7 -1
  54. package/dist/components/water-flow/section.js +54 -9
  55. package/dist/components/water-flow/section.js.map +1 -1
  56. package/dist/components/water-flow/utils.d.ts +4 -0
  57. package/dist/components/water-flow/utils.js +5 -1
  58. package/dist/components/water-flow/utils.js.map +1 -1
  59. package/dist/components/water-flow/water-flow-node-cache.d.ts +24 -0
  60. package/dist/components/water-flow/water-flow-node-cache.js +161 -0
  61. package/dist/components/water-flow/water-flow-node-cache.js.map +1 -0
  62. package/dist/components/water-flow/water-flow.d.ts +2 -3
  63. package/dist/components/water-flow/water-flow.js +286 -31
  64. package/dist/components/water-flow/water-flow.js.map +1 -1
  65. package/dist/index.js +3 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/utils/index.d.ts +1 -0
  68. package/dist/utils/index.js +1 -0
  69. package/dist/utils/index.js.map +1 -1
  70. package/dist/utils/scrollElementContext.d.ts +15 -0
  71. package/dist/utils/scrollElementContext.js +14 -0
  72. package/dist/utils/scrollElementContext.js.map +1 -0
  73. package/dist/utils/scrollParent.d.ts +33 -0
  74. package/dist/utils/scrollParent.js +88 -0
  75. package/dist/utils/scrollParent.js.map +1 -0
  76. package/package.json +9 -8
@@ -0,0 +1,84 @@
1
+ import { useState, useRef, useEffect } from 'react';
2
+
3
+ const WARNED_NESTED = new WeakSet();
4
+ const MAX_RETRY = 20;
5
+ const RETRY_DELAY = 50;
6
+ /**
7
+ * 测量 scrollElement 内 content 节点之前所有兄弟的高度/宽度之和,作为 startOffset。
8
+ * 用于 scrollElement 模式下无 Context/props 时自动计算上方内容高度。
9
+ * - 直接子节点:累加前兄弟尺寸(更稳定)
10
+ * - 非直接子节点:getBoundingClientRect 回退,并 warning 建议传 startOffset
11
+ * - ref 未就绪时自动重试,确保绑定到最外层滚动容器后能正确测量
12
+ */
13
+ function useMeasureStartOffset(scrollElRef, contentRef, options) {
14
+ const { enabled, isHorizontal = false } = options;
15
+ const [measuredStartOffset, setMeasuredStartOffset] = useState(0);
16
+ const [retryTrigger, setRetryTrigger] = useState(0);
17
+ const retryCountRef = useRef(0);
18
+ useEffect(() => {
19
+ if (!enabled) {
20
+ retryCountRef.current = 0;
21
+ return;
22
+ }
23
+ const scrollEl = scrollElRef.current;
24
+ const contentEl = contentRef.current;
25
+ // ref 未就绪时重试(如 ScrollView 与 WaterFlow 异步挂载)
26
+ if (!scrollEl || !contentEl) {
27
+ if (retryCountRef.current < MAX_RETRY) {
28
+ retryCountRef.current += 1;
29
+ const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY);
30
+ return () => clearTimeout(id);
31
+ }
32
+ return;
33
+ }
34
+ retryCountRef.current = 0;
35
+ const measure = () => {
36
+ const el = contentRef.current;
37
+ const scroll = scrollElRef.current;
38
+ if (!el || !scroll)
39
+ return;
40
+ if (el.parentElement === scroll) {
41
+ // 直接子节点:累加前兄弟尺寸
42
+ let offset = 0;
43
+ let prev = el.previousElementSibling;
44
+ while (prev) {
45
+ offset += isHorizontal ? prev.offsetWidth : prev.offsetHeight;
46
+ prev = prev.previousElementSibling;
47
+ }
48
+ setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - offset) < 1 ? prevVal : offset));
49
+ return;
50
+ }
51
+ // 非直接子节点:getBoundingClientRect 回退
52
+ const scrollRect = scroll.getBoundingClientRect();
53
+ const contentRect = el.getBoundingClientRect();
54
+ const offset = isHorizontal
55
+ ? contentRect.left - scrollRect.left + scroll.scrollLeft
56
+ : contentRect.top - scrollRect.top + scroll.scrollTop;
57
+ const value = Math.max(0, offset);
58
+ setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value));
59
+ if (!WARNED_NESTED.has(el)) {
60
+ WARNED_NESTED.add(el);
61
+ // eslint-disable-next-line no-console
62
+ console.warn('[useMeasureStartOffset] content 不是 scrollElement 的直接子节点,使用 getBoundingClientRect 测量。' +
63
+ '建议通过 props 或 Context 传入 startOffset 以获得更稳定的布局。');
64
+ }
65
+ };
66
+ measure();
67
+ scrollEl.addEventListener('scroll', measure, { passive: true });
68
+ const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null;
69
+ if (ro) {
70
+ ro.observe(scrollEl);
71
+ Array.from(scrollEl.children).forEach((child) => ro.observe(child));
72
+ // 非直接子节点:content 自身或其祖先变化时也需重测
73
+ ro.observe(contentEl);
74
+ }
75
+ return () => {
76
+ scrollEl.removeEventListener('scroll', measure);
77
+ ro === null || ro === void 0 ? void 0 : ro.disconnect();
78
+ };
79
+ }, [enabled, scrollElRef, contentRef, isHorizontal, retryTrigger]);
80
+ return measuredStartOffset;
81
+ }
82
+
83
+ export { useMeasureStartOffset };
84
+ //# sourceMappingURL=useMeasureStartOffset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMeasureStartOffset.js","sources":["../../../../src/components/list/hooks/useMeasureStartOffset.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport type { RefObject } from 'react'\n\nconst WARNED_NESTED = new WeakSet<Element>()\nconst MAX_RETRY = 20\nconst RETRY_DELAY = 50\n\n/**\n * 测量 scrollElement 内 content 节点之前所有兄弟的高度/宽度之和,作为 startOffset。\n * 用于 scrollElement 模式下无 Context/props 时自动计算上方内容高度。\n * - 直接子节点:累加前兄弟尺寸(更稳定)\n * - 非直接子节点:getBoundingClientRect 回退,并 warning 建议传 startOffset\n * - ref 未就绪时自动重试,确保绑定到最外层滚动容器后能正确测量\n */\nexport function useMeasureStartOffset(\n scrollElRef: RefObject<HTMLElement | null>,\n contentRef: RefObject<HTMLElement | null>,\n options: { enabled: boolean, isHorizontal?: boolean }\n): number {\n const { enabled, isHorizontal = false } = options\n const [measuredStartOffset, setMeasuredStartOffset] = useState(0)\n const [retryTrigger, setRetryTrigger] = useState(0)\n const retryCountRef = useRef(0)\n\n useEffect(() => {\n if (!enabled) {\n retryCountRef.current = 0\n return\n }\n const scrollEl = scrollElRef.current\n const contentEl = contentRef.current\n\n // ref 未就绪时重试(如 ScrollView 与 WaterFlow 异步挂载)\n if (!scrollEl || !contentEl) {\n if (retryCountRef.current < MAX_RETRY) {\n retryCountRef.current += 1\n const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY)\n return () => clearTimeout(id)\n }\n return\n }\n retryCountRef.current = 0\n\n const measure = () => {\n const el = contentRef.current\n const scroll = scrollElRef.current\n if (!el || !scroll) return\n\n if (el.parentElement === scroll) {\n // 直接子节点:累加前兄弟尺寸\n let offset = 0\n let prev: Element | null = el.previousElementSibling\n while (prev) {\n offset += isHorizontal ? (prev as HTMLElement).offsetWidth : (prev as HTMLElement).offsetHeight\n prev = prev.previousElementSibling\n }\n setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - offset) < 1 ? prevVal : offset))\n return\n }\n\n // 非直接子节点:getBoundingClientRect 回退\n const scrollRect = scroll.getBoundingClientRect()\n const contentRect = el.getBoundingClientRect()\n const offset = isHorizontal\n ? contentRect.left - scrollRect.left + scroll.scrollLeft\n : contentRect.top - scrollRect.top + scroll.scrollTop\n const value = Math.max(0, offset)\n setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value))\n\n if (!WARNED_NESTED.has(el)) {\n WARNED_NESTED.add(el)\n // eslint-disable-next-line no-console\n console.warn(\n '[useMeasureStartOffset] content 不是 scrollElement 的直接子节点,使用 getBoundingClientRect 测量。' +\n '建议通过 props 或 Context 传入 startOffset 以获得更稳定的布局。'\n )\n }\n }\n\n measure()\n scrollEl.addEventListener('scroll', measure, { passive: true })\n const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null\n if (ro) {\n ro.observe(scrollEl)\n Array.from(scrollEl.children).forEach((child) => ro.observe(child))\n // 非直接子节点:content 自身或其祖先变化时也需重测\n ro.observe(contentEl)\n }\n return () => {\n scrollEl.removeEventListener('scroll', measure)\n ro?.disconnect()\n }\n }, [enabled, scrollElRef, contentRef, isHorizontal, retryTrigger])\n\n return measuredStartOffset\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { MutableRefObject, RefObject } from 'react';
2
+ /**
3
+ * 小程序版 startOffset 测量:通过 createSelectorQuery 获取 scroll-view 与 content 的位置,
4
+ * 计算 content 相对于 scroll 内容顶部的偏移。
5
+ *
6
+ * 公式:startOffset = contentRect.top - scrollRect.top + scrollTop
7
+ * (content 在屏幕上的 top - scroll 可视区 top + 已滚动距离)
8
+ */
9
+ export declare function useMeasureStartOffsetWeapp(scrollElRef: RefObject<HTMLElement | null>, contentId: string, options: {
10
+ enabled: boolean;
11
+ isHorizontal?: boolean;
12
+ startOffsetRef?: MutableRefObject<number>;
13
+ }): number;
@@ -0,0 +1,85 @@
1
+ import Taro from '@tarojs/taro';
2
+ import { useState, useRef, useEffect } from 'react';
3
+
4
+ const MAX_RETRY = 20;
5
+ const RETRY_DELAY = 50;
6
+ /** 与 useListScrollElementAttachWeapp 容器测量间隔一致(H5 无 interval,用 ResizeObserver+scroll 事件驱动) */
7
+ const MEASURE_INTERVAL = 150;
8
+ /**
9
+ * 小程序版 startOffset 测量:通过 createSelectorQuery 获取 scroll-view 与 content 的位置,
10
+ * 计算 content 相对于 scroll 内容顶部的偏移。
11
+ *
12
+ * 公式:startOffset = contentRect.top - scrollRect.top + scrollTop
13
+ * (content 在屏幕上的 top - scroll 可视区 top + 已滚动距离)
14
+ */
15
+ function useMeasureStartOffsetWeapp(scrollElRef, contentId, options) {
16
+ const { enabled, isHorizontal = false, startOffsetRef } = options;
17
+ const [measuredStartOffset, setMeasuredStartOffset] = useState(0);
18
+ const [retryTrigger, setRetryTrigger] = useState(0);
19
+ const retryCountRef = useRef(0);
20
+ const autoIdRef = useRef(`_ls_so_${Math.random().toString(36).slice(2, 9)}`);
21
+ useEffect(() => {
22
+ if (!enabled || !contentId) {
23
+ retryCountRef.current = 0;
24
+ return;
25
+ }
26
+ const measure = () => {
27
+ const scrollEl = scrollElRef.current;
28
+ if (!scrollEl)
29
+ return;
30
+ if (!scrollEl.id) {
31
+ scrollEl.id = autoIdRef.current;
32
+ }
33
+ const scrollViewId = scrollEl.id;
34
+ const instance = Taro.getCurrentInstance();
35
+ const query = (instance === null || instance === void 0 ? void 0 : instance.page)
36
+ ? Taro.createSelectorQuery().in(instance.page)
37
+ : Taro.createSelectorQuery();
38
+ query
39
+ .select(`#${scrollViewId}`)
40
+ .boundingClientRect()
41
+ .select(`#${scrollViewId}`)
42
+ .scrollOffset()
43
+ .select(`#${contentId}`)
44
+ .boundingClientRect()
45
+ .exec((res) => {
46
+ var _a, _b;
47
+ const scrollRect = res === null || res === void 0 ? void 0 : res[0];
48
+ const scrollInfo = res === null || res === void 0 ? void 0 : res[1];
49
+ const contentRect = res === null || res === void 0 ? void 0 : res[2];
50
+ if (!scrollRect || !scrollInfo || !contentRect)
51
+ return;
52
+ const scrollTop = (_a = scrollInfo.scrollTop) !== null && _a !== void 0 ? _a : 0;
53
+ const scrollLeft = (_b = scrollInfo.scrollLeft) !== null && _b !== void 0 ? _b : 0;
54
+ const value = isHorizontal
55
+ ? Math.max(0, contentRect.left - scrollRect.left + scrollLeft)
56
+ : Math.max(0, contentRect.top - scrollRect.top + scrollTop);
57
+ startOffsetRef && (startOffsetRef.current = value);
58
+ setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value));
59
+ });
60
+ };
61
+ const scrollEl = scrollElRef.current;
62
+ if (!scrollEl) {
63
+ if (retryCountRef.current < MAX_RETRY) {
64
+ retryCountRef.current += 1;
65
+ const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY);
66
+ return () => clearTimeout(id);
67
+ }
68
+ return;
69
+ }
70
+ retryCountRef.current = 0;
71
+ measure();
72
+ // 对标 H5:scroll 时触发测量(H5 用 scrollEl.addEventListener('scroll', measure))
73
+ scrollEl.addEventListener('scroll', measure);
74
+ // 无 ResizeObserver,用 interval 兜底布局变化
75
+ const interval = setInterval(measure, MEASURE_INTERVAL);
76
+ return () => {
77
+ scrollEl.removeEventListener('scroll', measure);
78
+ clearInterval(interval);
79
+ };
80
+ }, [enabled, scrollElRef, contentId, isHorizontal, retryTrigger]);
81
+ return measuredStartOffset;
82
+ }
83
+
84
+ export { useMeasureStartOffsetWeapp };
85
+ //# sourceMappingURL=useMeasureStartOffsetWeapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMeasureStartOffsetWeapp.js","sources":["../../../../src/components/list/hooks/useMeasureStartOffsetWeapp.ts"],"sourcesContent":["import Taro from '@tarojs/taro'\nimport { useEffect, useRef, useState } from 'react'\n\nimport type { MutableRefObject, RefObject } from 'react'\n\nconst MAX_RETRY = 20\nconst RETRY_DELAY = 50\n/** 与 useListScrollElementAttachWeapp 容器测量间隔一致(H5 无 interval,用 ResizeObserver+scroll 事件驱动) */\nconst MEASURE_INTERVAL = 150\n\n/**\n * 小程序版 startOffset 测量:通过 createSelectorQuery 获取 scroll-view 与 content 的位置,\n * 计算 content 相对于 scroll 内容顶部的偏移。\n *\n * 公式:startOffset = contentRect.top - scrollRect.top + scrollTop\n * (content 在屏幕上的 top - scroll 可视区 top + 已滚动距离)\n */\nexport function useMeasureStartOffsetWeapp(\n scrollElRef: RefObject<HTMLElement | null>,\n contentId: string,\n options: { enabled: boolean, isHorizontal?: boolean, startOffsetRef?: MutableRefObject<number> }\n): number {\n const { enabled, isHorizontal = false, startOffsetRef } = options\n const [measuredStartOffset, setMeasuredStartOffset] = useState(0)\n const [retryTrigger, setRetryTrigger] = useState(0)\n const retryCountRef = useRef(0)\n const autoIdRef = useRef(`_ls_so_${Math.random().toString(36).slice(2, 9)}`)\n\n useEffect(() => {\n if (!enabled || !contentId) {\n retryCountRef.current = 0\n return\n }\n\n const measure = () => {\n const scrollEl = scrollElRef.current as any\n if (!scrollEl) return\n\n if (!scrollEl.id) {\n scrollEl.id = autoIdRef.current\n }\n const scrollViewId = scrollEl.id\n\n const instance = Taro.getCurrentInstance()\n const query = instance?.page\n ? Taro.createSelectorQuery().in(instance.page as any)\n : Taro.createSelectorQuery()\n query\n .select(`#${scrollViewId}`)\n .boundingClientRect()\n .select(`#${scrollViewId}`)\n .scrollOffset()\n .select(`#${contentId}`)\n .boundingClientRect()\n .exec((res) => {\n const scrollRect = res?.[0]\n const scrollInfo = res?.[1]\n const contentRect = res?.[2]\n if (!scrollRect || !scrollInfo || !contentRect) return\n\n const scrollTop = scrollInfo.scrollTop ?? 0\n const scrollLeft = scrollInfo.scrollLeft ?? 0\n const value = isHorizontal\n ? Math.max(0, contentRect.left - scrollRect.left + scrollLeft)\n : Math.max(0, contentRect.top - scrollRect.top + scrollTop)\n startOffsetRef && (startOffsetRef.current = value)\n setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value))\n })\n }\n\n const scrollEl = scrollElRef.current\n if (!scrollEl) {\n if (retryCountRef.current < MAX_RETRY) {\n retryCountRef.current += 1\n const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY)\n return () => clearTimeout(id)\n }\n return\n }\n retryCountRef.current = 0\n measure()\n // 对标 H5:scroll 时触发测量(H5 用 scrollEl.addEventListener('scroll', measure))\n scrollEl.addEventListener('scroll', measure)\n // 无 ResizeObserver,用 interval 兜底布局变化\n const interval = setInterval(measure, MEASURE_INTERVAL)\n return () => {\n scrollEl.removeEventListener('scroll', measure)\n clearInterval(interval)\n }\n }, [enabled, scrollElRef, contentId, isHorizontal, retryTrigger])\n\n return measuredStartOffset\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+ /**
3
+ * List 组件内部的 refresher 配置类型(独立于 Refresher 组件)
4
+ * 与 ScrollView refresher 相关属性语义对齐
5
+ */
6
+ export interface ListRefresherConfig {
7
+ refresherEnabled?: boolean;
8
+ refresherThreshold?: number;
9
+ refresherDefaultStyle?: 'black' | 'white' | 'none';
10
+ refresherBackground?: string;
11
+ refresherTriggered?: boolean;
12
+ /** 自定义刷新内容(来自 Refresher 子组件的 children) */
13
+ children?: React.ReactNode;
14
+ onRefresherPulling?: (e?: {
15
+ detail?: {
16
+ deltaY?: number;
17
+ };
18
+ }) => void;
19
+ onRefresherRefresh?: () => void | Promise<void>;
20
+ onRefresherRestore?: () => void;
21
+ onRefresherAbort?: () => void;
22
+ onRefresherWillRefresh?: () => void;
23
+ onRefresherStatusChange?: (e?: {
24
+ detail?: {
25
+ status?: number;
26
+ dy?: number;
27
+ };
28
+ }) => void;
29
+ }
30
+ /** 默认刷新层高度(对齐 Dynamic),无自定义 children 时使用 */
31
+ export declare const DEFAULT_REFRESHER_HEIGHT = 50;
32
+ /** 下拉刷新状态枚举(对齐微信小程序 RefreshStatus) */
33
+ export declare const enum RefreshStatus {
34
+ /** 空闲 */
35
+ Idle = 0,
36
+ /** 超过下拉刷新阈值 */
37
+ CanRefresh = 1,
38
+ /** 刷新中 */
39
+ Refreshing = 2,
40
+ /** 刷新完成 */
41
+ Completed = 3,
42
+ /** 刷新失败 */
43
+ Failed = 4
44
+ }
45
+ interface UseRefresherReturn {
46
+ scrollViewRefresherProps: {
47
+ refresherEnabled?: boolean;
48
+ refresherThreshold?: number;
49
+ refresherDefaultStyle?: string;
50
+ refresherBackground?: string;
51
+ refresherTriggered?: boolean;
52
+ };
53
+ scrollViewRefresherHandlers: {
54
+ onRefresherPulling?: (e: any) => void;
55
+ onRefresherRefresh?: (e: any) => void;
56
+ onRefresherRestore?: () => void;
57
+ onRefresherAbort?: () => void;
58
+ };
59
+ h5RefresherProps: {
60
+ touchHandlers: Record<string, unknown>;
61
+ pullDistance: number;
62
+ isRefreshing: boolean;
63
+ /** H5 单结构下恒为 true,仅兼容旧类型 */
64
+ showRefresherLayer: boolean;
65
+ };
66
+ addImperativeTouchListeners?: (el: HTMLElement) => () => void;
67
+ renderRefresherContent: () => React.ReactNode | null;
68
+ }
69
+ export declare function useRefresher(config: ListRefresherConfig | null,
70
+ /** 列表逻辑顶部对应的 scrollTop,用于触顶判断;H5「顶栏悬浮+只滚列表」时传 0,imperative 内以 DOM scrollTop 为准 */
71
+ scrollTopAtLogicalTop: number,
72
+ /** scrollElement 模式下可选:下拉起始点须在 List 内才触发刷新;未传时默认 true(沿用原逻辑) */
73
+ getIsTouchInListArea?: (ev: TouchEvent) => boolean): UseRefresherReturn;
74
+ export {};