react-virtual-renderer 1.1.3 → 1.1.5

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 (92) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/App.js +65 -3
  3. package/dist/App.js.map +1 -1
  4. package/dist/components/VirtualGrid.d.ts +30 -0
  5. package/dist/components/VirtualGrid.d.ts.map +1 -1
  6. package/dist/components/VirtualGrid.js +147 -117
  7. package/dist/components/VirtualGrid.js.map +1 -1
  8. package/dist/components/VirtualList.d.ts +0 -4
  9. package/dist/components/VirtualList.d.ts.map +1 -1
  10. package/dist/components/VirtualList.js +76 -86
  11. package/dist/components/VirtualList.js.map +1 -1
  12. package/dist/components/VirtualLiveRegion.d.ts +12 -0
  13. package/dist/components/VirtualLiveRegion.d.ts.map +1 -0
  14. package/dist/components/VirtualLiveRegion.js +27 -0
  15. package/dist/components/VirtualLiveRegion.js.map +1 -0
  16. package/dist/core/FenwickTree.d.ts +47 -0
  17. package/dist/core/FenwickTree.d.ts.map +1 -0
  18. package/dist/core/FenwickTree.js +206 -0
  19. package/dist/core/FenwickTree.js.map +1 -0
  20. package/dist/core/GridLayoutEngine.d.ts +64 -0
  21. package/dist/core/GridLayoutEngine.d.ts.map +1 -0
  22. package/dist/core/GridLayoutEngine.js +153 -0
  23. package/dist/core/GridLayoutEngine.js.map +1 -0
  24. package/dist/core/GroupedListEngine.d.ts +21 -0
  25. package/dist/core/GroupedListEngine.d.ts.map +1 -0
  26. package/dist/core/GroupedListEngine.js +22 -0
  27. package/dist/core/GroupedListEngine.js.map +1 -0
  28. package/dist/core/ListController.d.ts +31 -0
  29. package/dist/core/ListController.d.ts.map +1 -0
  30. package/dist/core/ListController.js +71 -0
  31. package/dist/core/ListController.js.map +1 -0
  32. package/dist/core/MeasurementSystem.d.ts +1 -1
  33. package/dist/core/MeasurementSystem.d.ts.map +1 -1
  34. package/dist/core/MeasurementSystem.js +22 -10
  35. package/dist/core/MeasurementSystem.js.map +1 -1
  36. package/dist/core/VirtualizationEngine.d.ts +24 -13
  37. package/dist/core/VirtualizationEngine.d.ts.map +1 -1
  38. package/dist/core/VirtualizationEngine.js +50 -87
  39. package/dist/core/VirtualizationEngine.js.map +1 -1
  40. package/dist/examples/DynamicHeightLists.d.ts +2 -0
  41. package/dist/examples/DynamicHeightLists.d.ts.map +1 -0
  42. package/dist/examples/DynamicHeightLists.js +42 -0
  43. package/dist/examples/DynamicHeightLists.js.map +1 -0
  44. package/dist/examples/FixedGrid.d.ts +2 -0
  45. package/dist/examples/FixedGrid.d.ts.map +1 -0
  46. package/dist/examples/FixedGrid.js +40 -0
  47. package/dist/examples/FixedGrid.js.map +1 -0
  48. package/dist/examples/GroupedContactList.d.ts +2 -0
  49. package/dist/examples/GroupedContactList.d.ts.map +1 -0
  50. package/dist/examples/GroupedContactList.js +20 -0
  51. package/dist/examples/GroupedContactList.js.map +1 -0
  52. package/dist/examples/InfiniteScrollLists.d.ts +2 -0
  53. package/dist/examples/InfiniteScrollLists.d.ts.map +1 -0
  54. package/dist/examples/InfiniteScrollLists.js +93 -0
  55. package/dist/examples/InfiniteScrollLists.js.map +1 -0
  56. package/dist/examples/MasonaryGrid.d.ts +2 -0
  57. package/dist/examples/MasonaryGrid.d.ts.map +1 -0
  58. package/dist/examples/MasonaryGrid.js +36 -0
  59. package/dist/examples/MasonaryGrid.js.map +1 -0
  60. package/dist/examples/PerfHarness.d.ts +2 -0
  61. package/dist/examples/PerfHarness.d.ts.map +1 -0
  62. package/dist/examples/PerfHarness.js +131 -0
  63. package/dist/examples/PerfHarness.js.map +1 -0
  64. package/dist/hooks/useBidirectionalInfiniteScroll.d.ts +32 -0
  65. package/dist/hooks/useBidirectionalInfiniteScroll.d.ts.map +1 -0
  66. package/dist/hooks/useBidirectionalInfiniteScroll.js +89 -0
  67. package/dist/hooks/useBidirectionalInfiniteScroll.js.map +1 -0
  68. package/dist/hooks/useInfiniteScroll.d.ts +36 -12
  69. package/dist/hooks/useInfiniteScroll.d.ts.map +1 -1
  70. package/dist/hooks/useInfiniteScroll.js +46 -45
  71. package/dist/hooks/useInfiniteScroll.js.map +1 -1
  72. package/dist/hooks/useRevoingTabIndex.d.ts +11 -0
  73. package/dist/hooks/useRevoingTabIndex.d.ts.map +1 -0
  74. package/dist/hooks/useRevoingTabIndex.js +28 -0
  75. package/dist/hooks/useRevoingTabIndex.js.map +1 -0
  76. package/dist/hooks/useVirtualAllyProps.d.ts +23 -0
  77. package/dist/hooks/useVirtualAllyProps.d.ts.map +1 -0
  78. package/dist/hooks/useVirtualAllyProps.js +25 -0
  79. package/dist/hooks/useVirtualAllyProps.js.map +1 -0
  80. package/dist/hooks/useVirtualList.d.ts +2 -0
  81. package/dist/hooks/useVirtualList.d.ts.map +1 -1
  82. package/dist/hooks/useVirtualList.js +12 -4
  83. package/dist/hooks/useVirtualList.js.map +1 -1
  84. package/dist/index.cjs.js +1 -1
  85. package/dist/index.cjs.js.map +1 -1
  86. package/dist/index.esm.js +1 -1
  87. package/dist/index.esm.js.map +1 -1
  88. package/dist/main.js +4 -4
  89. package/dist/main.js.map +1 -1
  90. package/dist/types.d.ts +10 -0
  91. package/dist/types.d.ts.map +1 -1
  92. package/package.json +1 -1
@@ -1,10 +1,26 @@
1
+ import { FenwickTree } from './FenwickTree';
2
+ /**
3
+ * Core offset/range math shared by VirtualList and VirtualGrid.
4
+ *
5
+ * PERFORMANCE: previously this held a plain prefix-sum array and a
6
+ * `dirty` flag, rebuilding the WHOLE array (O(n)) the next time
7
+ * anything was read after any single item's size changed. Every read
8
+ * (getItemOffset, getTotalSize, the binary search for visible range)
9
+ * paid that O(n) cost whenever a measurement had landed since the last
10
+ * read - which, for a dynamic-height list, is essentially every scroll
11
+ * frame.
12
+ *
13
+ * This version is backed by a FenwickTree (see FenwickTree.ts). There
14
+ * is no dirty flag and no rebuild: every operation below is O(log n),
15
+ * full stop, regardless of how many items have been re-measured.
16
+ */
1
17
  export class VirtualizationEngine {
2
18
  constructor(estimatedItemSize = 35) {
3
- Object.defineProperty(this, "itemSizeMap", {
19
+ Object.defineProperty(this, "tree", {
4
20
  enumerable: true,
5
21
  configurable: true,
6
22
  writable: true,
7
- value: {}
23
+ value: void 0
8
24
  });
9
25
  Object.defineProperty(this, "estimatedItemSize", {
10
26
  enumerable: true,
@@ -18,117 +34,64 @@ export class VirtualizationEngine {
18
34
  writable: true,
19
35
  value: 0
20
36
  });
21
- // prefix sum cache
22
- Object.defineProperty(this, "prefix", {
23
- enumerable: true,
24
- configurable: true,
25
- writable: true,
26
- value: [0]
27
- });
28
- Object.defineProperty(this, "dirty", {
29
- enumerable: true,
30
- configurable: true,
31
- writable: true,
32
- value: true
33
- });
34
37
  this.estimatedItemSize = estimatedItemSize;
38
+ this.tree = new FenwickTree(0);
35
39
  }
36
40
  setItemCount(count) {
37
- /**
38
- * FIX: previously this unconditionally set `dirty = true`
39
- * on every call, even when the count hadn't changed. Since
40
- * getVisibleRange() calls setItemCount() on every single
41
- * invocation (i.e. every scroll frame), that forced a full
42
- * O(n) prefix-sum rebuild every frame regardless of whether
43
- * anything actually changed.
44
- *
45
- * Now we only mark dirty when the count actually differs.
46
- * Measurement updates still mark dirty via recordItemSize(),
47
- * so cache invalidation on real changes is unaffected.
48
- */
49
- if (this.itemCount === count) {
41
+ if (this.itemCount === count)
50
42
  return;
51
- }
43
+ this.tree.resize(count, this.estimatedItemSize);
52
44
  this.itemCount = count;
53
- this.dirty = true;
54
45
  }
55
46
  recordItemSize(index, size) {
56
- if (this.itemSizeMap[index] === size)
47
+ if (index < 0 || index >= this.itemCount)
57
48
  return;
58
- this.itemSizeMap[index] = size;
59
- this.dirty = true;
49
+ this.tree.update(index, size);
60
50
  }
61
51
  /**
62
- * NEW (additive): Invalidate cached measurements from `fromIndex`
63
- * onward (inclusive), or all measurements if `fromIndex` is
64
- * omitted. Affected indices fall back to `estimatedItemSize`
65
- * until they are re-measured and recordItemSize() is called
66
- * again for them.
52
+ * Invalidate cached measurements from `fromIndex` onward
53
+ * (inclusive), or everything if omitted. Affected indices fall
54
+ * back to `estimatedItemSize` until re-measured.
67
55
  *
68
- * Does not remove items below fromIndex, and does not touch
69
- * itemCount. Safe to call at any time; it only marks the
70
- * prefix-sum cache dirty so the next read rebuilds it.
56
+ * Each reset index is a single O(log n) point update - so
57
+ * invalidating a suffix of k items is O(k log n), not a full
58
+ * array rebuild. A full invalidate (no fromIndex) is the one
59
+ * intentionally O(n) path in this class, reserved for "the whole
60
+ * dataset changed" situations, not the scroll hot path.
71
61
  */
72
62
  invalidateFrom(fromIndex) {
73
63
  if (fromIndex === undefined) {
74
- this.itemSizeMap = {};
75
- this.dirty = true;
64
+ this.tree.resetAll(this.estimatedItemSize);
76
65
  return;
77
66
  }
78
- if (fromIndex < 0) {
79
- fromIndex = 0;
80
- }
81
- for (const key of Object.keys(this.itemSizeMap)) {
82
- const index = Number(key);
83
- if (index >= fromIndex) {
84
- delete this.itemSizeMap[index];
85
- }
86
- }
87
- this.dirty = true;
88
- }
89
- rebuildPrefix() {
90
- let sum = 0;
91
- this.prefix = [0];
92
- for (let i = 0; i < this.itemCount; i++) {
93
- sum += this.itemSizeMap[i] ?? this.estimatedItemSize;
94
- this.prefix[i + 1] = sum;
67
+ const start = Math.max(0, fromIndex);
68
+ for (let i = start; i < this.itemCount; i++) {
69
+ this.tree.update(i, this.estimatedItemSize);
95
70
  }
96
- this.dirty = false;
97
71
  }
98
72
  getItemSize(index) {
99
- return this.itemSizeMap[index] ?? this.estimatedItemSize;
73
+ if (index < 0 || index >= this.itemCount)
74
+ return this.estimatedItemSize;
75
+ return this.tree.getValue(index);
100
76
  }
101
77
  getItemOffset(index) {
102
- if (this.dirty)
103
- this.rebuildPrefix();
104
- return this.prefix[index] ?? 0;
78
+ return this.tree.prefixSum(Math.max(0, index));
105
79
  }
106
80
  getTotalSize() {
107
- if (this.dirty)
108
- this.rebuildPrefix();
109
- return this.prefix[this.itemCount] || 0;
110
- }
111
- binarySearch(offset) {
112
- if (this.dirty)
113
- this.rebuildPrefix();
114
- let low = 0;
115
- let high = this.itemCount - 1;
116
- while (low <= high) {
117
- const mid = (low + high) >> 1;
118
- const value = this.prefix[mid];
119
- if (value === offset)
120
- return mid;
121
- if (value < offset)
122
- low = mid + 1;
123
- else
124
- high = mid - 1;
125
- }
126
- return Math.max(0, low - 1);
81
+ return this.tree.total();
127
82
  }
128
83
  getVisibleRange(scrollOffset, containerSize, itemCount, overscan = 5) {
129
84
  this.setItemCount(itemCount);
130
- const start = this.binarySearch(scrollOffset);
131
- const end = this.binarySearch(scrollOffset + containerSize);
85
+ if (itemCount === 0) {
86
+ return {
87
+ startIndex: 0,
88
+ endIndex: -1,
89
+ overscanStartIndex: 0,
90
+ overscanEndIndex: -1,
91
+ };
92
+ }
93
+ const start = this.tree.findIndexAtOffset(scrollOffset);
94
+ const end = this.tree.findIndexAtOffset(scrollOffset + containerSize);
132
95
  return {
133
96
  startIndex: Math.max(0, start - overscan),
134
97
  endIndex: Math.min(itemCount - 1, end + overscan),
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizationEngine.js","sourceRoot":"","sources":["../../src/core/VirtualizationEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VirtualizationEngine.js","sourceRoot":"","sources":["../../src/core/VirtualizationEngine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function DynamicHeightListExample(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=DynamicHeightLists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DynamicHeightLists.d.ts","sourceRoot":"","sources":["../../src/examples/DynamicHeightLists.tsx"],"names":[],"mappings":"AAqDA,MAAM,CAAC,OAAO,UAAU,wBAAwB,4CAyD/C"}
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { VirtualList } from "../components/VirtualList";
4
+ async function fetchRealComments(signal) {
5
+ const res = await fetch("https://jsonplaceholder.typicode.com/comments", { signal });
6
+ if (!res.ok)
7
+ throw new Error(`Failed to fetch comments: ${res.status}`);
8
+ return res.json();
9
+ }
10
+ function tileToTargetSize(source, targetCount) {
11
+ return Array.from({ length: targetCount }, (_, i) => {
12
+ const src = source[i % source.length];
13
+ return { id: i, author: src.email, body: src.body };
14
+ });
15
+ }
16
+ const TARGET_COUNT = 50000;
17
+ export default function DynamicHeightListExample() {
18
+ const [comments, setComments] = React.useState(null);
19
+ const [error, setError] = React.useState(null);
20
+ const listRef = React.useRef(null);
21
+ React.useEffect(() => {
22
+ const controller = new AbortController();
23
+ fetchRealComments(controller.signal)
24
+ .then((raw) => setComments(tileToTargetSize(raw, TARGET_COUNT)))
25
+ .catch((err) => {
26
+ if (!controller.signal.aborted) {
27
+ setError(err instanceof Error ? err.message : "Failed to load comments");
28
+ }
29
+ });
30
+ return () => controller.abort();
31
+ }, []);
32
+ if (error) {
33
+ return _jsx("div", { style: { padding: 16, color: "#b91c1c" }, children: error });
34
+ }
35
+ if (!comments) {
36
+ return _jsx("div", { style: { padding: 16, color: "#888" }, children: "Loading real comment data\u2026" });
37
+ }
38
+ return (_jsxs("div", { children: [_jsx("div", { style: { marginBottom: 8 }, children: _jsx("button", { onClick: () => {
39
+ listRef.current?.scrollTo({ top: 500000, behavior: "smooth" });
40
+ }, children: "Jump deep into the list (tests offset math on unmeasured items)" }) }), _jsx(VirtualList, { ref: listRef, items: comments, height: 600, width: "100%", estimatedItemSize: 90, overscan: 6, itemKey: (_, item) => item.id, itemStyle: { borderBottom: "1px solid #eee", padding: "8px 12px" }, renderItem: ({ item }) => (_jsxs("div", { children: [_jsx("strong", { children: item.author }), _jsx("p", { style: { margin: "4px 0 0" }, children: item.body })] })) })] }));
41
+ }
42
+ //# sourceMappingURL=DynamicHeightLists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DynamicHeightLists.js","sourceRoot":"","sources":["../../src/examples/DynamicHeightLists.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAqCxD,KAAK,UAAU,iBAAiB,CAAC,MAAmB;IAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,+CAA+C,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACrF,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAoB,EAAE,WAAmB;IAC/D,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,YAAY,GAAG,KAAK,CAAC;AAE3B,MAAM,CAAC,OAAO,UAAU,wBAAwB;IAC5C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAmB,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEnD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QAEzC,iBAAiB,CAAC,UAAU,CAAC,MAAM,CAAC;aAC/B,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;aAC/D,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC7B,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;YAC7E,CAAC;QACL,CAAC,CAAC,CAAC;QAEP,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,KAAK,EAAE,CAAC;QACR,OAAO,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAG,KAAK,GAAO,CAAC;IACxE,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gDAAkC,CAAC;IACxF,CAAC;IAED,OAAO,CACH,0BACI,cAAK,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,YAC3B,iBACI,OAAO,EAAE,GAAG,EAAE;wBACV,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;oBACnE,CAAC,gFAGI,GACP,EAEN,KAAC,WAAW,IACR,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,GAAG,EACX,KAAK,EAAC,MAAM,EACZ,iBAAiB,EAAE,EAAE,EACrB,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAC7B,SAAS,EAAE,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,EAClE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACtB,0BACI,2BAAS,IAAI,CAAC,MAAM,GAAU,EAC9B,YAAG,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,YAAG,IAAI,CAAC,IAAI,GAAK,IAC9C,CACT,GACH,IACA,CACT,CAAC;AACN,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function FixedGridExample(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=FixedGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FixedGrid.d.ts","sourceRoot":"","sources":["../../src/examples/FixedGrid.tsx"],"names":[],"mappings":"AAoDA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CAwDvC"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { VirtualGrid } from "../components/VirtualGrid";
4
+ async function fetchRealProducts(signal) {
5
+ const res = await fetch("https://dummyjson.com/products?limit=194", { signal });
6
+ if (!res.ok)
7
+ throw new Error(`Failed to fetch products: ${res.status}`);
8
+ const data = await res.json();
9
+ return data.products;
10
+ }
11
+ function tileToTargetSize(source, targetCount) {
12
+ return Array.from({ length: targetCount }, (_, i) => {
13
+ const src = source[i % source.length];
14
+ return { id: i, name: src.title, price: src.price, thumbnail: src.thumbnail };
15
+ });
16
+ }
17
+ const TARGET_COUNT = 200000;
18
+ export default function FixedGridExample() {
19
+ const [products, setProducts] = React.useState(null);
20
+ const [error, setError] = React.useState(null);
21
+ React.useEffect(() => {
22
+ const controller = new AbortController();
23
+ fetchRealProducts(controller.signal)
24
+ .then((raw) => setProducts(tileToTargetSize(raw, TARGET_COUNT)))
25
+ .catch((err) => {
26
+ if (!controller.signal.aborted) {
27
+ setError(err instanceof Error ? err.message : "Failed to load products");
28
+ }
29
+ });
30
+ return () => controller.abort();
31
+ }, []);
32
+ if (error) {
33
+ return _jsx("div", { style: { padding: 16, color: "#b91c1c" }, children: error });
34
+ }
35
+ if (!products) {
36
+ return _jsx("div", { style: { padding: 16, color: "#888" }, children: "Loading real product data\u2026" });
37
+ }
38
+ return (_jsx(VirtualGrid, { items: products, layout: "grid", columnCount: "auto", rowHeight: 220, gap: 16, height: 700, width: "100%", overscan: 8, itemKey: (_, item) => item.id, itemStyle: { borderRadius: 8, overflow: "hidden", border: "1px solid #eee" }, renderItem: ({ item }) => (_jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [_jsx("img", { src: item.thumbnail, alt: item.name, loading: "lazy", style: { flex: 1, width: "100%", objectFit: "cover" } }), _jsxs("div", { style: { padding: 8 }, children: [_jsx("div", { style: { fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: item.name }), _jsxs("div", { style: { color: "#555" }, children: ["$", item.price.toFixed(2)] })] })] })) }));
39
+ }
40
+ //# sourceMappingURL=FixedGrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FixedGrid.js","sourceRoot":"","sources":["../../src/examples/FixedGrid.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAmCxD,KAAK,UAAU,iBAAiB,CAAC,MAAmB;IAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,0CAA0C,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAChF,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAoB,EAAE,WAAmB;IAC/D,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;IAClF,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,MAAM,CAAC,OAAO,UAAU,gBAAgB;IACpC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAmB,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAE9D,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QAEzC,iBAAiB,CAAC,UAAU,CAAC,MAAM,CAAC;aAC/B,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;aAC/D,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC7B,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;YAC7E,CAAC;QACL,CAAC,CAAC,CAAC;QAEP,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,KAAK,EAAE,CAAC;QACR,OAAO,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAG,KAAK,GAAO,CAAC;IACxE,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gDAAkC,CAAC;IACxF,CAAC;IAED,OAAO,CACH,KAAC,WAAW,IACR,KAAK,EAAE,QAAQ,EACf,MAAM,EAAC,MAAM,EACb,WAAW,EAAC,MAAM,EAClB,SAAS,EAAE,GAAG,EACd,GAAG,EAAE,EAAE,EACP,MAAM,EAAE,GAAG,EACX,KAAK,EAAC,MAAM,EACZ,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAC7B,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAC5E,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACtB,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aACpE,cACI,GAAG,EAAE,IAAI,CAAC,SAAS,EACnB,GAAG,EAAE,IAAI,CAAC,IAAI,EACd,OAAO,EAAC,MAAM,EACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GACvD,EACF,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,aACtB,cAAK,KAAK,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,YAC9F,IAAI,CAAC,IAAI,GACR,EACN,eAAK,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAO,IAC3D,IACJ,CACT,GACH,CACL,CAAC;AACN,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function GroupedContactListExample(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=GroupedContactList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupedContactList.d.ts","sourceRoot":"","sources":["../../src/examples/GroupedContactList.tsx"],"names":[],"mappings":"AAcA,MAAM,CAAC,OAAO,UAAU,yBAAyB,4CAkChD"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // examples/GroupedContactList.tsx
3
+ import React from 'react';
4
+ import { VirtualList } from '../components/VirtualList';
5
+ import { flattenGroups } from '../core/GroupedListEngine';
6
+ const FIRST_NAMES = [
7
+ 'Amara', 'Beatrix', 'Cyrus', 'Dahlia', 'Elias', 'Farah', 'Gideon', 'Harlow',
8
+ 'Ines', 'Jasper', 'Kira', 'Lior', 'Marisol', 'Noor', 'Otis', 'Priya',
9
+ 'Quinn', 'Rosalind', 'Soren', 'Talia', 'Uma', 'Vance', 'Willa', 'Xiomara',
10
+ 'Yusuf', 'Zara',
11
+ ];
12
+ export default function GroupedContactListExample() {
13
+ const contacts = React.useMemo(() => Array.from({ length: 5000 }, (_, i) => {
14
+ const first = FIRST_NAMES[i % FIRST_NAMES.length];
15
+ return { id: i, name: `${first} ${String(i).padStart(4, '0')}` };
16
+ }).sort((a, b) => a.name.localeCompare(b.name)), []);
17
+ const { rows, stickyIndices } = React.useMemo(() => flattenGroups({ items: contacts, getGroupKey: (c) => c.name[0].toUpperCase() }), [contacts]);
18
+ return (_jsx(VirtualList, { items: rows, height: 600, width: "100%", estimatedItemSize: 44, stickyIndices: stickyIndices, itemKey: (_, row) => (row.type === 'header' ? `h-${row.groupKey}` : row.item.id), renderItem: ({ item: row }) => row.type === 'header' ? (_jsx("div", { style: { background: '#f8f9fa', fontWeight: 700, padding: '6px 12px' }, children: row.groupKey })) : (_jsx("div", { style: { padding: '10px 12px' }, children: row.item.name })) }));
19
+ }
20
+ //# sourceMappingURL=GroupedContactList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupedContactList.js","sourceRoot":"","sources":["../../src/examples/GroupedContactList.tsx"],"names":[],"mappings":";AAAA,kCAAkC;AAClC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI1D,MAAM,WAAW,GAAG;IAChB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ;IAC3E,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IACpE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS;IACzE,OAAO,EAAE,MAAM;CAClB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,yBAAyB;IAC7C,MAAM,QAAQ,GAAc,KAAK,CAAC,OAAO,CACrC,GAAG,EAAE,CACD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EACnD,EAAE,CACL,CAAC;IAEF,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC,OAAO,CACzC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,EACrF,CAAC,QAAQ,CAAC,CACb,CAAC;IAEF,OAAO,CACH,KAAC,WAAW,IACR,KAAK,EAAE,IAAI,EACX,MAAM,EAAE,GAAG,EACX,KAAK,EAAC,MAAM,EACZ,iBAAiB,EAAE,EAAE,EACrB,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAK,CAAC,EAAE,CAAC,EACjF,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAC1B,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CACpB,cAAK,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,YACtE,GAAG,CAAC,QAAQ,GACX,CACT,CAAC,CAAC,CAAC,CACA,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,YAAG,GAAG,CAAC,IAAK,CAAC,IAAI,GAAO,CAC/D,GAEP,CACL,CAAC;AACN,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function InfiniteScrollExample(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=InfiniteScrollLists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InfiniteScrollLists.d.ts","sourceRoot":"","sources":["../../src/examples/InfiniteScrollLists.tsx"],"names":[],"mappings":"AA6EA,MAAM,CAAC,OAAO,UAAU,qBAAqB,4CA4H5C"}
@@ -0,0 +1,93 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { VirtualList } from "../components/VirtualList";
4
+ import { useInfiniteScroll } from "../hooks/useInfiniteScroll";
5
+ const PAGE_SIZE = 20;
6
+ async function fetchPostsPage(skip, signal) {
7
+ const res = await fetch(`https://dummyjson.com/posts?limit=${PAGE_SIZE}&skip=${skip}`, { signal });
8
+ if (!res.ok)
9
+ throw new Error(`Failed to fetch posts: ${res.status}`);
10
+ return res.json();
11
+ }
12
+ function normalizePost(raw) {
13
+ const reactions = typeof raw.reactions === "number"
14
+ ? { likes: raw.reactions, dislikes: 0 }
15
+ : raw.reactions;
16
+ return {
17
+ id: raw.id,
18
+ title: raw.title,
19
+ body: raw.body,
20
+ tags: raw.tags,
21
+ likes: reactions.likes,
22
+ dislikes: reactions.dislikes,
23
+ views: raw.views,
24
+ };
25
+ }
26
+ export default function InfiniteScrollExample() {
27
+ const [items, setItems] = React.useState([]);
28
+ const [total, setTotal] = React.useState(null);
29
+ const [isLoading, setIsLoading] = React.useState(false);
30
+ const [error, setError] = React.useState(null);
31
+ const containerRef = React.useRef(null);
32
+ const abortRef = React.useRef(null);
33
+ const hasMore = total === null || items.length < total;
34
+ const loadMore = React.useCallback(async () => {
35
+ if (total !== null && items.length >= total)
36
+ return;
37
+ const controller = new AbortController();
38
+ abortRef.current = controller;
39
+ setIsLoading(true);
40
+ setError(null);
41
+ try {
42
+ const data = await fetchPostsPage(items.length, controller.signal);
43
+ setItems((prev) => [...prev, ...data.posts.map(normalizePost)]);
44
+ setTotal(data.total);
45
+ }
46
+ catch (err) {
47
+ if (!controller.signal.aborted) {
48
+ setError(err instanceof Error ? err.message : "Failed to load more posts");
49
+ }
50
+ }
51
+ finally {
52
+ if (!controller.signal.aborted)
53
+ setIsLoading(false);
54
+ }
55
+ }, [items.length, total]);
56
+ React.useEffect(() => {
57
+ loadMore();
58
+ // eslint-disable-next-line react-hooks/exhaustive-deps
59
+ }, []);
60
+ React.useEffect(() => {
61
+ return () => {
62
+ abortRef.current?.abort();
63
+ };
64
+ }, []);
65
+ const { sentinelRef } = useInfiniteScroll({
66
+ onLoadMore: loadMore,
67
+ isLoading,
68
+ enabled: hasMore,
69
+ root: containerRef,
70
+ rootMargin: "400px",
71
+ });
72
+ return (_jsxs("div", { children: [error && (_jsxs("div", { style: { padding: 8, color: "#b91c1c", fontSize: 13 }, children: [error, " \u2014", " ", _jsx("button", { onClick: () => loadMore(), style: { textDecoration: "underline" }, children: "retry" })] })), _jsx(VirtualList, { ref: containerRef, items: items, height: 600, width: "100%", estimatedItemSize: 140, itemKey: (_, item) => item.id, itemStyle: {
73
+ display: "flex",
74
+ flexDirection: "column",
75
+ gap: 6,
76
+ padding: "14px 16px",
77
+ borderBottom: "1px solid #eee",
78
+ }, renderItem: ({ item }) => (_jsxs(_Fragment, { children: [_jsx("div", { style: { fontWeight: 600, fontSize: 15 }, children: item.title }), _jsx("p", { style: { margin: 0, color: "#555", lineHeight: 1.5 }, children: item.body }), _jsx("div", { style: { display: "flex", gap: 6, flexWrap: "wrap", marginTop: 4 }, children: item.tags.map((tag) => (_jsxs("span", { style: {
79
+ fontSize: 12,
80
+ padding: "2px 8px",
81
+ borderRadius: 999,
82
+ background: "#f1f3f5",
83
+ color: "#495057",
84
+ }, children: ["#", tag] }, tag))) }), _jsxs("div", { style: { display: "flex", gap: 16, fontSize: 12, color: "#888", marginTop: 4 }, children: [_jsxs("span", { children: ["\uD83D\uDC4D ", item.likes] }), _jsxs("span", { children: ["\uD83D\uDC4E ", item.dislikes] }), _jsxs("span", { children: ["\uD83D\uDC41 ", item.views.toLocaleString(), " views"] })] })] })),
85
+ // sentinel is now ALWAYS mounted, independent of virtualization -
86
+ // this is the actual fix, not the renderItem branch above
87
+ footer: hasMore ? (_jsx("div", { ref: sentinelRef, style: { height: 1, width: "100%" } })) : null }), _jsx("div", { style: { textAlign: "center", padding: 12, color: "#888", fontSize: 13 }, children: isLoading
88
+ ? "Loading more…"
89
+ : hasMore
90
+ ? `Loaded ${items.length} of ${total ?? "…"} posts`
91
+ : `That's everything (${items.length} posts)` })] }));
92
+ }
93
+ //# sourceMappingURL=InfiniteScrollLists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InfiniteScrollLists.js","sourceRoot":"","sources":["../../src/examples/InfiniteScrollLists.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function MasonryGridExample(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=MasonaryGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MasonaryGrid.d.ts","sourceRoot":"","sources":["../../src/examples/MasonaryGrid.tsx"],"names":[],"mappings":"AAoDA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CAiDzC"}
@@ -0,0 +1,36 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { VirtualGrid } from "../components/VirtualGrid";
4
+ /**
5
+ * Plain data generator - NOT a component or hook, so it must not call
6
+ * useState/useEffect/etc. (that was the bug in the previous version:
7
+ * a bare `[images] = useState(...)` inside a regular function violates
8
+ * the Rules of Hooks and silently breaks - hooks only run inside a
9
+ * component body or another hook).
10
+ */
11
+ function makePhotos(startId, count) {
12
+ return Array.from({ length: count }, (_, i) => {
13
+ const id = startId + i;
14
+ // deterministic pseudo-random height per id, stable across re-renders -
15
+ // matches picsum's own {width}/{height} path so the requested image
16
+ // dimensions always equal the space we've reserved for it
17
+ const height = 220 + (id % 6) * 60;
18
+ return {
19
+ id,
20
+ url: `https://picsum.photos/500/${height}?random=${id}`,
21
+ title: `Beautiful Image ${id + 1}`,
22
+ height,
23
+ };
24
+ });
25
+ }
26
+ export default function MasonryGridExample() {
27
+ const [photos, setPhotos] = React.useState(() => makePhotos(0, 200));
28
+ const rowHeightForIndex = React.useCallback((index) => photos[index]?.height ?? 220, [photos]);
29
+ return (_jsxs("div", { children: [_jsx("div", { style: { marginBottom: 8, display: "flex", gap: 8, alignItems: "center" }, children: _jsxs("button", { onClick: () => setPhotos((prev) => [...prev, ...makePhotos(prev.length, 20)]), children: ["Load 20 more (", photos.length, " total) - watch this stay fast even at 50k+"] }) }), _jsx(VirtualGrid, { items: photos, layout: "masonry", columnCount: 5, rowHeight: rowHeightForIndex, gap: 12, height: 700, width: "100%", overscan: 6, itemKey: (_, item) => item.id, itemStyle: { borderRadius: 8, overflow: "hidden", background: "#eee" }, renderItem: ({ item }) => (_jsx("img", { src: item.url, alt: item.title, loading: "lazy", width: 500, height: item.height, style: {
30
+ width: "100%",
31
+ height: "100%",
32
+ objectFit: "cover",
33
+ display: "block",
34
+ } })) })] }));
35
+ }
36
+ //# sourceMappingURL=MasonaryGrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MasonaryGrid.js","sourceRoot":"","sources":["../../src/examples/MasonaryGrid.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AA4BxD;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,OAAe,EAAE,KAAa;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,EAAE,GAAG,OAAO,GAAG,CAAC,CAAC;QACvB,wEAAwE;QACxE,oEAAoE;QACpE,0DAA0D;QAC1D,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACnC,OAAO;YACH,EAAE;YACF,GAAG,EAAE,6BAA6B,MAAM,WAAW,EAAE,EAAE;YACvD,KAAK,EAAE,mBAAmB,EAAE,GAAG,CAAC,EAAE;YAClC,MAAM;SACT,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,kBAAkB;IACtC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAEpF,MAAM,iBAAiB,GAAG,KAAK,CAAC,WAAW,CACvC,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,GAAG,EAC/C,CAAC,MAAM,CAAC,CACX,CAAC;IAEF,OAAO,CACH,0BACI,cAAK,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,YAC1E,kBACI,OAAO,EAAE,GAAG,EAAE,CACV,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,+BAGnD,MAAM,CAAC,MAAM,mDACvB,GACP,EAEN,KAAC,WAAW,IACR,KAAK,EAAE,MAAM,EACb,MAAM,EAAC,SAAS,EAChB,WAAW,EAAE,CAAC,EACd,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,EAAE,EACP,MAAM,EAAE,GAAG,EACX,KAAK,EAAC,MAAM,EACZ,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAC7B,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,EACtE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACtB,cACI,GAAG,EAAE,IAAI,CAAC,GAAG,EACb,GAAG,EAAE,IAAI,CAAC,KAAK,EACf,OAAO,EAAC,MAAM,EACd,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,KAAK,EAAE;wBACH,KAAK,EAAE,MAAM;wBACb,MAAM,EAAE,MAAM;wBACd,SAAS,EAAE,OAAO;wBAClB,OAAO,EAAE,OAAO;qBACnB,GACH,CACL,GACH,IACA,CACT,CAAC;AACN,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function PerfHarnessExample(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=PerfHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PerfHarness.d.ts","sourceRoot":"","sources":["../../src/examples/PerfHarness.tsx"],"names":[],"mappings":"AAkHA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CAmGzC"}