├── .gitignore
├── lib
├── VariableSizeGrid.svelte
├── VariableSizeList.svelte
├── FixedSizeList.svelte
├── FixedSizeGrid.svelte
├── FixedSizeGridSSR.svelte
├── FixedSizeListSSR.svelte
├── VariableSizeGridSSR.svelte
└── VariableSizeListSSR.svelte
├── src
├── shallowDiffers.js
├── styleString.js
├── shouldComponentUpdate.js
├── areEqual.js
├── index.js
├── timer.js
├── domHelpers.js
├── FixedSizeList.js
├── FixedSizeGrid.js
├── VariableSizeList.js
├── VariableSizeGrid.js
├── ListComponent.svelte
├── GridComponent.svelte
└── index.d.ts
├── LICENSE.md
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/lib/VariableSizeGrid.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
--------------------------------------------------------------------------------
/lib/VariableSizeList.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
--------------------------------------------------------------------------------
/lib/FixedSizeList.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/lib/FixedSizeGrid.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/shallowDiffers.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 |
4 |
5 | // Pulled from react-compat
6 | // https://github.com/developit/preact-compat/blob/7c5de00e7c85e2ffd011bf3af02899b63f699d3a/src/index.js#L349
7 | export default function shallowDiffers(prev, next) {
8 | for (let attribute in prev) {
9 | if (!(attribute in next)) {
10 | return true;
11 | }
12 | }
13 | for (let attribute in next) {
14 | if (prev[attribute] !== next[attribute]) {
15 | return true;
16 | }
17 | }
18 | return false;
19 | }
20 |
--------------------------------------------------------------------------------
/src/styleString.js:
--------------------------------------------------------------------------------
1 | export const styleString = (s) => (s.position !== undefined ? "position: " + s.position + ";" : "") +
2 | (s.left !== undefined ? "left: " + s.left + "px;" : "") +
3 | (s.right !== undefined ? "right: " + s.right + "px;" : "") +
4 | (s.top !== undefined ? "top: " + s.top + "px;" : "") +
5 | (s.height !== undefined ?
6 | "height: " + (typeof s.height === "number" ? s.height + "px" : s.height) + ";"
7 | : "") +
8 | (s.width !== undefined ?
9 | "width: " + (typeof s.width === "number" ? s.width + "px" : s.width) + ";"
10 | : "");
--------------------------------------------------------------------------------
/src/shouldComponentUpdate.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 |
4 | import areEqual from './areEqual';
5 | import shallowDiffers from './shallowDiffers';
6 |
7 | // Custom shouldComponentUpdate for class components.
8 | // It knows to compare individual style props and ignore the wrapper object.
9 | // See https://reactjs.org/docs/react-component.html#shouldcomponentupdate
10 | export default function shouldComponentUpdate(
11 | nextProps,
12 | nextState
13 | ) {
14 | return (
15 | !areEqual(this.props, nextProps) || shallowDiffers(this.state, nextState)
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/areEqual.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 | import shallowDiffers from './shallowDiffers';
4 |
5 | // Custom comparison function for React.memo().
6 | // It knows to compare individual style props and ignore the wrapper object.
7 | // See https://reactjs.org/docs/react-api.html#reactmemo
8 | export default function areEqual(
9 | prevProps,
10 | nextProps
11 | ) {
12 | const { style: prevStyle, ...prevRest } = prevProps;
13 | const { style: nextStyle, ...nextRest } = nextProps;
14 |
15 | return (
16 | !shallowDiffers(prevStyle, nextStyle) && !shallowDiffers(prevRest, nextRest)
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/lib/FixedSizeGridSSR.svelte:
--------------------------------------------------------------------------------
1 |
16 | {#if m}
17 |
18 | {/if}
--------------------------------------------------------------------------------
/lib/FixedSizeListSSR.svelte:
--------------------------------------------------------------------------------
1 |
16 | {#if m}
17 |
18 | {/if}
--------------------------------------------------------------------------------
/lib/VariableSizeGridSSR.svelte:
--------------------------------------------------------------------------------
1 |
16 | {#if m}
17 |
18 | {/if}
--------------------------------------------------------------------------------
/lib/VariableSizeListSSR.svelte:
--------------------------------------------------------------------------------
1 |
16 | {#if m}
17 |
18 | {/if}
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 |
4 |
5 | export { default as VariableSizeGrid } from '../lib/VariableSizeGrid.svelte';
6 | export { default as VariableSizeList } from '../lib/VariableSizeList.svelte';
7 | export { default as FixedSizeGrid } from '../lib/FixedSizeGrid.svelte';
8 | export { default as FixedSizeList } from '../lib/FixedSizeList.svelte';
9 | export { default as VariableSizeGridSSR } from '../lib/VariableSizeGridSSR.svelte';
10 | export { default as VariableSizeListSSR } from '../lib/VariableSizeListSSR.svelte';
11 | export { default as FixedSizeGridSSR } from '../lib/FixedSizeGridSSR.svelte';
12 | export { default as FixedSizeListSSR } from '../lib/FixedSizeListSSR.svelte';
13 |
14 | export { default as areEqual } from './areEqual';
15 | export { default as shouldComponentUpdate } from './shouldComponentUpdate';
16 | export {styleString} from './styleString';
17 |
--------------------------------------------------------------------------------
/src/timer.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 |
4 |
5 | // Animation frame based implementation of setTimeout.
6 | // Inspired by Joe Lambert, https://gist.github.com/joelambert/1002116#file-requesttimeout-js
7 |
8 | const hasNativePerformanceNow =
9 | typeof performance === 'object' && typeof performance.now === 'function';
10 |
11 | const now = hasNativePerformanceNow
12 | ? () => performance.now()
13 | : () => Date.now();
14 |
15 |
16 | export function cancelTimeout(timeoutID) {
17 | cancelAnimationFrame(timeoutID.id);
18 | }
19 |
20 | export function requestTimeout(callback, delay) {
21 | const start = now();
22 |
23 | function tick() {
24 | if (now() - start >= delay) {
25 | callback.call(null);
26 | } else {
27 | timeoutID.id = requestAnimationFrame(tick);
28 | }
29 | }
30 |
31 | const timeoutID = {
32 | id: requestAnimationFrame(tick),
33 | };
34 |
35 | return timeoutID;
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Michael Lucht
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-window",
3 | "version": "1.2.5",
4 | "description": "Svelte components for efficiently rendering large, scrollable lists and tabular data. Port of react-window to Svelte.",
5 | "main": "src/index.js",
6 | "module": "src/index.js",
7 | "svelte": "src/index.js",
8 | "types": "src/index.d.ts",
9 | "bundleDependencies": false,
10 | "contributors": [
11 | {
12 | "name": "Michael Lucht",
13 | "email": "micha-lmxt@gradientdescent.de",
14 | "url": "https://github.com/micha-lmxt/svelte-window"
15 | }
16 | ],
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/micha-lmxt/svelte-window.git"
20 | },
21 | "author": "micha-lmxt (https://gradientdescent.de)",
22 | "license": "MIT",
23 | "devDependencies": {
24 | "svelte": "^3.32.3"
25 | },
26 | "sideEffects": false,
27 | "type":"module",
28 | "keywords": [
29 | "svelte",
30 | "sveltejs",
31 | "react",
32 | "reactjs",
33 | "virtual",
34 | "window",
35 | "windowed",
36 | "list",
37 | "scrolling",
38 | "infinite",
39 | "virtualized",
40 | "table",
41 | "grid",
42 | "spreadsheet"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/src/domHelpers.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 | let size = -1;
4 |
5 | // This utility copied from "dom-helpers" package.
6 | export function getScrollbarSize(recalculate = false) {
7 | if (size === -1 || recalculate) {
8 | const div = document.createElement('div');
9 | const style = div.style;
10 | style.width = '50px';
11 | style.height = '50px';
12 | style.overflow = 'scroll';
13 |
14 | document.body.appendChild(div);
15 |
16 | size = div.offsetWidth - div.clientWidth;
17 |
18 | document.body.removeChild(div);
19 | }
20 |
21 | return size;
22 | }
23 |
24 | let cachedRTLResult = null;
25 |
26 | // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
27 | // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
28 | // Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.
29 | // The safest way to check this is to intentionally set a negative offset,
30 | // and then verify that the subsequent "scroll" event matches the negative offset.
31 | // If it does not match, then we can assume a non-standard RTL scroll implementation.
32 | export function getRTLOffsetType(recalculate = false) {
33 | if (cachedRTLResult === null || recalculate) {
34 | const outerDiv = document.createElement('div');
35 | const outerStyle = outerDiv.style;
36 | outerStyle.width = '50px';
37 | outerStyle.height = '50px';
38 | outerStyle.overflow = 'scroll';
39 | outerStyle.direction = 'rtl';
40 |
41 | const innerDiv = document.createElement('div');
42 | const innerStyle = innerDiv.style;
43 | innerStyle.width = '100px';
44 | innerStyle.height = '100px';
45 |
46 | outerDiv.appendChild(innerDiv);
47 |
48 | document.body.appendChild(outerDiv);
49 |
50 | if (outerDiv.scrollLeft > 0) {
51 | cachedRTLResult = 'positive-descending';
52 | } else {
53 | outerDiv.scrollLeft = 1;
54 | if (outerDiv.scrollLeft === 0) {
55 | cachedRTLResult = 'negative';
56 | } else {
57 | cachedRTLResult = 'positive-ascending';
58 | }
59 | }
60 |
61 | document.body.removeChild(outerDiv);
62 |
63 | return cachedRTLResult;
64 | }
65 |
66 | return cachedRTLResult;
67 | }
68 |
--------------------------------------------------------------------------------
/src/FixedSizeList.js:
--------------------------------------------------------------------------------
1 | // Ported from "react-window@1.8.6"
2 | // Copyright (c) 2018 Brian Vaughn
3 |
4 | const FixedSizeListSpecificProps = ({
5 | getItemOffset: ({ itemSize }, index) =>
6 | index * ((itemSize)),
7 |
8 | getItemSize: ({ itemSize }, index) =>
9 | ((itemSize)),
10 |
11 | getEstimatedTotalSize: ({ itemCount, itemSize }) =>
12 | ((itemSize)) * itemCount,
13 |
14 | getOffsetForIndexAndAlignment: (
15 | { direction, height, itemCount, itemSize, layout, width },
16 | index,
17 | align,
18 | scrollOffset
19 | ) => {
20 | // TODO Deprecate direction "horizontal"
21 | const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
22 | const size = (((isHorizontal ? width : height)));
23 | const lastItemOffset = Math.max(
24 | 0,
25 | itemCount * ((itemSize)) - size
26 | );
27 | const maxOffset = Math.min(
28 | lastItemOffset,
29 | index * ((itemSize))
30 | );
31 | const minOffset = Math.max(
32 | 0,
33 | index * ((itemSize)) - size + ((itemSize))
34 | );
35 |
36 | if (align === 'smart') {
37 | if (
38 | scrollOffset >= minOffset - size &&
39 | scrollOffset <= maxOffset + size
40 | ) {
41 | align = 'auto';
42 | } else {
43 | align = 'center';
44 | }
45 | }
46 |
47 | switch (align) {
48 | case 'start':
49 | return maxOffset;
50 | case 'end':
51 | return minOffset;
52 | case 'center': {
53 | // "Centered" offset is usually the average of the min and max.
54 | // But near the edges of the list, this doesn't hold true.
55 | const middleOffset = Math.round(
56 | minOffset + (maxOffset - minOffset) / 2
57 | );
58 | if (middleOffset < Math.ceil(size / 2)) {
59 | return 0; // near the beginning
60 | } else if (middleOffset > lastItemOffset + Math.floor(size / 2)) {
61 | return lastItemOffset; // near the end
62 | } else {
63 | return middleOffset;
64 | }
65 | }
66 | case 'auto':
67 | default:
68 | if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
69 | return scrollOffset;
70 | } else if (scrollOffset < minOffset) {
71 | return minOffset;
72 | } else {
73 | return maxOffset;
74 | }
75 | }
76 | },
77 |
78 | getStartIndexForOffset: (
79 | { itemCount, itemSize },
80 | offset
81 | ) =>
82 | Math.max(
83 | 0,
84 | Math.min(itemCount - 1, Math.floor(offset / ((itemSize))))
85 | ),
86 |
87 | getStopIndexForStartIndex: (
88 | { direction, height, itemCount, itemSize, layout, width },
89 | startIndex,
90 | scrollOffset
91 | ) => {
92 | // TODO Deprecate direction "horizontal"
93 | const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
94 | const offset = startIndex * ((itemSize));
95 | const size = (((isHorizontal ? width : height)));
96 | const numVisibleItems = Math.ceil(
97 | (size + scrollOffset - offset) / ((itemSize))
98 | );
99 | return Math.max(
100 | 0,
101 | Math.min(
102 | itemCount - 1,
103 | startIndex + numVisibleItems - 1 // -1 is because stop index is inclusive
104 | )
105 | );
106 | },
107 |
108 | initInstanceProps(props) {
109 | // Noop
110 | },
111 |
112 | shouldResetStyleCacheOnItemSizeChange: true,
113 |
114 | validateProps: ({ itemSize }) => {
115 | /*if (process.env.NODE_ENV !== 'production') {
116 | if (typeof itemSize !== 'number') {
117 | throw Error(
118 | 'An invalid "itemSize" prop has been specified. ' +
119 | 'Value should be a number. ' +
120 | `"${itemSize === null ? 'null' : typeof itemSize}" was specified.`
121 | );
122 | }
123 | }*/
124 | },
125 | });
126 |
127 | export default FixedSizeListSpecificProps;
128 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # svelte-window
2 |
3 | > Svelte components for efficiently rendering large, scrollable lists and tabular data. Port of react-window to Svelte.
4 |
5 | Svelte window works by only rendering *part* of a large data set (just enough to fill the viewport). This helps address some common performance bottlenecks:
6 | 1. It reduces the amount of work (and time) required to render the initial view and to process updates.
7 | 2. It reduces the memory footprint by avoiding over-allocation of DOM nodes.
8 |
9 | [](LICENSE.md)
10 |
11 | ## Install
12 |
13 | ```bash
14 | npm install --save-dev svelte-window
15 | ```
16 |
17 | ## Usage
18 |
19 | This library is a port of react-window, here are some examples: [react-window.now.sh](https://react-window.now.sh/).
20 |
21 | This is how to render a basic list:
22 |
23 |
24 | ```svelte
25 |
28 |
34 | {#each items as it (it.key)}
35 |
Row {it.index}
36 | {/each}
37 |
38 | ```
39 |
40 | Here is another example with a fixed size grid with a scroll-to button, scrolling indicators:
41 |
42 | ```svelte
43 |
58 |
59 |
69 | {#each items as it (it.key)}
70 |
element.
43 | */
44 | className?: string;
45 | /**
46 | * Tag name passed to document.createElement to create the inner container element. This is an advanced property; in most cases, the default ("div") should be used.
47 | */
48 | innerElementType?: string;
49 | /**
50 | * Ref to attach to the inner container element. This is an advanced property.
51 | */
52 | innerRef?: HTMLDivElement;
53 | /**
54 | * Tag name passed to document.createElement to create the inner container element. This is an advanced property; in most cases, the default ("div") should be used.
55 | *
56 | * @deprecated since 1.4.0
57 | */
58 | innerTagName?: string;
59 | /**
60 | * Contextual data to be passed to the item renderer as a data prop. This is a light-weight alternative to React's built-in context API.
61 | *
62 | * Item data is useful for item renderers that are class components.
63 | */
64 | itemData?: any;
65 | /**
66 | * Tag name passed to document.createElement to create the outer container element. This is an advanced property; in most cases, the default ("div") should be used.
67 | */
68 | outerElementType?: string;
69 | /**
70 | * Ref to attach to the outer container element. This is an advanced property.
71 | */
72 | outerRef?: HTMLDivElement;
73 | /**
74 | * Tag name passed to document.createElement to create the outer container element. This is an advanced property; in most cases, the default ("div") should be used.
75 | *
76 | * @deprecated since 1.4.0
77 | */
78 | outerTagName?: string;
79 | /**
80 | * Optional inline style to attach to outermost
element.
81 | */
82 | style?: string;
83 | /**
84 | * Adds an additional isScrolling parameter to the children render function. This parameter can be used to show a placeholder row or column while the list is being scrolled.
85 | *
86 | * Note that using this parameter will result in an additional render call after scrolling has stopped (when isScrolling changes from true to false).
87 | */
88 | useIsScrolling?: boolean;
89 | }
90 |
91 | export type ListItemKeySelector = (index: number, data: any) => string | number;
92 |
93 | export interface ListOnItemsRenderedProps {
94 | overscanStartIndex: number;
95 | overscanStopIndex: number;
96 | visibleStartIndex: number;
97 | visibleStopIndex: number;
98 | }
99 |
100 | export interface ListOnScrollProps {
101 | scrollDirection: ScrollDirection;
102 | scrollOffset: number;
103 | scrollUpdateWasRequested: boolean;
104 | }
105 |
106 | export interface ListProps extends CommonProps {
107 |
108 | /**
109 | * Height of the list.
110 | *
111 | * For vertical lists, this must be a number. It affects the number of rows that will be rendered (and displayed) at any given time.
112 | *
113 | * For horizontal lists, this can be a number or a string (e.g. "50%").
114 | */
115 | height: number | string;
116 | /**
117 | * Total number of items in the list. Note that only a few items will be rendered and displayed at a time.
118 | */
119 | itemCount: number;
120 | /**
121 | * Width of the list.
122 | *
123 | * For horizontal lists, this must be a number. It affects the number of columns that will be rendered (and displayed) at any given time.
124 | *
125 | * For vertical lists, this can be a number or a string (e.g. "50%").
126 | */
127 | width: number | string;
128 | /**
129 | * Determines the direction of text and horizontal scrolling.
130 | *
131 | * This property also automatically sets the CSS direction style for the list component.
132 | *
133 | * Specifying "horizontal" or "vertical" for this value is deprecated. Use "layout" prop instead.
134 | *
135 | * @default "ltr"
136 | */
137 | direction?: CSSDirection | Direction;
138 | /**
139 | * Layout/orientation of the list.
140 | *
141 | * Acceptable values are:
142 | * - "vertical" (default) - Up/down scrolling.
143 | * - "horizontal" - Left/right scrolling.
144 | *
145 | * Note that lists may scroll in both directions (depending on CSS) but content will only be windowed in the layout direction specified.
146 | */
147 | layout?: Layout;
148 | /**
149 | * Scroll offset for initial render.
150 | *
151 | * For vertical lists, this affects scrollTop. For horizontal lists, this affects scrollLeft.
152 | */
153 | initialScrollOffset?: number;
154 | /**
155 | * By default, lists will use an item's index as its key. This is okay if:
156 | *
157 | * - Your collections of items is never sorted or modified
158 | * - Your item renderer is not stateful and does not extend PureComponent
159 | *
160 | * If your list does not satisfy the above constraints, use the itemKey property to specify your own keys for items
161 | */
162 | itemKey?: ListItemKeySelector;
163 | /**
164 | * The number of items (rows or columns) to render outside of the visible area. This property can be important for two reasons:
165 | *
166 | * - Overscanning by one row or column allows the tab key to focus on the next (not yet visible) item.
167 | * - Overscanning slightly can reduce or prevent a flash of empty space when a user first starts scrolling.
168 | *
169 | * Note that overscanning too much can negatively impact performance. By default, List overscans by one item.
170 | */
171 | overscanCount?: number;
172 | /**
173 | * Called when the items rendered by the list change.
174 | */
175 | onItemsRendered?: (props: ListOnItemsRenderedProps) => any;
176 | /**
177 | * Called when the list scroll positions changes, as a result of user scrolling or scroll-to method calls.
178 | */
179 | onScroll?: (props: ListOnScrollProps) => any;
180 | }
181 |
182 | export type GridItemKeySelector = (params: {
183 | columnIndex: number;
184 | rowIndex: number;
185 | data: any;
186 | }) => string | number;
187 |
188 | export interface GridOnItemsRenderedProps {
189 | overscanColumnStartIndex: number;
190 | overscanColumnStopIndex: number;
191 | overscanRowStartIndex: number;
192 | overscanRowStopIndex: number;
193 | visibleColumnStartIndex: number;
194 | visibleColumnStopIndex: number;
195 | visibleRowStartIndex: number;
196 | visibleRowStopIndex: number;
197 | }
198 |
199 | export interface GridOnScrollProps {
200 | horizontalScrollDirection: ScrollDirection;
201 | scrollLeft: number;
202 | scrollTop: number;
203 | scrollUpdateWasRequested: boolean;
204 | verticalScrollDirection: ScrollDirection;
205 | }
206 |
207 | export interface GridProps extends CommonProps {
208 | /**
209 | * Number of columns in the grid. Note that only a few columns will be rendered and displayed at a time.
210 | */
211 | columnCount: number;
212 | /**
213 | * Determines the direction of text and horizontal scrolling.
214 | *
215 | * This property also automatically sets the CSS direction style for the grid component.
216 | *
217 | * @default "ltr"
218 | */
219 | direction?: CSSDirection;
220 | /**
221 | * Height of the grid. This affects the number of rows that will be rendered (and displayed) at any given time.
222 | */
223 | height: number;
224 | /**
225 | * Horizontal scroll offset for initial render.
226 | */
227 | initialScrollLeft?: number;
228 | /**
229 | * Vertical scroll offset for initial render.
230 | */
231 | initialScrollTop?: number;
232 | /**
233 | * By default, grids will use an item's indices as its key. This is okay if:
234 | *
235 | * - Your collections of items is never sorted or modified
236 | * - Your item renderer is not stateful and does not extend PureComponent
237 | *
238 | * If your grid does not satisfy the above constraints, use the itemKey property to specify your own keys for items.
239 | */
240 | itemKey?: GridItemKeySelector;
241 | /**
242 | * Called when the items rendered by the grid change.
243 | */
244 | onItemsRendered?: (props: GridOnItemsRenderedProps) => any;
245 | /**
246 | * Called when the grid scroll positions changes, as a result of user scrolling or scroll-to method calls.
247 | */
248 | onScroll?: (props: GridOnScrollProps) => any;
249 | /**
250 | * @deprecated since version 1.8.2, please use overscanColumnCount
251 | */
252 | overscanColumnsCount?: number;
253 | /**
254 | * The number of columns to render outside of the visible area. This property can be important for two reasons:
255 | *
256 | * - Overscanning by one row or column allows the tab key to focus on the next (not yet visible) item.
257 | * - Overscanning slightly can reduce or prevent a flash of empty space when a user first starts scrolling.
258 | *
259 | * Note that overscanning too much can negatively impact performance. By default, grid overscans by one item.
260 | */
261 | overscanColumnCount?: number;
262 | /**
263 | * @deprecated since version 1.8.2, please use overscanRowCount
264 | */
265 | overscanRowsCount?: number;
266 | /**
267 | * The number of rows to render outside of the visible area. This property can be important for two reasons:
268 | *
269 | * - Overscanning by one row or column allows the tab key to focus on the next (not yet visible) item.
270 | * - Overscanning slightly can reduce or prevent a flash of empty space when a user first starts scrolling.
271 | *
272 | * Note that overscanning too much can negatively impact performance. By default, grid overscans by one item.
273 | */
274 | overscanRowCount?: number;
275 | /**
276 | * The number of items (rows or columns) to render outside of the visible area. This property can be important for two reasons:
277 | *
278 | * - Overscanning by one row or column allows the tab key to focus on the next (not yet visible) item.
279 | * - Overscanning slightly can reduce or prevent a flash of empty space when a user first starts scrolling.
280 | *
281 | * Note that overscanning too much can negatively impact performance. By default, grid overscans by one item.
282 | *
283 | * @deprecated since version 1.4.0
284 | */
285 | overscanCount?: number;
286 | /**
287 | * Number of rows in the grid. Note that only a few rows will be rendered and displayed at a time.
288 | */
289 | rowCount: number;
290 | /**
291 | * Width of the grid. This affects the number of columns that will be rendered (and displayed) at any given time.
292 | */
293 | width: number;
294 | }
295 |
296 | export interface FixedSizeListProps extends ListProps {
297 | /**
298 | * Size of a item in the direction being windowed. For vertical lists, this is the row height. For horizontal lists, this is the column width.
299 | */
300 | itemSize: number;
301 | }
302 |
303 | export interface VariableSizeListProps extends ListProps {
304 | /**
305 | * Estimated size of a item in the direction being windowed. For vertical lists, this is the row height. For horizontal lists, this is the column width.
306 | *
307 | * This value is used to calculated the estimated total size of a list before its items have all been measured. The total size impacts user scrolling behavior.
308 | * It is updated whenever new items are measured.
309 | */
310 | estimatedItemSize?: number;
311 | /**
312 | * Returns the size of a item in the direction being windowed. For vertical lists, this is the row height. For horizontal lists, this is the column width.
313 | */
314 | itemSize: (index: number) => number;
315 | }
316 |
317 | export interface FixedSizeGridProps extends GridProps {
318 | /**
319 | * Width of an individual column within the grid.
320 | */
321 | columnWidth: number;
322 | /**
323 | * Height of an individual row within the grid.
324 | */
325 | rowHeight: number;
326 | }
327 |
328 | export interface VariableSizeGridProps extends GridProps {
329 | /**
330 | * Returns the width of the specified column.
331 | */
332 | columnWidth: (index: number) => number;
333 | /**
334 | * Average (or estimated) column width for unrendered columns.
335 | *
336 | * This value is used to calculated the estimated total width of a Grid before its columns have all been measured.
337 | * The estimated width impacts user scrolling behavior. It is updated whenever new columns are measured.
338 | */
339 | estimatedColumnWidth?: number;
340 | /**
341 | * Average (or estimated) row height for unrendered rows.
342 | *
343 | * This value is used to calculated the estimated total height of a Grid before its rows have all been measured.
344 | * The estimated height impacts user scrolling behavior. It is updated whenever new rows are measured.
345 | */
346 | estimatedRowHeight?: number;
347 | /**
348 | * Returns the height of the specified row.
349 | */
350 | rowHeight: (index: number) => number;
351 | }
352 |
353 | /**
354 | * Fixed Size List
355 | *
356 | * usage:
357 | *
358 | * {#each items as item (item.key)}
359 | * {item.index}
360 | * {/each}
361 | *
362 | */
363 | export class FixedSizeList extends SvelteComponentTyped {
366 | /**
367 | * Scroll to the specified offset (scrollTop or scrollLeft, depending on the direction prop).
368 | */
369 | scrollTo(scrollOffset: number): void;
370 | /**
371 | * Scroll to the specified item.
372 | *
373 | * By default, the List will scroll as little as possible to ensure the item is visible.
374 | * You can control the alignment of the item though by specifying a second alignment parameter. Acceptable values are:
375 | *
376 | * - auto (default) - Scroll as little as possible to ensure the item is visible. (If the item is already visible, it won't scroll at all.)
377 | * - smart
378 | * - If the item is already visible, don't scroll at all.
379 | * - If it is less than one viewport away, scroll as little as possible so that it becomes visible.
380 | * - If it is more than one viewport away, scroll so that it is centered within the list.
381 | * - center - Center align the item within the list.
382 | * - end - Align the item to the end of the list (the bottom for vertical lists or the right for horizontal lists).
383 | * - start - Align the item to the beginning of the list (the top for vertical lists or the left for horizontal lists).
384 | */
385 | scrollToItem(index: number, align?: Align): void;
386 | }
387 |
388 | /**
389 | * Fixed Size List for use in Server-Side-Rendered environment
390 | *
391 | * usage:
392 | *
393 | * {#each items as item (item.key)}
394 | * {item.index}
395 | * {/each}
396 | *
397 | */
398 | export type FixedSizeListSSR = FixedSizeList;
399 |
400 | /**
401 | * Variable Size List
402 | *
403 | * usage:
404 | *
405 | * {#each items as item (item.key)}
406 | * {item.index}
407 | * {/each}
408 | * *
409 | */
410 | export class VariableSizeList extends SvelteComponentTyped {
413 | /**
414 | * Scroll to the specified offset (scrollTop or scrollLeft, depending on the direction prop).
415 | */
416 | scrollTo(scrollOffset: number): void;
417 | /**
418 | * Scroll to the specified item.
419 | *
420 | * By default, the List will scroll as little as possible to ensure the item is visible.
421 | * You can control the alignment of the item though by specifying a second alignment parameter. Acceptable values are:
422 | *
423 | * - auto (default) - Scroll as little as possible to ensure the item is visible. (If the item is already visible, it won't scroll at all.)
424 | * - smart
425 | * - If the item is already visible, don't scroll at all.
426 | * - If it is less than one viewport away, scroll as little as possible so that it becomes visible.
427 | * - If it is more than one viewport away, scroll so that it is centered within the list.
428 | * - center - Center align the item within the list.
429 | * - end - Align the item to the end of the list (the bottom for vertical lists or the right for horizontal lists).
430 | * - start - Align the item to the beginning of the list (the top for vertical lists or the left for horizontal lists).
431 | */
432 | scrollToItem(index: number, align?: Align): void;
433 | /**
434 | * VariableSizeList caches offsets and measurements for each index for performance purposes.
435 | * This method clears that cached data for all items after (and including) the specified index.
436 | * It should be called whenever a item's size changes. (Note that this is not a typical occurrence.)
437 | *
438 | * By default the list will automatically re-render after the index is reset.
439 | * If you would like to delay this re-render until e.g. a state update has completed in the parent component,
440 | * specify a value of false for the second, optional parameter.
441 | */
442 | instance: {
443 | resetAfterIndex: (index: number, shouldForceUpdate?: boolean) => void;
444 | }
445 | }
446 | /**
447 | * Variable Size List for use in Server-Side-Rendered environment
448 | *
449 | * usage:
450 | *
451 | * {#each items as item (item.key)}
452 | * {item.index}
453 | * {/each}
454 | * *
455 | */
456 | export type VariableSizeListSSR = VariableSizeList
457 |
458 | /**
459 | * Fixed Size Grid
460 | *
461 | * usage:
462 | *
463 | * {#each items as item (item.key)}
464 | * {item.rowIndex} - {item.columnIndex}
465 | * {/each}
466 | * *
467 | */
468 | export class FixedSizeGrid extends SvelteComponentTyped {
471 | /**
472 | * Scroll to the specified offsets.
473 | */
474 | scrollTo(params: { scrollLeft: number; scrollTop: number }): void;
475 | /**
476 | * Scroll to the specified item.
477 | *
478 | * By default, the Grid will scroll as little as possible to ensure the item is visible.
479 | * You can control the alignment of the item though by specifying an `align` property. Acceptable values are:
480 | *
481 | * - auto (default) - Scroll as little as possible to ensure the item is visible. (If the item is already visible, it won't scroll at all.)
482 | * - smart
483 | * - If the item is already visible, don't scroll at all.
484 | * - If it is less than one viewport away, scroll as little as possible so that it becomes visible.
485 | * - If it is more than one viewport away, scroll so that it is centered within the grid.
486 | * - center - Center align the item within the grid.
487 | * - end - Align the item to the bottom, right hand side of the grid.
488 | * - start - Align the item to the top, left hand of the grid.
489 | *
490 | * If either `columnIndex` or `rowIndex` are omitted, `scrollLeft` or `scrollTop` will be unchanged (respectively).
491 | */
492 | scrollToItem(params: {
493 | align?: Align;
494 | columnIndex?: number;
495 | rowIndex?: number;
496 | }): void;
497 | }
498 |
499 | /**
500 | * Fixed Size Grid for use in Server-Side-Rendered environment
501 | *
502 | * usage:
503 | *
504 | * {#each items as item (item.key)}
505 | * {item.rowIndex} - {item.columnIndex}
506 | * {/each}
507 | * *
508 | */
509 | export type FixedSizeGridSSR = FixedSizeGrid
510 |
511 |
512 | /**
513 | * Variable Size Grid
514 | *
515 | * usage:
516 | *
517 | * {#each items as item (item.key)}
518 | * {item.rowIndex} - {item.columnIndex}
519 | * {/each}
520 | * *
521 | */
522 | export class VariableSizeGrid extends SvelteComponentTyped {
525 | /**
526 | * Scroll to the specified offsets.
527 | */
528 | scrollTo(params: { scrollLeft: number; scrollTop: number }): void;
529 | /**
530 | * Scroll to the specified item.
531 | *
532 | * By default, the Grid will scroll as little as possible to ensure the item is visible.
533 | * You can control the alignment of the item though by specifying an `align` property. Acceptable values are:
534 | *
535 | * - auto (default) - Scroll as little as possible to ensure the item is visible. (If the item is already visible, it won't scroll at all.)
536 | * - smart
537 | * - If the item is already visible, don't scroll at all.
538 | * - If it is less than one viewport away, scroll as little as possible so that it becomes visible.
539 | * - If it is more than one viewport away, scroll so that it is centered within the grid.
540 | * - center - Center align the item within the grid.
541 | * - end - Align the item to the bottom, right hand side of the grid.
542 | * - start - Align the item to the top, left hand of the grid.
543 | *
544 | * If either `columnIndex` or `rowIndex` are omitted, `scrollLeft` or `scrollTop` will be unchanged (respectively).
545 | */
546 | scrollToItem(params: {
547 | align?: Align;
548 | columnIndex?: number;
549 | rowIndex?: number;
550 | }): void;
551 |
552 | instance: {
553 | /**
554 | * VariableSizeGrid caches offsets and measurements for each column index for performance purposes.
555 | * This method clears that cached data for all columns after (and including) the specified index.
556 | * It should be called whenever a column's width changes. (Note that this is not a typical occurrence.)
557 | *
558 | * By default the grid will automatically re-render after the index is reset.
559 | * If you would like to delay this re-render until e.g. a state update has completed in the parent component,
560 | * specify a value of false for the second, optional parameter.
561 | */
562 | resetAfterColumnIndex: (index: number, shouldForceUpdate?: boolean) => void;
563 | /**
564 | * VariableSizeGrid caches offsets and measurements for each item for performance purposes.
565 | * This method clears that cached data for all items after (and including) the specified indices.
566 | * It should be called whenever an items size changes. (Note that this is not a typical occurrence.)
567 | *
568 | * By default the grid will automatically re-render after the index is reset.
569 | * If you would like to delay this re-render until e.g. a state update has completed in the parent component,
570 | * specify a value of false for the optional shouldForceUpdate parameter.
571 | */
572 | resetAfterIndices: (params: {
573 | columnIndex: number;
574 | rowIndex: number;
575 | shouldForceUpdate?: boolean;
576 | }) => void;
577 | /**
578 | * VariableSizeGrid caches offsets and measurements for each row index for performance purposes.
579 | * This method clears that cached data for all rows after (and including) the specified index.
580 | * It should be called whenever a row's height changes. (Note that this is not a typical occurrence.)
581 | *
582 | * By default the grid will automatically re-render after the index is reset.
583 | * If you would like to delay this re-render until e.g. a state update has completed in the parent component,
584 | * specify a value of false for the second, optional parameter.
585 | */
586 | resetAfterRowIndex: (index: number, shouldForceUpdate?: boolean) => void;
587 | }
588 | }
589 |
590 | /**
591 | * Variable Size Grid for use in Server-Side-Rendered environment
592 | *
593 | * usage:
594 | *
595 | * {#each items as item (item.key)}
596 | * {item.rowIndex} - {item.columnIndex}
597 | * {/each}
598 | * *
599 | */
600 | export type VariableSizeGridSSR = VariableSizeGrid
601 |
602 | /**
603 | * Custom comparison function for React.memo().
604 | * It knows to compare individual style props and ignore the wrapper object.
605 | *
606 | * @see https://reactjs.org/docs/react-api.html#reactmemo
607 | */
608 | export function areEqual(
609 | prevProps: Readonly