@rainbow-oh/yee-c 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Button/button.d.ts +1 -1
- package/dist/cjs/CSV/download.d.ts +1 -1
- package/dist/cjs/Carousel/carousel.d.ts +2 -2
- package/dist/cjs/Carousel/carousel.js +9 -2
- package/dist/cjs/Carousel/interface.d.ts +5 -0
- package/dist/cjs/Dialog/demo/basic.js +1 -1
- package/dist/cjs/Dialog/dialog.js +1 -1
- package/dist/cjs/Drawer/style/index.less +4 -0
- package/dist/cjs/Field/demo/validation.js +23 -3
- package/dist/cjs/Field/field.js +1 -1
- package/dist/cjs/FloatButton/float-button.d.ts +1 -1
- package/dist/cjs/Form/Field.js +1 -4
- package/dist/cjs/Form/Form.js +1 -1
- package/dist/cjs/Form/Group.js +36 -14
- package/dist/cjs/Form/List.js +23 -3
- package/dist/cjs/Form/demo/async-validate.d.ts +3 -0
- package/dist/cjs/Form/demo/async-validate.js +108 -0
- package/dist/cjs/Form/demo/basic.js +2 -2
- package/dist/cjs/Form/demo/virtual.js +1 -1
- package/dist/cjs/Form/form-store.d.ts +4 -4
- package/dist/cjs/Form/form-store.js +55 -25
- package/dist/cjs/Form/interface.d.ts +10 -7
- package/dist/cjs/Form/style/index.less +15 -0
- package/dist/cjs/Form/utils/validate.d.ts +23 -2
- package/dist/cjs/Form/utils/validate.js +59 -10
- package/dist/cjs/Input/style/index.less +0 -17
- package/dist/cjs/InputNumber/style/index.less +0 -29
- package/dist/cjs/PickerPanel/interface.d.ts +44 -2
- package/dist/cjs/PickerPanel/panels/DatePanel/DateBody.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/DatePanel/DateHeader.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/DatePanel/DateHeader.js +1 -1
- package/dist/cjs/PickerPanel/panels/DatePanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/DateTimePanel/index.d.ts +7 -1
- package/dist/cjs/PickerPanel/panels/DateTimePanel/index.js +18 -4
- package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeBody.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeBody.js +1 -1
- package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeHeader.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeHeader.js +1 -1
- package/dist/cjs/PickerPanel/panels/DecadePanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/DecadePanel/index.js +1 -1
- package/dist/cjs/PickerPanel/panels/Header.d.ts +13 -1
- package/dist/cjs/PickerPanel/panels/MonthPanel/MonthBody.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/MonthPanel/MonthHeader.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/MonthPanel/MonthHeader.js +1 -1
- package/dist/cjs/PickerPanel/panels/MonthPanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/MonthPanel/index.js +1 -1
- package/dist/cjs/PickerPanel/panels/PanelBody.d.ts +21 -1
- package/dist/cjs/PickerPanel/panels/PanelBody.js +3 -3
- package/dist/cjs/PickerPanel/panels/QuarterPanel/QuarterBody.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/QuarterPanel/QuarterHeader.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/QuarterPanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/RangePanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/RangePanel/index.js +2 -2
- package/dist/cjs/PickerPanel/panels/RangePanel/interface.d.ts +5 -5
- package/dist/cjs/PickerPanel/panels/TimePanel/TimeBody.d.ts +17 -1
- package/dist/cjs/PickerPanel/panels/TimePanel/TimeCell.d.ts +7 -1
- package/dist/cjs/PickerPanel/panels/TimePanel/TimeCell.js +1 -1
- package/dist/cjs/PickerPanel/panels/TimePanel/TimeColumn.d.ts +14 -1
- package/dist/cjs/PickerPanel/panels/TimePanel/TimeColumn.js +1 -1
- package/dist/cjs/PickerPanel/panels/TimePanel/TimeHeader.d.ts +4 -1
- package/dist/cjs/PickerPanel/panels/TimePanel/index.d.ts +9 -1
- package/dist/cjs/PickerPanel/panels/WeekPanel/WeekBody.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/WeekPanel/WeekHeader.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/WeekPanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/YearPanel/YearBody.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/YearPanel/YearBody.js +2 -2
- package/dist/cjs/PickerPanel/panels/YearPanel/YearHeader.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/YearPanel/YearHeader.js +7 -1
- package/dist/cjs/PickerPanel/panels/YearPanel/index.d.ts +2 -1
- package/dist/cjs/PickerPanel/panels/YearPanel/index.js +1 -1
- package/dist/cjs/PickerPanel/utils/pickerUtils.d.ts +7 -7
- package/dist/cjs/PickerPanel/utils/pickerUtils.js +2 -2
- package/dist/cjs/Select/demo/basic.js +1 -1
- package/dist/cjs/Select/demo/virtual.d.ts +3 -0
- package/dist/cjs/Select/demo/virtual.js +55 -0
- package/dist/cjs/Select/hooks/useSelectKeyboard.d.ts +7 -1
- package/dist/cjs/Select/hooks/useSelectKeyboard.js +16 -6
- package/dist/cjs/Select/interface.d.ts +44 -0
- package/dist/cjs/Select/option.js +3 -2
- package/dist/cjs/Select/options.js +115 -15
- package/dist/cjs/Select/select.js +20 -4
- package/dist/cjs/Select/style/index.less +17 -13
- package/dist/cjs/Selector/style/index.less +2 -137
- package/dist/cjs/Table/style/index.less +19 -0
- package/dist/cjs/TextArea/style/index.less +0 -17
- package/dist/cjs/hooks/index.d.ts +2 -1
- package/dist/cjs/hooks/index.js +3 -1
- package/dist/cjs/hooks/useEvent.js +4 -1
- package/dist/cjs/hooks/useVirtualList.d.ts +71 -0
- package/dist/cjs/hooks/useVirtualList.js +117 -0
- package/dist/cjs/style/size.css +1 -0
- package/dist/cjs/style/themes.css +1 -1
- package/dist/cjs/style/variables.css +2 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/Button/button.d.ts +1 -1
- package/dist/esm/CSV/download.d.ts +1 -1
- package/dist/esm/Carousel/carousel.d.ts +2 -2
- package/dist/esm/Carousel/carousel.js +5 -1
- package/dist/esm/Carousel/interface.d.ts +5 -0
- package/dist/esm/Dialog/demo/basic.js +1 -1
- package/dist/esm/Dialog/dialog.js +1 -1
- package/dist/esm/Drawer/style/index.less +4 -0
- package/dist/esm/Field/demo/validation.js +30 -9
- package/dist/esm/Field/field.js +2 -1
- package/dist/esm/FloatButton/float-button.d.ts +1 -1
- package/dist/esm/Form/Field.js +3 -4
- package/dist/esm/Form/Form.js +1 -1
- package/dist/esm/Form/Group.js +142 -53
- package/dist/esm/Form/List.js +61 -42
- package/dist/esm/Form/demo/async-validate.d.ts +3 -0
- package/dist/esm/Form/demo/async-validate.js +95 -0
- package/dist/esm/Form/demo/basic.js +4 -2
- package/dist/esm/Form/demo/virtual.js +1 -1
- package/dist/esm/Form/form-store.d.ts +4 -4
- package/dist/esm/Form/form-store.js +187 -93
- package/dist/esm/Form/interface.d.ts +10 -7
- package/dist/esm/Form/style/index.less +15 -0
- package/dist/esm/Form/utils/validate.d.ts +23 -2
- package/dist/esm/Form/utils/validate.js +122 -17
- package/dist/esm/Input/style/index.less +0 -17
- package/dist/esm/InputNumber/style/index.less +0 -29
- package/dist/esm/PickerPanel/interface.d.ts +44 -2
- package/dist/esm/PickerPanel/panels/DatePanel/DateBody.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/DatePanel/DateHeader.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/DatePanel/DateHeader.js +1 -1
- package/dist/esm/PickerPanel/panels/DatePanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/DateTimePanel/index.d.ts +7 -1
- package/dist/esm/PickerPanel/panels/DateTimePanel/index.js +11 -7
- package/dist/esm/PickerPanel/panels/DecadePanel/DecadeBody.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/DecadePanel/DecadeBody.js +2 -1
- package/dist/esm/PickerPanel/panels/DecadePanel/DecadeHeader.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/DecadePanel/DecadeHeader.js +2 -1
- package/dist/esm/PickerPanel/panels/DecadePanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/DecadePanel/index.js +1 -1
- package/dist/esm/PickerPanel/panels/Header.d.ts +13 -1
- package/dist/esm/PickerPanel/panels/MonthPanel/MonthBody.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/MonthPanel/MonthHeader.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/MonthPanel/MonthHeader.js +2 -1
- package/dist/esm/PickerPanel/panels/MonthPanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/MonthPanel/index.js +1 -1
- package/dist/esm/PickerPanel/panels/PanelBody.d.ts +21 -1
- package/dist/esm/PickerPanel/panels/PanelBody.js +2 -4
- package/dist/esm/PickerPanel/panels/QuarterPanel/QuarterBody.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/QuarterPanel/QuarterHeader.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/QuarterPanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/RangePanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/RangePanel/index.js +2 -2
- package/dist/esm/PickerPanel/panels/RangePanel/interface.d.ts +5 -5
- package/dist/esm/PickerPanel/panels/TimePanel/TimeBody.d.ts +17 -1
- package/dist/esm/PickerPanel/panels/TimePanel/TimeCell.d.ts +7 -1
- package/dist/esm/PickerPanel/panels/TimePanel/TimeCell.js +1 -1
- package/dist/esm/PickerPanel/panels/TimePanel/TimeColumn.d.ts +14 -1
- package/dist/esm/PickerPanel/panels/TimePanel/TimeColumn.js +1 -1
- package/dist/esm/PickerPanel/panels/TimePanel/TimeHeader.d.ts +4 -1
- package/dist/esm/PickerPanel/panels/TimePanel/index.d.ts +9 -1
- package/dist/esm/PickerPanel/panels/WeekPanel/WeekBody.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/WeekPanel/WeekHeader.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/WeekPanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/YearPanel/YearBody.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/YearPanel/YearBody.js +3 -2
- package/dist/esm/PickerPanel/panels/YearPanel/YearHeader.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/YearPanel/YearHeader.js +2 -1
- package/dist/esm/PickerPanel/panels/YearPanel/index.d.ts +2 -1
- package/dist/esm/PickerPanel/panels/YearPanel/index.js +1 -1
- package/dist/esm/PickerPanel/picker-panel.js +3 -0
- package/dist/esm/PickerPanel/utils/pickerUtils.d.ts +7 -7
- package/dist/esm/PickerPanel/utils/pickerUtils.js +4 -10
- package/dist/esm/Select/demo/basic.js +1 -1
- package/dist/esm/Select/demo/virtual.d.ts +3 -0
- package/dist/esm/Select/demo/virtual.js +38 -0
- package/dist/esm/Select/hooks/useSelectKeyboard.d.ts +7 -1
- package/dist/esm/Select/hooks/useSelectKeyboard.js +25 -9
- package/dist/esm/Select/interface.d.ts +44 -0
- package/dist/esm/Select/option.js +4 -2
- package/dist/esm/Select/options.js +132 -13
- package/dist/esm/Select/select.js +19 -4
- package/dist/esm/Select/style/index.less +17 -13
- package/dist/esm/Selector/style/index.less +2 -137
- package/dist/esm/Table/style/index.less +19 -0
- package/dist/esm/TextArea/style/index.less +0 -17
- package/dist/esm/hooks/index.d.ts +2 -1
- package/dist/esm/hooks/index.js +2 -1
- package/dist/esm/hooks/useVirtualList.d.ts +71 -0
- package/dist/esm/hooks/useVirtualList.js +129 -0
- package/dist/esm/style/size.css +1 -0
- package/dist/esm/style/themes.css +1 -1
- package/dist/esm/style/variables.css +2 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/umd/yee-c.min.css +2 -2
- package/dist/umd/yee-c.min.js +1 -1
- package/package.json +1 -1
- package/src/Carousel/carousel.tsx +14 -3
- package/src/Carousel/interface.ts +6 -0
- package/src/Cascader/cascader.tsx +3 -1
- package/src/Cascader/column.tsx +1 -1
- package/src/Dialog/demo/basic.tsx +1 -1
- package/src/Dialog/dialog.tsx +1 -1
- package/src/Drawer/style/index.less +4 -0
- package/src/Dropdown/dropdown.tsx +1 -1
- package/src/Field/demo/validation.tsx +2 -2
- package/src/Field/field.tsx +2 -1
- package/src/Field/index.en-US.md +1 -1
- package/src/Field/index.zh-CN.md +1 -1
- package/src/FloatButton/float-button.tsx +5 -3
- package/src/Form/Field.tsx +3 -4
- package/src/Form/Form.tsx +1 -1
- package/src/Form/Group.tsx +15 -12
- package/src/Form/List.tsx +3 -3
- package/src/Form/demo/async-validate.tsx +71 -0
- package/src/Form/demo/basic.tsx +2 -2
- package/src/Form/demo/virtual.tsx +1 -1
- package/src/Form/form-store.ts +37 -21
- package/src/Form/index.en-US.md +6 -5
- package/src/Form/index.zh-CN.md +6 -5
- package/src/Form/interface.ts +13 -7
- package/src/Form/style/index.less +15 -0
- package/src/Form/utils/validate.ts +65 -13
- package/src/Input/style/index.less +0 -17
- package/src/InputNumber/style/index.less +0 -29
- package/src/PickerPanel/interface.ts +43 -2
- package/src/PickerPanel/panels/DatePanel/DateBody.tsx +2 -1
- package/src/PickerPanel/panels/DatePanel/DateHeader.tsx +3 -2
- package/src/PickerPanel/panels/DatePanel/index.tsx +2 -1
- package/src/PickerPanel/panels/DateTimePanel/index.tsx +12 -5
- package/src/PickerPanel/panels/DecadePanel/DecadeBody.tsx +3 -2
- package/src/PickerPanel/panels/DecadePanel/DecadeHeader.tsx +3 -2
- package/src/PickerPanel/panels/DecadePanel/index.tsx +3 -2
- package/src/PickerPanel/panels/Header.tsx +14 -1
- package/src/PickerPanel/panels/MonthPanel/MonthBody.tsx +2 -1
- package/src/PickerPanel/panels/MonthPanel/MonthHeader.tsx +3 -2
- package/src/PickerPanel/panels/MonthPanel/index.tsx +3 -2
- package/src/PickerPanel/panels/PanelBody.tsx +27 -5
- package/src/PickerPanel/panels/QuarterPanel/QuarterBody.tsx +2 -1
- package/src/PickerPanel/panels/QuarterPanel/QuarterHeader.tsx +2 -1
- package/src/PickerPanel/panels/QuarterPanel/index.tsx +2 -1
- package/src/PickerPanel/panels/RangePanel/index.tsx +11 -9
- package/src/PickerPanel/panels/RangePanel/interface.ts +5 -5
- package/src/PickerPanel/panels/TimePanel/TimeBody.tsx +21 -5
- package/src/PickerPanel/panels/TimePanel/TimeCell.tsx +9 -2
- package/src/PickerPanel/panels/TimePanel/TimeColumn.tsx +15 -2
- package/src/PickerPanel/panels/TimePanel/TimeHeader.tsx +5 -1
- package/src/PickerPanel/panels/TimePanel/index.tsx +10 -1
- package/src/PickerPanel/panels/WeekPanel/WeekBody.tsx +2 -1
- package/src/PickerPanel/panels/WeekPanel/WeekHeader.tsx +2 -1
- package/src/PickerPanel/panels/WeekPanel/index.tsx +2 -1
- package/src/PickerPanel/panels/YearPanel/YearBody.tsx +4 -3
- package/src/PickerPanel/panels/YearPanel/YearHeader.tsx +9 -3
- package/src/PickerPanel/panels/YearPanel/index.tsx +3 -2
- package/src/PickerPanel/picker-panel.tsx +5 -3
- package/src/PickerPanel/utils/pickerUtils.ts +17 -8
- package/src/Select/demo/basic.tsx +1 -1
- package/src/Select/demo/virtual.tsx +25 -0
- package/src/Select/hooks/useSelectKeyboard.ts +30 -6
- package/src/Select/index.en-US.md +4 -0
- package/src/Select/index.zh-CN.md +4 -0
- package/src/Select/interface.ts +48 -2
- package/src/Select/option.tsx +2 -1
- package/src/Select/options.tsx +139 -8
- package/src/Select/select.tsx +23 -1
- package/src/Select/style/index.less +17 -13
- package/src/Selector/style/index.less +2 -137
- package/src/Splitter/hooks/useMove.ts +2 -2
- package/src/Table/style/index.less +19 -0
- package/src/TextArea/style/index.less +0 -17
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useEvent.ts +7 -4
- package/src/hooks/useMergedState.ts +6 -4
- package/src/hooks/useVirtualList.ts +169 -0
- package/src/style/size.css +1 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import useEvent from './useEvent';
|
|
3
|
+
import useResizeObserver from './useResizeObserver';
|
|
4
|
+
|
|
5
|
+
export interface UseVirtualListOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Total number of items in the list.
|
|
8
|
+
*/
|
|
9
|
+
itemCount: number;
|
|
10
|
+
/**
|
|
11
|
+
* Fixed height of every item in pixels.
|
|
12
|
+
*/
|
|
13
|
+
itemHeight: number;
|
|
14
|
+
/**
|
|
15
|
+
* Extra items rendered above and below the visible window
|
|
16
|
+
* to avoid white flashes while scrolling.
|
|
17
|
+
* @default 4
|
|
18
|
+
*/
|
|
19
|
+
overscan?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface UseVirtualListResult {
|
|
23
|
+
/**
|
|
24
|
+
* Inclusive start index of the render window (already includes overscan).
|
|
25
|
+
*/
|
|
26
|
+
start: number;
|
|
27
|
+
/**
|
|
28
|
+
* Exclusive end index of the render window (already includes overscan).
|
|
29
|
+
*/
|
|
30
|
+
end: number;
|
|
31
|
+
/**
|
|
32
|
+
* Vertical offset to apply to the rendered block, equal to `start * itemHeight`.
|
|
33
|
+
* Use it as `transform: translateY(offsetY)` or `top: offsetY`.
|
|
34
|
+
*/
|
|
35
|
+
offsetY: number;
|
|
36
|
+
/**
|
|
37
|
+
* Total scrollable height, equal to `itemCount * itemHeight`.
|
|
38
|
+
* Apply it to the inner spacer element so the scrollbar matches the full list.
|
|
39
|
+
*/
|
|
40
|
+
totalHeight: number;
|
|
41
|
+
/**
|
|
42
|
+
* Ref to bind to the scroll container element.
|
|
43
|
+
*/
|
|
44
|
+
viewportRef: React.RefObject<HTMLDivElement | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Stable scroll handler (rAF-throttled). Bind to the viewport's `onScroll`.
|
|
47
|
+
*/
|
|
48
|
+
onScroll: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Scroll the viewport so that the item at `index` is visible.
|
|
51
|
+
* Used by keyboard navigation to replace `scrollIntoView`.
|
|
52
|
+
*/
|
|
53
|
+
scrollToIndex: (index: number) => void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Fixed-height virtual scrolling hook.
|
|
58
|
+
*
|
|
59
|
+
* Renders only the items inside the visible window (plus an `overscan` buffer)
|
|
60
|
+
* and keeps the DOM node count constant regardless of `itemCount`.
|
|
61
|
+
*
|
|
62
|
+
* Usage:
|
|
63
|
+
* const { start, end, offsetY, totalHeight, viewportRef, onScroll, scrollToIndex } =
|
|
64
|
+
* useVirtualList({ itemCount, itemHeight });
|
|
65
|
+
*
|
|
66
|
+
* <div ref={viewportRef} onScroll={onScroll} style={{ maxHeight: 200, overflowY: 'auto' }}>
|
|
67
|
+
* <div style={{ height: totalHeight, position: 'relative' }}>
|
|
68
|
+
* {items.slice(start, end).map((it, i) => (
|
|
69
|
+
* <div key={it.key} style={{ position: 'absolute', height: itemHeight, transform: `translateY(${offsetY + i * itemHeight}px)` }}>
|
|
70
|
+
* {it.content}
|
|
71
|
+
* </div>
|
|
72
|
+
* ))}
|
|
73
|
+
* </div>
|
|
74
|
+
* </div>
|
|
75
|
+
*/
|
|
76
|
+
export default function useVirtualList({
|
|
77
|
+
itemCount,
|
|
78
|
+
itemHeight,
|
|
79
|
+
overscan = 4,
|
|
80
|
+
}: UseVirtualListOptions): UseVirtualListResult {
|
|
81
|
+
const [scrollTop, setScrollTop] = useState(0);
|
|
82
|
+
const [visibleHeight, setVisibleHeight] = useState(0);
|
|
83
|
+
const rafRef = useRef<number | null>(null);
|
|
84
|
+
|
|
85
|
+
// useResizeObserver owns its ref; we reuse it as the viewport ref so the
|
|
86
|
+
// scroll container and the measured element are the same node.
|
|
87
|
+
const { ref: viewportRef } = useResizeObserver<HTMLDivElement>((entries) => {
|
|
88
|
+
const entry = entries[0];
|
|
89
|
+
if (!entry) return;
|
|
90
|
+
const h = entry.contentRect.height;
|
|
91
|
+
setVisibleHeight((prev) => (prev === h ? prev : h));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const totalHeight = itemCount * itemHeight;
|
|
95
|
+
|
|
96
|
+
// Read the live scrollTop / clientHeight from the viewport node.
|
|
97
|
+
const readViewport = useEvent(() => {
|
|
98
|
+
const viewport = viewportRef.current;
|
|
99
|
+
if (!viewport) return;
|
|
100
|
+
const top = viewport.scrollTop;
|
|
101
|
+
const h = viewport.clientHeight;
|
|
102
|
+
setScrollTop((prev) => (prev === top ? prev : top));
|
|
103
|
+
setVisibleHeight((prev) => (prev === h ? prev : h));
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const onScroll = useEvent(() => {
|
|
107
|
+
if (rafRef.current !== null) return;
|
|
108
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
109
|
+
rafRef.current = null;
|
|
110
|
+
readViewport();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
useEffect(
|
|
115
|
+
() => () => {
|
|
116
|
+
if (rafRef.current !== null) {
|
|
117
|
+
cancelAnimationFrame(rafRef.current);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
[],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Measure once on mount (ResizeObserver fires shortly after, this covers the first frame).
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
readViewport();
|
|
126
|
+
}, [readViewport]);
|
|
127
|
+
|
|
128
|
+
// Keep scrollTop within bounds when the data shrinks (e.g. after filtering),
|
|
129
|
+
// otherwise the viewport would sit at an offset with empty space below.
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const viewport = viewportRef.current;
|
|
132
|
+
if (!viewport) return;
|
|
133
|
+
const maxScroll = Math.max(0, totalHeight - viewport.clientHeight);
|
|
134
|
+
if (viewport.scrollTop > maxScroll) {
|
|
135
|
+
viewport.scrollTop = maxScroll;
|
|
136
|
+
setScrollTop(maxScroll);
|
|
137
|
+
}
|
|
138
|
+
}, [totalHeight, viewportRef]);
|
|
139
|
+
|
|
140
|
+
const scrollToIndex = useEvent((index: number) => {
|
|
141
|
+
const viewport = viewportRef.current;
|
|
142
|
+
if (!viewport) return;
|
|
143
|
+
const maxScroll = Math.max(0, totalHeight - viewport.clientHeight);
|
|
144
|
+
const target = Math.min(Math.max(0, index * itemHeight), maxScroll);
|
|
145
|
+
if (viewport.scrollTop !== target) {
|
|
146
|
+
viewport.scrollTop = target;
|
|
147
|
+
}
|
|
148
|
+
readViewport();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Fallback for the first paint before ResizeObserver reports a height,
|
|
152
|
+
// so we still render at least one screen + buffer.
|
|
153
|
+
const effectiveVisibleHeight = visibleHeight || itemHeight;
|
|
154
|
+
const visibleCount = Math.ceil(effectiveVisibleHeight / itemHeight);
|
|
155
|
+
|
|
156
|
+
const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
|
|
157
|
+
const end = Math.min(itemCount, start + visibleCount + overscan * 2);
|
|
158
|
+
const offsetY = start * itemHeight;
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
start,
|
|
162
|
+
end,
|
|
163
|
+
offsetY,
|
|
164
|
+
totalHeight,
|
|
165
|
+
viewportRef,
|
|
166
|
+
onScroll,
|
|
167
|
+
scrollToIndex,
|
|
168
|
+
};
|
|
169
|
+
}
|
package/src/style/size.css
CHANGED