vlist 2.0.0 → 2.0.2

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 (91) hide show
  1. package/README.github.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/core/dom.d.ts +1 -1
  4. package/dist/core/index.d.ts +1 -1
  5. package/dist/core/pipeline.d.ts +2 -2
  6. package/dist/core/scroll.d.ts +1 -1
  7. package/dist/core/types.d.ts +7 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +1 -28
  10. package/dist/internals.js +1 -60
  11. package/dist/plugins/scrollbar/controller.d.ts +3 -3
  12. package/dist/plugins/scrollbar/scrollbar.d.ts +2 -2
  13. package/dist/rendering/renderer.d.ts +2 -2
  14. package/dist/rendering/viewport.d.ts +1 -1
  15. package/dist/size.json +1 -1
  16. package/dist/types.d.ts +1 -1
  17. package/package.json +1 -1
  18. package/dist/constants.js +0 -83
  19. package/dist/core/create.js +0 -740
  20. package/dist/core/dom.js +0 -47
  21. package/dist/core/hooks.js +0 -67
  22. package/dist/core/index.js +0 -13
  23. package/dist/core/pipeline.js +0 -307
  24. package/dist/core/pool.js +0 -42
  25. package/dist/core/scroll.js +0 -137
  26. package/dist/core/sizes.js +0 -6
  27. package/dist/core/state.js +0 -56
  28. package/dist/core/types.js +0 -7
  29. package/dist/core/velocity.js +0 -33
  30. package/dist/events/emitter.js +0 -60
  31. package/dist/events/index.js +0 -6
  32. package/dist/plugins/a11y/index.js +0 -1
  33. package/dist/plugins/a11y/plugin.js +0 -259
  34. package/dist/plugins/async/index.js +0 -12
  35. package/dist/plugins/async/manager.js +0 -568
  36. package/dist/plugins/async/placeholder.js +0 -154
  37. package/dist/plugins/async/plugin.js +0 -311
  38. package/dist/plugins/async/sparse.js +0 -540
  39. package/dist/plugins/autosize/index.js +0 -4
  40. package/dist/plugins/autosize/plugin.js +0 -185
  41. package/dist/plugins/grid/index.js +0 -5
  42. package/dist/plugins/grid/layout.js +0 -275
  43. package/dist/plugins/grid/plugin.js +0 -347
  44. package/dist/plugins/grid/renderer.js +0 -525
  45. package/dist/plugins/grid/types.js +0 -11
  46. package/dist/plugins/groups/async-bridge.js +0 -246
  47. package/dist/plugins/groups/index.js +0 -13
  48. package/dist/plugins/groups/layout.js +0 -294
  49. package/dist/plugins/groups/plugin.js +0 -571
  50. package/dist/plugins/groups/sticky.js +0 -255
  51. package/dist/plugins/groups/types.js +0 -12
  52. package/dist/plugins/masonry/index.js +0 -6
  53. package/dist/plugins/masonry/layout.js +0 -261
  54. package/dist/plugins/masonry/plugin.js +0 -381
  55. package/dist/plugins/masonry/renderer.js +0 -354
  56. package/dist/plugins/masonry/types.js +0 -9
  57. package/dist/plugins/page/index.js +0 -5
  58. package/dist/plugins/page/plugin.js +0 -166
  59. package/dist/plugins/scale/index.js +0 -4
  60. package/dist/plugins/scale/plugin.js +0 -507
  61. package/dist/plugins/scrollbar/controller.js +0 -574
  62. package/dist/plugins/scrollbar/index.js +0 -6
  63. package/dist/plugins/scrollbar/plugin.js +0 -93
  64. package/dist/plugins/scrollbar/scrollbar.js +0 -556
  65. package/dist/plugins/selection/index.js +0 -7
  66. package/dist/plugins/selection/plugin.js +0 -601
  67. package/dist/plugins/selection/state.js +0 -332
  68. package/dist/plugins/snapshots/index.js +0 -5
  69. package/dist/plugins/snapshots/plugin.js +0 -301
  70. package/dist/plugins/sortable/index.js +0 -6
  71. package/dist/plugins/sortable/plugin.js +0 -753
  72. package/dist/plugins/table/header.js +0 -501
  73. package/dist/plugins/table/index.js +0 -12
  74. package/dist/plugins/table/layout.js +0 -211
  75. package/dist/plugins/table/plugin.js +0 -391
  76. package/dist/plugins/table/renderer.js +0 -625
  77. package/dist/plugins/table/types.js +0 -12
  78. package/dist/plugins/transition/index.js +0 -5
  79. package/dist/plugins/transition/plugin.js +0 -405
  80. package/dist/rendering/aria.js +0 -23
  81. package/dist/rendering/index.js +0 -18
  82. package/dist/rendering/measured.js +0 -98
  83. package/dist/rendering/renderer.js +0 -586
  84. package/dist/rendering/scale.js +0 -267
  85. package/dist/rendering/scroll.js +0 -71
  86. package/dist/rendering/sizes.js +0 -193
  87. package/dist/rendering/sort.js +0 -65
  88. package/dist/rendering/viewport.js +0 -268
  89. package/dist/types.js +0 -5
  90. package/dist/utils/padding.js +0 -49
  91. package/dist/utils/stats.js +0 -124
@@ -1,255 +0,0 @@
1
- /**
2
- * vlist - Sticky Header
3
- *
4
- * Manages a floating header that sticks to the viewport edge and transitions
5
- * smoothly when the next group's header approaches (push-out effect).
6
- *
7
- * Two permanent slot elements are recycled — content is swapped via a
8
- * caller-provided `renderInto` callback, keeping the sticky header
9
- * template-agnostic (same pattern as item rendering).
10
- *
11
- * Header offsets and sizes are pre-cached into flat arrays on rebuild,
12
- * keeping the per-tick scroll handler free of function calls.
13
- *
14
- * .vlist-sticky-header (position: relative, overflow: hidden)
15
- * ├── .sticky-group (active slot — translated during push)
16
- * └── .sticky-group (standby slot — translated during push)
17
- */
18
- /**
19
- * Create the sticky header container element upfront (before data arrives)
20
- * so the DOM structure is stable and doesn't cause a visual shift.
21
- */
22
- export const createStickyContainer = (root, classPrefix, horizontal, headerHeight, stickyOffset = 0) => {
23
- const mainProp = horizontal ? "width" : "height";
24
- const container = document.createElement("div");
25
- container.className = `${classPrefix}-sticky-header`;
26
- container.setAttribute("role", "presentation");
27
- container.setAttribute("aria-hidden", "true");
28
- container.style.cssText =
29
- `position:relative;z-index:5;pointer-events:none;overflow:hidden;` +
30
- (horizontal
31
- ? `top:0;bottom:0;left:${stickyOffset || 0}px`
32
- : `top:${stickyOffset || 0}px`);
33
- container.style[mainProp] = `${headerHeight}px`;
34
- root.insertBefore(container, root.firstChild);
35
- return container;
36
- };
37
- export const createStickyHeader = (root, layout, sizeCache, renderInto, classPrefix, horizontal = false, stickyOffset = 0, getCompressionRatio, existingContainer) => {
38
- // Orientation helpers — resolved once
39
- const mainProp = horizontal ? "width" : "height";
40
- const crossProp = horizontal ? "height" : "width";
41
- const translateAxis = horizontal ? "X" : "Y";
42
- const setMain = (el, px) => {
43
- el.style[mainProp] = `${px}px`;
44
- };
45
- // DOM setup — reuse pre-created container if provided
46
- const container = existingContainer ?? createStickyContainer(root, classPrefix, horizontal, 0, stickyOffset);
47
- const mkSlot = () => {
48
- const s = document.createElement("div");
49
- s.className = "sticky-group";
50
- s.style.position = "absolute";
51
- s.style.willChange = "transform";
52
- s.style[crossProp] = "100%";
53
- return s;
54
- };
55
- const slotA = mkSlot();
56
- const slotB = mkSlot();
57
- container.append(slotA, slotB);
58
- // Slot references — swap roles after each completed transition
59
- let active = slotA;
60
- let standby = slotB;
61
- // Pre-cached arrays — rebuilt in cacheGroups(), read on every scroll tick
62
- // offsets & vSizes are in virtual (scroll) space for binary search / push detection.
63
- // sizes are in actual pixels for DOM rendering.
64
- let groups = layout.groups;
65
- let offsets = [];
66
- let sizes = [];
67
- let vSizes = [];
68
- let groupCount = 0;
69
- const cacheGroups = () => {
70
- groups = layout.groups;
71
- groupCount = groups.length;
72
- offsets = new Array(groupCount);
73
- sizes = new Array(groupCount);
74
- vSizes = new Array(groupCount);
75
- const ratio = getCompressionRatio ? getCompressionRatio() : 1;
76
- for (let i = 0; i < groupCount; i++) {
77
- offsets[i] = sizeCache.getOffset(groups[i].headerLayoutIndex) * ratio;
78
- sizes[i] = layout.getHeaderHeight(i);
79
- vSizes[i] = sizes[i] * ratio;
80
- }
81
- };
82
- cacheGroups();
83
- // Mutable state
84
- let curGroup = -1;
85
- let curSize = 0;
86
- let curVSize = 0;
87
- let nxtGroup = -1;
88
- let visible = false;
89
- let lastOffset = 0;
90
- let transitioning = false;
91
- // Slot content — delegate to caller-provided renderInto
92
- const fill = (slot, gi) => {
93
- renderInto(slot, gi);
94
- const sz = sizes[gi];
95
- setMain(slot, sz);
96
- return sz;
97
- };
98
- const clear = (slot) => {
99
- slot.replaceChildren();
100
- slot.style.transform = "";
101
- };
102
- // Current group
103
- const setCurrent = (gi) => {
104
- if (gi === curGroup)
105
- return;
106
- curGroup = gi;
107
- curSize = 0;
108
- curVSize = 0;
109
- if (gi < 0 || gi >= groupCount) {
110
- clear(active);
111
- return;
112
- }
113
- curSize = fill(active, gi);
114
- curVSize = vSizes[gi];
115
- setMain(container, curSize);
116
- active.style.transform = "";
117
- };
118
- // Push transition
119
- const applyPush = (offset) => {
120
- if (offset === lastOffset)
121
- return;
122
- lastOffset = offset;
123
- const r = Math.round(offset);
124
- active.style.transform = `translate${translateAxis}(${r}px)`;
125
- standby.style.transform = `translate${translateAxis}(${r + curSize}px)`;
126
- };
127
- const resetTransforms = () => {
128
- lastOffset = 0;
129
- active.style.transform = "";
130
- standby.style.transform = "";
131
- };
132
- const complete = () => {
133
- if (!transitioning)
134
- return;
135
- const prev = active;
136
- active = standby;
137
- standby = prev;
138
- curGroup = nxtGroup;
139
- curSize = curGroup >= 0 ? sizes[curGroup] : 0;
140
- curVSize = curGroup >= 0 ? vSizes[curGroup] : 0;
141
- setMain(container, curSize);
142
- clear(standby);
143
- nxtGroup = -1;
144
- transitioning = false;
145
- resetTransforms();
146
- };
147
- const cancel = () => {
148
- if (!transitioning)
149
- return;
150
- clear(standby);
151
- nxtGroup = -1;
152
- transitioning = false;
153
- resetTransforms();
154
- };
155
- // Visibility — when a pre-created container is reused, use visibility
156
- // instead of display to preserve layout (the viewport is sized with
157
- // calc(100% - headerHeight) and relies on the container occupying space).
158
- const preserveLayout = !!existingContainer;
159
- const show = () => {
160
- if (visible)
161
- return;
162
- visible = true;
163
- if (preserveLayout)
164
- container.style.visibility = "";
165
- else
166
- container.style.display = "";
167
- };
168
- const hide = () => {
169
- if (!visible)
170
- return;
171
- visible = false;
172
- if (preserveLayout)
173
- container.style.visibility = "hidden";
174
- else
175
- container.style.display = "none";
176
- clear(active);
177
- curGroup = -1;
178
- curSize = 0;
179
- curVSize = 0;
180
- cancel();
181
- };
182
- // Scroll handler — hot path
183
- const update = (scroll) => {
184
- if (groupCount === 0) {
185
- hide();
186
- return;
187
- }
188
- if (scroll < offsets[0]) {
189
- hide();
190
- return;
191
- }
192
- // Binary search — pure array reads, no function calls
193
- // offsets and vSizes are in virtual (scroll) space
194
- let lo = 0, hi = groupCount - 1;
195
- while (lo < hi) {
196
- const mid = (lo + hi + 1) >>> 1;
197
- if (offsets[mid] + vSizes[mid] <= scroll)
198
- lo = mid;
199
- else
200
- hi = mid - 1;
201
- }
202
- if (!visible)
203
- show();
204
- setCurrent(lo);
205
- // Push transition check — dist is in virtual space,
206
- // scaled to actual pixels for DOM transforms
207
- const nxt = lo + 1;
208
- if (nxt < groupCount) {
209
- const dist = offsets[nxt] - scroll;
210
- if (dist <= 0 && dist > -curVSize) {
211
- if (nxtGroup !== nxt || !transitioning) {
212
- nxtGroup = nxt;
213
- fill(standby, nxt);
214
- transitioning = true;
215
- }
216
- const pxDist = curVSize > 0 ? (dist / curVSize) * curSize : dist;
217
- applyPush(pxDist);
218
- }
219
- else if (dist <= -curVSize) {
220
- if (transitioning)
221
- complete();
222
- }
223
- else {
224
- if (transitioning)
225
- cancel();
226
- }
227
- }
228
- else {
229
- if (transitioning)
230
- cancel();
231
- }
232
- };
233
- const refresh = () => {
234
- cacheGroups();
235
- const prev = curGroup;
236
- curGroup = -1;
237
- curSize = 0;
238
- curVSize = 0;
239
- if (prev >= 0)
240
- setCurrent(prev);
241
- };
242
- const destroy = () => {
243
- container.remove();
244
- curGroup = -1;
245
- curSize = 0;
246
- curVSize = 0;
247
- nxtGroup = -1;
248
- visible = false;
249
- transitioning = false;
250
- };
251
- if (!existingContainer) {
252
- container.style.display = "none";
253
- }
254
- return { update, refresh, show, hide, destroy };
255
- };
@@ -1,12 +0,0 @@
1
- /**
2
- * vlist - Group Types
3
- * Types for sticky headers and grouped lists
4
- */
5
- /**
6
- * Type guard: check if an item is a group header pseudo-item
7
- */
8
- export const isGroupHeader = (item) => {
9
- return (item !== null &&
10
- typeof item === "object" &&
11
- item.__groupHeader === true);
12
- };
@@ -1,6 +0,0 @@
1
- /**
2
- * vlist v2 — Masonry Plugin
3
- */
4
- export { masonry } from "./plugin";
5
- export { createMasonryLayout } from "./layout";
6
- export { createMasonryRenderer } from "./renderer";
@@ -1,261 +0,0 @@
1
- /**
2
- * vlist - Masonry Layout
3
- * Shortest-lane placement algorithm for masonry/Pinterest-style layouts.
4
- *
5
- * Algorithm:
6
- * 1. Track the size (height/width) of each lane (column/row)
7
- * 2. For each item:
8
- * - Find the shortest lane
9
- * - Place item at the end of that lane
10
- * - Update lane size
11
- * 3. Cache all item positions for O(1) lookup during rendering
12
- *
13
- * Complexity:
14
- * - Layout calculation: O(n) where n = total items
15
- * - Position lookup: O(1) using cached placements
16
- * - Visibility check: O(k * log(n/k)) using per-lane binary search
17
- * where k = columns, n = total items
18
- */
19
- // =============================================================================
20
- // Factory
21
- // =============================================================================
22
- /**
23
- * Create a MasonryLayout instance.
24
- *
25
- * @param config - Masonry configuration (columns, gap, containerSize)
26
- * @returns MasonryLayout with placement algorithm
27
- */
28
- export const createMasonryLayout = (config) => {
29
- let columns = Math.max(1, Math.floor(config.columns));
30
- let gap = config.gap ?? 0;
31
- let containerSize = config.containerSize;
32
- // ── Cached derived values ──
33
- // Recomputed when columns, gap, or containerSize change.
34
- let crossAxisSize = 0;
35
- let laneOffsets = [];
36
- const recomputeDerived = () => {
37
- const totalGap = (columns - 1) * gap;
38
- crossAxisSize = Math.max(0, (containerSize - totalGap) / columns);
39
- laneOffsets = new Array(columns);
40
- const stride = crossAxisSize + gap;
41
- for (let i = 0; i < columns; i++) {
42
- laneOffsets[i] = i * stride;
43
- }
44
- };
45
- // Initial computation
46
- recomputeDerived();
47
- // ── Per-lane placement indices (for binary search in getVisibleItems) ──
48
- // Built by calculateLayout, consumed by getVisibleItems.
49
- let lanePlacements = [];
50
- // ── Cached total size from last calculateLayout ──
51
- let cachedTotalSize = 0;
52
- // ── Pooled visible-items array ──
53
- // Reused by getVisibleItems to avoid allocation per scroll frame.
54
- // Single-consumer contract: caller must finish reading before the next call.
55
- let visiblePool = [];
56
- /**
57
- * Calculate layout for all items using shortest-lane algorithm.
58
- * Returns array of item placements with cached positions.
59
- *
60
- * Also caches:
61
- * - Total size (tallest lane) — retrievable via getTotalSize([])
62
- * - Per-lane placement index lists — used by getVisibleItems for binary search
63
- */
64
- const calculateLayout = (totalItems, getSizeForItem) => {
65
- if (totalItems <= 0) {
66
- cachedTotalSize = 0;
67
- lanePlacements = [];
68
- return [];
69
- }
70
- // Initialize lane sizes (accumulated height/width for each column/row)
71
- const laneSizes = new Array(columns).fill(0);
72
- // Per-lane placement indices (for binary search later)
73
- const lanes = new Array(columns);
74
- for (let c = 0; c < columns; c++) {
75
- lanes[c] = [];
76
- }
77
- // Array to store all item placements
78
- const placements = new Array(totalItems);
79
- // Place each item in the shortest lane
80
- for (let i = 0; i < totalItems; i++) {
81
- // Find shortest lane
82
- let lane = 0;
83
- let shortestSize = laneSizes[0];
84
- for (let c = 1; c < columns; c++) {
85
- const currentSize = laneSizes[c];
86
- if (currentSize < shortestSize) {
87
- shortestSize = currentSize;
88
- lane = c;
89
- }
90
- }
91
- // Get item size in main axis
92
- const itemSize = getSizeForItem(i);
93
- // Position: use precomputed lane offset, current lane accumulator
94
- const mainOffset = laneSizes[lane];
95
- // Create placement (flat structure — no nested position object)
96
- placements[i] = {
97
- index: i,
98
- x: laneOffsets[lane],
99
- y: mainOffset,
100
- lane,
101
- size: itemSize,
102
- crossSize: crossAxisSize,
103
- };
104
- // Track placement index per lane
105
- lanes[lane].push(i);
106
- // Update lane size (add item size + gap)
107
- laneSizes[lane] = mainOffset + itemSize + gap;
108
- }
109
- // Cache per-lane placements for binary search
110
- lanePlacements = lanes;
111
- // Cache total size (max lane extent, minus trailing gap)
112
- let maxExtent = 0;
113
- for (let c = 0; c < columns; c++) {
114
- const laneSize = laneSizes[c];
115
- // laneSizes includes a trailing gap after the last item — subtract it
116
- // unless the lane is empty (size === 0)
117
- const extent = laneSize > 0 ? laneSize - gap : 0;
118
- if (extent > maxExtent)
119
- maxExtent = extent;
120
- }
121
- cachedTotalSize = maxExtent;
122
- return placements;
123
- };
124
- /**
125
- * Get total size in main axis (tallest column height or widest row width).
126
- * This determines the total scroll size.
127
- *
128
- * When called with the result of calculateLayout, returns the cached value
129
- * computed during layout (O(1)). Falls back to recomputation for external
130
- * placement arrays.
131
- */
132
- const getTotalSize = (placements) => {
133
- // Fast path: return cached value when called with the layout result
134
- // (the common case — feature.ts always passes cachedPlacements)
135
- if (placements.length === 0)
136
- return cachedTotalSize;
137
- // If the first placement matches our cached data, use cached total
138
- // This avoids the O(n) scan in the normal flow
139
- if (cachedTotalSize)
140
- return cachedTotalSize;
141
- // Fallback: recompute (only for externally-constructed placements)
142
- const laneSizes = new Array(columns).fill(0);
143
- for (const placement of placements) {
144
- const extent = placement.y + placement.size;
145
- const currentSize = laneSizes[placement.lane];
146
- if (extent > currentSize) {
147
- laneSizes[placement.lane] = extent;
148
- }
149
- }
150
- let max = 0;
151
- for (let c = 0; c < columns; c++) {
152
- if (laneSizes[c] > max)
153
- max = laneSizes[c];
154
- }
155
- return max;
156
- };
157
- /**
158
- * Get items visible within the given main-axis range.
159
- * Uses per-lane binary search for O(k * log(n/k)) performance
160
- * where k = columns and n = total items.
161
- *
162
- * Within each lane, items are sorted by Y position (guaranteed by the
163
- * shortest-lane algorithm). We binary search each lane to find the first
164
- * item whose bottom edge enters the viewport and the last item whose
165
- * top edge is before the viewport end.
166
- */
167
- const getVisibleItems = (placements, mainAxisStart, mainAxisEnd) => {
168
- if (placements.length === 0 || mainAxisEnd <= mainAxisStart) {
169
- visiblePool.length = 0;
170
- return visiblePool;
171
- }
172
- // If per-lane data isn't available (external placements), fall back to linear scan
173
- if (lanePlacements.length === 0 || lanePlacements.length !== columns) {
174
- return getVisibleItemsLinear(placements, mainAxisStart, mainAxisEnd);
175
- }
176
- // Reuse pooled array — reset length to 0 (no allocation)
177
- visiblePool.length = 0;
178
- for (let c = 0; c < columns; c++) {
179
- const laneIndices = lanePlacements[c];
180
- const laneLen = laneIndices.length;
181
- if (!laneLen)
182
- continue;
183
- // Binary search: find first item in this lane where itemEnd > mainAxisStart
184
- // i.e., the item's bottom edge is past the viewport top
185
- let lo = 0;
186
- let hi = laneLen;
187
- while (lo < hi) {
188
- const mid = (lo + hi) >>> 1;
189
- const p = placements[laneIndices[mid]];
190
- if (p.y + p.size <= mainAxisStart) {
191
- lo = mid + 1;
192
- }
193
- else {
194
- hi = mid;
195
- }
196
- }
197
- // Collect visible items from this lane starting at `lo`
198
- for (let j = lo; j < laneLen; j++) {
199
- const p = placements[laneIndices[j]];
200
- // Once the item's top edge is past the viewport bottom, stop
201
- if (p.y >= mainAxisEnd)
202
- break;
203
- visiblePool.push(p);
204
- }
205
- }
206
- return visiblePool;
207
- };
208
- /**
209
- * Linear fallback for getVisibleItems when per-lane data is unavailable.
210
- * Used only for externally-constructed placement arrays.
211
- */
212
- const getVisibleItemsLinear = (placements, mainAxisStart, mainAxisEnd) => {
213
- visiblePool.length = 0;
214
- for (const placement of placements) {
215
- const itemEnd = placement.y + placement.size;
216
- if (itemEnd > mainAxisStart && placement.y < mainAxisEnd) {
217
- visiblePool.push(placement);
218
- }
219
- }
220
- return visiblePool;
221
- };
222
- /**
223
- * Update masonry configuration without recreating the layout.
224
- */
225
- const updateConfig = (newConfig) => {
226
- let changed = false;
227
- if (newConfig.columns !== undefined) {
228
- const newCols = Math.max(1, Math.floor(newConfig.columns));
229
- if (newCols !== columns) {
230
- columns = newCols;
231
- changed = true;
232
- }
233
- }
234
- if (newConfig.gap !== undefined && newConfig.gap !== gap) {
235
- gap = newConfig.gap;
236
- changed = true;
237
- }
238
- if (newConfig.containerSize !== undefined && newConfig.containerSize !== containerSize) {
239
- containerSize = newConfig.containerSize;
240
- changed = true;
241
- }
242
- if (changed) {
243
- recomputeDerived();
244
- }
245
- };
246
- return {
247
- get columns() {
248
- return columns;
249
- },
250
- get gap() {
251
- return gap;
252
- },
253
- get containerSize() {
254
- return containerSize;
255
- },
256
- update: updateConfig,
257
- calculateLayout,
258
- getTotalSize,
259
- getVisibleItems,
260
- };
261
- };