UNPKG

@kelvininc/ui-components

Version:
219 lines (218 loc) 8.12 kB
import { Host, h } from "@stencil/core"; import { debounce, throttle } from "lodash-es"; import { buildElement } from "./virtualized-list.helper"; export class KvVirtualizedList { constructor() { /** @inheritdoc */ this.overscanCount = 5; // create an Observer instance this.resizeObserver = new ResizeObserver(() => this.debounceResize()); this.totalHeight = 1; this.scrollTop = 0; this.debounceResize = debounce(() => this.updateVisibleElements(), 100); this.throttledScroll = throttle(() => { this.updateScrollTop(); this.updateVisibleElements(); }, 16, { trailing: true }); this.updateScrollTop = () => { var _a; this.scrollTop = (_a = this.element.scrollTop) !== null && _a !== void 0 ? _a : 0; }; this.updateVisibleElements = () => { this.elements = this.getVisibleElements(); }; this.getVisibleElements = () => { var _a; const containerHeight = (_a = this.element.clientHeight) !== null && _a !== void 0 ? _a : 0; const elements = []; let accumulator = 0; const overscanHeight = this.overscanCount * this.itemHeight; for (let index = 0; index < this.itemCount; index++) { let itemkey = this.getItemKey(index); // Check if the item is above the viewport if (this.scrollTop - overscanHeight > accumulator + this.itemHeight) { accumulator += this.itemHeight; continue; } // Check if the item is below the viewport if (this.scrollTop + containerHeight + overscanHeight < accumulator) { break; } elements.push(buildElement(index, itemkey, this.itemHeight, accumulator, this.renderItem)); accumulator += this.itemHeight; } return elements; }; } updateTotalHeight() { this.totalHeight = this.itemHeight * this.itemCount; } renderItemHandle() { this.updateVisibleElements(); } connectedCallback() { this.element.addEventListener('scroll', this.throttledScroll); this.resizeObserver.observe(this.element); this.updateTotalHeight(); } disconnectedCallback() { this.element.removeEventListener('scroll', this.throttledScroll); this.resizeObserver.disconnect(); } render() { return (h(Host, { key: '9f51b9c9ddb6cdefedef133bb24adff93edd7682' }, h("div", { key: '1b14fb2c2b7412e6cad824dd9a65d1e6e6fb19cb', class: "inner", style: { height: `${this.totalHeight}px` } }, this.elements))); } static get is() { return "kv-virtualized-list"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["virtualized-list.scss"] }; } static get styleUrls() { return { "$": ["virtualized-list.css"] }; } static get properties() { return { "itemCount": { "type": "number", "attribute": "item-count", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(required) Defines the total number of items rendered in the list" }, "getter": false, "setter": false, "reflect": true }, "itemHeight": { "type": "number", "attribute": "item-height", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(required) Defines the estimated height in pixels of an item" }, "getter": false, "setter": false, "reflect": true }, "getItemKey": { "type": "unknown", "attribute": "get-item-key", "mutable": false, "complexType": { "original": "(index: number) => string", "resolved": "(index: number) => string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(required) Defines the given item key" }, "getter": false, "setter": false }, "renderItem": { "type": "unknown", "attribute": "render-item", "mutable": false, "complexType": { "original": "RenderItemFunc", "resolved": "(index: number) => ChildType | Promise<ChildType> | ChildType[] | Promise<ChildType[]> | Promise<ChildType>[]", "references": { "RenderItemFunc": { "location": "import", "path": "./virtualized-list.types", "id": "src/components/virtualized-list/virtualized-list.types.ts::RenderItemFunc" } } }, "required": false, "optional": false, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(required) Defines the item render function" }, "getter": false, "setter": false }, "overscanCount": { "type": "number", "attribute": "overscan-count", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) The number of items outside the viewport that are rendered. Default: `5`" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "5" } }; } static get states() { return { "totalHeight": {}, "scrollTop": {}, "elements": {} }; } static get elementRef() { return "element"; } static get watchers() { return [{ "propName": "itemHeight", "methodName": "updateTotalHeight" }, { "propName": "itemCount", "methodName": "updateTotalHeight" }, { "propName": "renderItem", "methodName": "renderItemHandle" }]; } }