├── .editorconfig ├── .gitignore ├── LICENSE ├── dist ├── collection │ ├── collection-manifest.json │ ├── components │ │ ├── fetch-helper │ │ │ ├── fetch-helper.css │ │ │ ├── fetch-helper.js │ │ │ └── fetch-helper.scss │ │ └── virtual-scroll │ │ │ ├── virtual-scroll.css │ │ │ ├── virtual-scroll.js │ │ │ └── virtual-scroll.scss │ ├── index.js │ └── interface.js ├── esm │ ├── es5 │ │ ├── kbufhwni.js │ │ ├── nqhdrz5d.js │ │ ├── polyfills │ │ │ ├── array.js │ │ │ ├── dom.js │ │ │ ├── fetch.js │ │ │ ├── object.js │ │ │ ├── promise.js │ │ │ └── string.js │ │ ├── virtualscroll.components.js │ │ ├── virtualscroll.core.js │ │ ├── virtualscroll.define.js │ │ └── virtualscroll.global.js │ └── index.js ├── index.js ├── types │ ├── components.d.ts │ ├── components │ │ ├── fetch-helper │ │ │ └── fetch-helper.d.ts │ │ └── virtual-scroll │ │ │ └── virtual-scroll.d.ts │ ├── index.d.ts │ └── stencil.core.d.ts ├── virtualscroll.js └── virtualscroll │ ├── kbufhwni.es5.js │ ├── kbufhwni.js │ ├── nqhdrz5d.es5.js │ ├── nqhdrz5d.js │ ├── virtualscroll.4u6xzod9.js │ ├── virtualscroll.etffcq0f.js │ └── virtualscroll.global.js ├── package.json ├── readme.md ├── src ├── components.d.ts ├── components │ ├── fetch-helper │ │ ├── fetch-helper.scss │ │ ├── fetch-helper.spec.ts │ │ └── fetch-helper.tsx │ └── virtual-scroll │ │ ├── virtual-scroll.scss │ │ ├── virtual-scroll.spec.ts │ │ └── virtual-scroll.tsx ├── index.d.ts ├── index.html └── index.ts ├── stencil.config.js ├── tsconfig.json └── www ├── build ├── virtualscroll.js └── virtualscroll │ ├── kbufhwni.es5.js │ ├── kbufhwni.js │ ├── nqhdrz5d.es5.js │ ├── nqhdrz5d.js │ ├── virtualscroll.4u6xzod9.js │ ├── virtualscroll.etffcq0f.js │ ├── virtualscroll.global.js │ └── virtualscroll.registry.json └── index.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | *~ 4 | *.sw[mnpcod] 5 | *.log 6 | *.lock 7 | *.tmp 8 | *.tmp.* 9 | log.txt 10 | *.sublime-project 11 | *.sublime-workspace 12 | 13 | .idea/ 14 | .vscode/ 15 | .sass-cache/ 16 | .versions/ 17 | node_modules/ 18 | $RECYCLE.BIN/ 19 | 20 | .DS_Store 21 | Thumbs.db 22 | UserInterfaceState.xcuserstate 23 | .env 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ionic 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 | -------------------------------------------------------------------------------- /dist/collection/collection-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": [ 3 | { 4 | "tag": "fetch-helper", 5 | "dependencies": [ 6 | "virtual-scroll" 7 | ], 8 | "componentClass": "FetchHelperWebComponent", 9 | "componentPath": "components/fetch-helper/fetch-helper.js", 10 | "styles": { 11 | "$": { 12 | "stylePaths": [ 13 | "components/fetch-helper/fetch-helper.scss" 14 | ] 15 | } 16 | }, 17 | "props": [ 18 | { 19 | "name": "selector", 20 | "type": "String", 21 | "attr": "selector" 22 | } 23 | ], 24 | "states": [ 25 | { 26 | "name": "changed" 27 | }, 28 | { 29 | "name": "list" 30 | } 31 | ], 32 | "hostElement": { 33 | "name": "el" 34 | } 35 | }, 36 | { 37 | "tag": "virtual-scroll", 38 | "dependencies": [], 39 | "componentClass": "VirualScrollWebComponent", 40 | "componentPath": "components/virtual-scroll/virtual-scroll.js", 41 | "styles": { 42 | "$": { 43 | "stylePaths": [ 44 | "components/virtual-scroll/virtual-scroll.scss" 45 | ] 46 | } 47 | }, 48 | "props": [ 49 | { 50 | "name": "bottomOffset", 51 | "type": "Number", 52 | "attr": "bottom-offset" 53 | }, 54 | { 55 | "name": "list", 56 | "attr": "list", 57 | "watch": [ 58 | "watchHandler" 59 | ] 60 | }, 61 | { 62 | "name": "selector", 63 | "type": "String", 64 | "attr": "selector" 65 | }, 66 | { 67 | "name": "virtualRatio", 68 | "type": "Number", 69 | "attr": "virtual-ratio" 70 | } 71 | ], 72 | "states": [ 73 | { 74 | "name": "changed" 75 | } 76 | ], 77 | "methods": [ 78 | { 79 | "name": "clear" 80 | }, 81 | { 82 | "name": "forceUpdateComponent" 83 | }, 84 | { 85 | "name": "refresh" 86 | }, 87 | { 88 | "name": "scrollToNode" 89 | }, 90 | { 91 | "name": "setInfinateFinally" 92 | }, 93 | { 94 | "name": "setInfinateOn" 95 | } 96 | ], 97 | "hostElement": { 98 | "name": "el" 99 | }, 100 | "events": [ 101 | { 102 | "event": "toBottom" 103 | }, 104 | { 105 | "event": "update" 106 | } 107 | ] 108 | } 109 | ], 110 | "collections": [], 111 | "compiler": { 112 | "name": "@stencil/core", 113 | "version": "0.9.11", 114 | "typescriptVersion": "2.9.2" 115 | }, 116 | "bundles": [ 117 | { 118 | "components": [ 119 | "virtual-scroll" 120 | ] 121 | }, 122 | { 123 | "components": [ 124 | "fetch-helper" 125 | ] 126 | } 127 | ] 128 | } -------------------------------------------------------------------------------- /dist/collection/components/fetch-helper/fetch-helper.css: -------------------------------------------------------------------------------- 1 | .cover { 2 | position: relative; 3 | width: 150px; 4 | height: 150px; 5 | background-size: cover; 6 | margin: 0 auto; } 7 | 8 | .title { 9 | font-size: 15px; 10 | height: 40px; 11 | text-align: center; } 12 | 13 | .cover:after { 14 | content: ""; 15 | display: block; 16 | padding-bottom: 67%; } 17 | 18 | .reload, .scrolling { 19 | position: absolute; 20 | top: 0; 21 | margin: 10px; 22 | padding: 10px; 23 | background: #ccc; 24 | cursor: pointer; 25 | z-index: 1; } 26 | 27 | .scrolling { 28 | right: 0; } 29 | 30 | .reload { 31 | left: 0; } 32 | -------------------------------------------------------------------------------- /dist/collection/components/fetch-helper/fetch-helper.js: -------------------------------------------------------------------------------- 1 | export class FetchHelperWebComponent { 2 | constructor() { 3 | this.list = []; 4 | //class selector 5 | this.selector = ''; 6 | this.virtual = []; 7 | //change detection strategy 8 | this.changed = []; 9 | } 10 | componentWillLoad() { 11 | this.request(); 12 | } 13 | request() { 14 | let headers = {}; 15 | headers['Content-Type'] = 'application/json'; 16 | headers['token'] = 'kRuGZ3Xd'; 17 | let mode = "cors"; 18 | let options = { 19 | method: 'GET', 20 | mode: mode, 21 | headers: new Headers(headers) 22 | }; 23 | let request = new Request("https://jsonplaceholder.typicode.com/photos", options); 24 | fetch(request).then(response => { return response.json(); }).then(r => { 25 | r.splice(0, 50).map(m => { 26 | m.index = this.list.length; 27 | this.list = [...this.list, m]; 28 | }); 29 | const scrollTag = this.el.querySelector('virtual-scroll'); 30 | scrollTag.list = this.list; 31 | scrollTag.addEventListener('toBottom', () => { 32 | this.lazyRequest(); 33 | }); 34 | scrollTag.addEventListener('update', (event) => { 35 | console.log('update'); 36 | this.virtual = event.detail; 37 | this.changed = [...this.changed, '']; 38 | }); 39 | }); 40 | } 41 | lazyRequest() { 42 | let headers = {}; 43 | headers['Content-Type'] = 'application/json'; 44 | let mode = "cors"; 45 | let options = { 46 | method: 'GET', 47 | mode: mode, 48 | headers: new Headers(headers) 49 | }; 50 | let request = new Request("https://jsonplaceholder.typicode.com/photos", options); 51 | fetch(request).then(response => { return response.json(); }).then(r => { 52 | setTimeout(() => { 53 | r.splice(0, 50).map(m => { 54 | m.index = this.list.length; 55 | this.list = [...this.list, m]; 56 | }); 57 | const scrollTag = this.el.querySelector('virtual-scroll'); 58 | scrollTag.list = this.list; 59 | if (this.list.length > 200) { 60 | scrollTag.setInfinateFinally(); 61 | } 62 | else { 63 | scrollTag.setInfinateOn(); 64 | } 65 | }, 3000); 66 | }); 67 | } 68 | reload() { 69 | const scrollTag = this.el.querySelector('virtual-scroll'); 70 | scrollTag.list = []; 71 | scrollTag.clear(); 72 | this.changed = [...this.changed, '']; 73 | setTimeout(() => { 74 | let headers = {}; 75 | headers['Content-Type'] = 'application/json'; 76 | let mode = "cors"; 77 | let options = { 78 | method: 'GET', 79 | mode: mode, 80 | headers: new Headers(headers) 81 | }; 82 | let request = new Request("https://jsonplaceholder.typicode.com/photos", options); 83 | fetch(request).then(response => { return response.json(); }).then(r => { 84 | r.splice(0, 50).map(m => { 85 | m.index = this.list.length; 86 | this.list = [...this.list, m]; 87 | }); 88 | const scrollTag = this.el.querySelector('virtual-scroll'); 89 | scrollTag.list = this.list; 90 | if (this.list.length > 200) { 91 | scrollTag.setInfinateFinally(); 92 | } 93 | else { 94 | scrollTag.setInfinateOn(); 95 | } 96 | }); 97 | }, 2000); 98 | } 99 | scrolling() { 100 | const scrollTag = this.el.querySelector('virtual-scroll'); 101 | // scrollTag.list.splice(2, 1); 102 | // scrollTag.refresh(); 103 | // this.changed = [...this.changed, '']; 104 | scrollTag.scrollToNode(25, 1000, -50); 105 | } 106 | render() { 107 | return ([ 108 | h("div", { onClick: this.reload.bind(this), class: "reload" }, "reload"), 109 | h("div", { onClick: this.scrolling.bind(this), class: "scrolling" }, "scrolling"), 110 | h("div", { class: "virtual-container" }, 111 | h("virtual-scroll", { "bottom-offset": "5", "virtual-ratio": "15", selector: this.selector }, 112 | h("div", { slot: "virtual", class: "virtual-slot" }, this.virtual.map((item) => h("div", { class: "offer virtual-item", id: item.index }, 113 | h("div", { style: { backgroundImage: "url(" + item.thumbnailUrl + ")" }, class: "cover" }), 114 | h("div", { class: "title" }, item.index), 115 | h("div", { class: "title" }, item.title)))), 116 | h("div", { slot: "loader" }, "loading..."))) 117 | ]); 118 | } 119 | static get is() { return "fetch-helper"; } 120 | static get properties() { return { 121 | "changed": { 122 | "state": true 123 | }, 124 | "el": { 125 | "elementRef": true 126 | }, 127 | "list": { 128 | "state": true 129 | }, 130 | "selector": { 131 | "type": String, 132 | "attr": "selector" 133 | } 134 | }; } 135 | static get style() { return "/**style-placeholder:fetch-helper:**/"; } 136 | } 137 | -------------------------------------------------------------------------------- /dist/collection/components/fetch-helper/fetch-helper.scss: -------------------------------------------------------------------------------- 1 | 2 | .cover { 3 | position: relative; 4 | width: 150px; 5 | height: 150px; 6 | background-size: cover; 7 | margin: 0 auto; 8 | } 9 | .title { 10 | font-size: 15px; 11 | height: 40px; 12 | text-align: center; 13 | } 14 | .cover:after { 15 | content: ""; 16 | display: block; 17 | padding-bottom: 67%; 18 | } 19 | 20 | .reload, .scrolling { 21 | position: absolute; 22 | top: 0; 23 | margin: 10px; 24 | padding: 10px; 25 | background: #ccc; 26 | cursor: pointer; 27 | z-index: 1; 28 | } 29 | 30 | .scrolling { 31 | right: 0; 32 | } 33 | 34 | .reload { 35 | left: 0; 36 | } -------------------------------------------------------------------------------- /dist/collection/components/virtual-scroll/virtual-scroll.css: -------------------------------------------------------------------------------- 1 | .vscroll.inner { 2 | overflow-y: auto; 3 | height: 100%; } 4 | 5 | .vscroll.external { 6 | overflow-y: hidden; } 7 | 8 | .vscroll { 9 | overflow-x: hidden; 10 | position: relative; 11 | display: block; } 12 | .vscroll .vscroll-back { 13 | width: 1px; 14 | opacity: 0; } 15 | .vscroll .vscroll-content { 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | position: absolute; } 20 | .vscroll .vscroll-content.inner { 21 | height: 100%; } 22 | 23 | .infinate-finally div[slot='loader'] { 24 | visibility: hidden; } 25 | 26 | .cleared div[slot='loader'] { 27 | display: none; } 28 | 29 | virual-scroll { 30 | height: 100%; 31 | display: block; } 32 | -------------------------------------------------------------------------------- /dist/collection/components/virtual-scroll/virtual-scroll.js: -------------------------------------------------------------------------------- 1 | /* 2 | logic of this component base on 3 | ... 4 | */ 5 | export class VirualScrollWebComponent { 6 | constructor() { 7 | //list og imported values 8 | this.list = []; 9 | //class selector 10 | this.selector = ''; 11 | //offset bottom event 12 | this.bottomOffset = 0; 13 | //reserve of the bootom rows 14 | this.virtualRatio = 3; 15 | //change detection strategy 16 | this.changed = []; 17 | //position of scroll element 18 | this.position = 0; 19 | this.parentScrollHeight = 0; 20 | //offset of scroll 21 | this.vscrollOffsetTop = 0; 22 | //private contentOffsetTop: number = 0; 23 | this.elementOffsetTop = 0; 24 | /*EVENTS^^^*/ 25 | /*LAZYLOAD*/ 26 | //state to enable bottom infinate event 27 | this.infinateOn = true; 28 | //state to common disable bottom infinate event 29 | this.infinateFinally = false; 30 | /*LAZYLOAD^^^*/ 31 | //full height of component 32 | this.totalHeight = 0; 33 | //list items dimensions 34 | this.listDimensions = []; 35 | //bool state to detect init render 36 | this.initRender = false; 37 | this.toNextUpdateDimensions = false; 38 | // private stackToDelete: Array = []; 39 | this.scrollEventDispatch = () => undefined; 40 | } 41 | //change list event2 42 | watchHandler(newValue, oldValue) { 43 | if (oldValue.length > 0) { 44 | let deleted = oldValue.filter(f => newValue.filter(f2 => f2.index == f.index).length == 0); 45 | if (deleted.length > 0) { 46 | deleted.map(m => { 47 | this._deleteDimension(m.index); 48 | }); 49 | } 50 | } 51 | //let edited = newValue.filter(f => oldValue.filter(f2 => f2.index == f.index).length == 0); 52 | //console.log('let deleted', deleted); 53 | //console.log('let edited', edited); 54 | //console.log('let list', edited); 55 | this.list.map((m, i) => { 56 | if (!m.index) { 57 | m.index = i; 58 | } 59 | }); 60 | this.updateVirtual(true); 61 | //recalculation dimesions of list items 62 | this._setDimensions(); 63 | } 64 | //life cicle methods 65 | componentDidLoad() { 66 | this._setDefParams(); 67 | //get scroll element 68 | if (this.selector.length > 0) { 69 | this.parentScroll = this.el.closest('.' + this.selector); 70 | } 71 | else { 72 | this.parentScroll = this.el.querySelector('.vscroll'); 73 | } 74 | //get scroll element height 75 | this.parentScrollHeight = this.parentScroll['offsetHeight']; 76 | //get scroll element offset top 77 | //this.contentOffsetTop = (this.parentScroll) ? this.parentScroll['offsetTop'] : 0; 78 | //get content element 79 | this.contentEl = this.el.querySelector('.vscroll-content'); 80 | let vscroll = this.el.querySelector('.vscroll'); 81 | this.vscrollOffsetTop = (vscroll) ? vscroll['offsetTop'] : 0; 82 | this.scrollEventDispatch = this.parentScroll.addEventListener('scroll', () => { 83 | //console.log(this.parentScroll['scrollTop'] - this.vscrollOffsetTop - this.elementOffsetTop + this.parentScrollHeight); 84 | if (this.parentScroll['scrollTop'] - this.vscrollOffsetTop - this.elementOffsetTop + this.parentScrollHeight < 0) { 85 | return; 86 | } 87 | this.position = this.parentScroll['scrollTop'] - this.vscrollOffsetTop - this.elementOffsetTop; 88 | // console.log(this.position); 89 | // console.log('-----'); 90 | this.updateVirtual(); 91 | }, false); 92 | } 93 | //dispatch listener of scroll on unload 94 | unwatch() { 95 | if (this.parentScroll) { 96 | this.parentScroll.removeEventListener('scroll', this._listener); 97 | } 98 | } 99 | _listener() { 100 | this.position = this.parentScroll['scrollTop'] - this.vscrollOffsetTop; 101 | this.updateVirtual(); 102 | } 103 | //life cicle methods 104 | componentDidUnload() { 105 | this.unwatch(); 106 | if (this.scrollEventDispatch) { 107 | this.scrollEventDispatch(); 108 | this.scrollEventDispatch = null; 109 | } 110 | // this.el.remove(); 111 | // this.contentEl.remove(); 112 | // this.parentScroll.remove(); 113 | // this.list = null; 114 | // this.listDimensions = null; 115 | } 116 | //life cicle methods 117 | componentWillLoad() { 118 | } 119 | _setDefParams() { 120 | this.first = null; 121 | this.last = null; 122 | this.listDimensions = []; 123 | this.totalHeight = 0; 124 | this.position = 0; 125 | this.infinateOn = true; 126 | this.infinateFinally = false; 127 | } 128 | //update virtual list items 129 | updateVirtual(update = false) { 130 | let findex = (this.first) ? this.first.rindex : 0; 131 | let lindex = (this.last) ? this.last.rindex : 0; 132 | //get first and last viewed nodes by position 133 | this.first = this.listDimensions.filter(f => this.position >= f.start && this.position < f.end)[0]; 134 | this.last = this.listDimensions.filter(f => this.position + this.parentScroll.clientHeight >= f.start && this.position + this.parentScroll.clientHeight < f.end)[0]; 135 | //if last node by position is null, take last of list 136 | if (!this.last) { 137 | this.last = this.listDimensions[this.listDimensions.length - 1]; 138 | } 139 | // console.log('this.first', this.first) 140 | // console.log('this.last', this.last) 141 | //if first/last exist, set topPadding(content transformY). 142 | //virtual list set ... 143 | if (this.first && this.last) { 144 | let lastOffsetIndex = (this.last.rindex + this.virtualRatio) >= this.list.length ? this.list.length : this.last.rindex + this.virtualRatio; 145 | let firstOffsetIndex = (this.first.rindex - this.virtualRatio) < 0 ? 0 : this.first.rindex - this.virtualRatio; 146 | if (lastOffsetIndex == this.list.length && (this.totalHeight - this.position - this.parentScrollHeight) < 0) { 147 | firstOffsetIndex = (findex - this.virtualRatio) < 0 ? 0 : findex - this.virtualRatio; 148 | this.first = this.listDimensions.filter(f => f.rindex == findex)[0]; 149 | } 150 | let v = []; 151 | if (this.list.length > 0) { 152 | v = this.list.slice(firstOffsetIndex, lastOffsetIndex); 153 | } 154 | if ((findex != this.first.rindex || lindex != this.last.rindex) || update) { 155 | requestAnimationFrame(() => { 156 | let d = this.listDimensions.filter(f => f.rindex == firstOffsetIndex)[0]; 157 | if (d) { 158 | this.contentEl.style.transform = 'translateY(' + d.start + 'px)'; 159 | this.contentEl.style.webkitTransform = 'translateY(' + d.start + 'px)'; 160 | } 161 | //this.virtual = v; 162 | this.update.emit(v); 163 | if (update) { 164 | //change detection 165 | this.changed = [...this.changed, '']; 166 | } 167 | }); 168 | //change detection 169 | this.changed = [...this.changed, '']; 170 | } 171 | } 172 | else { 173 | if (this.list.length > 0) { 174 | let v = this.list.slice(0, 20); 175 | //console.log('v2', v) 176 | //this.virtual = v; 177 | this.update.emit(v); 178 | //change detection 179 | this.changed = [...this.changed, '']; 180 | } 181 | } 182 | //bottom event 183 | if (this.last && this.last.rindex >= this.list.length - 1 - this.bottomOffset) { 184 | if (this.infinateOn && !this.infinateFinally && this.list.length > 0) { 185 | this.infinateOn = false; 186 | this.toBottom.emit(this.position); 187 | } 188 | } 189 | } 190 | //set infinate on status to send events 191 | setInfinateOn() { 192 | this.infinateOn = true; 193 | } 194 | //set infinate off status to send events 195 | setInfinateFinally() { 196 | this.infinateFinally = true; 197 | } 198 | //clear component data 199 | clear() { 200 | this._setDefParams(); 201 | requestAnimationFrame(() => { 202 | this.list = []; 203 | this.contentEl.style.transform = 'translateY(' + 0 + 'px)'; 204 | this.contentEl.style.webkitTransform = 'translateY(' + 0 + 'px)'; 205 | this.changed = [...this.changed, '']; 206 | }); 207 | } 208 | //scroll to element method at index 209 | scrollToNode(index, speed, offset = 0) { 210 | if (this.parentScroll) { 211 | if (index <= this.listDimensions.length - 1) { 212 | let dimension = this.listDimensions.filter(f => f.rindex == index)[0]; 213 | this._scrollTo(dimension.start + offset, speed); 214 | } 215 | else { 216 | this._scrollToIndex(index); 217 | } 218 | } 219 | } 220 | // //scroll to element method 221 | // @Method() 222 | // refresh() { 223 | // let missing = this.list.filter(item => this.list.indexOf(item) < 0); 224 | // console.log(missing); 225 | // let v = this.list.slice(this.first.rindex, this.last.rindex + this.bottomOffsetIndex); 226 | // this.update.emit(v); 227 | // //change detection 228 | // this.changed = [...this.changed, '']; 229 | // } 230 | _scrollToIndex(index) { 231 | let perTick = 100; 232 | setTimeout(() => { 233 | this.parentScroll['scrollTop'] = this.parentScroll['scrollTop'] + perTick; 234 | if (this.first && this.first.rindex === index) 235 | return; 236 | this._scrollToIndex(index); 237 | }, 10); 238 | } 239 | _scrollTo(to, duration) { 240 | if (duration <= 0) 241 | return; 242 | let difference = to - this.parentScroll['scrollTop']; 243 | let perTick = difference / duration * 10; 244 | setTimeout(() => { 245 | this.parentScroll['scrollTop'] = this.parentScroll['scrollTop'] + perTick; 246 | if (this.parentScroll['scrollTop'] === to) 247 | return; 248 | this._scrollTo(to, duration - 10); 249 | }, 10); 250 | } 251 | //recalculation dimesions of list items 252 | _setDimensions() { 253 | let oldTotal = this.totalHeight; 254 | if (this.toNextUpdateDimensions) { 255 | this.listDimensions = []; 256 | } 257 | this.toNextUpdateDimensions = false; 258 | let nodes = this.el.querySelectorAll('.virtual-slot .virtual-item'); 259 | // console.log('_setDimensions', nodes) 260 | if (nodes.length > 0) { 261 | for (let vindex = 0; vindex <= nodes.length - 1; vindex++) { 262 | let node = nodes[vindex]; 263 | let rindex = node['id']; 264 | let d = this.listDimensions.filter(f => f.rindex == rindex)[0]; 265 | if (!d) { 266 | this._addNewDimensionToEnd(node['offsetHeight'], rindex); 267 | this.totalHeight = this.listDimensions[this.listDimensions.length - 1].end; 268 | } 269 | } 270 | } 271 | return (this.totalHeight != oldTotal); 272 | } 273 | //Append new dimensions of list item 274 | _addNewDimensionToEnd(height, rindex) { 275 | let parentEnd = (this.listDimensions.length > 0) ? this.listDimensions[this.listDimensions.length - 1].end : 0; 276 | this.listDimensions.push({ 277 | height: height, 278 | start: parentEnd, 279 | end: parentEnd + height, 280 | rindex: parseInt(rindex) 281 | }); 282 | } 283 | _deleteDimension(rindex) { 284 | //this index from list -> [index], if i get index from listDimensions -> filter().. 285 | let d = this.listDimensions.filter(f => f.rindex == rindex)[0]; 286 | if (d) { 287 | d.start = 0; 288 | d.end = 0; 289 | for (let i = rindex + 1; i <= this.listDimensions.length - 1; i++) { 290 | this.listDimensions[i].start = this.listDimensions[i].start - d.height; 291 | this.listDimensions[i].end = this.listDimensions[i].end - d.height; 292 | } 293 | let notDeleted = this.listDimensions.filter(f => f.end > 0); 294 | if (notDeleted.length == 0) { 295 | this.totalHeight = 0; 296 | } 297 | else { 298 | this.totalHeight = notDeleted[notDeleted.length - 1].end; 299 | } 300 | } 301 | } 302 | refresh() { 303 | this.toNextUpdateDimensions = true; 304 | } 305 | //this method may be called if something is wrong in framework logic. For example: in ionic 3, the page component not updated with new data on the inactive tab page. 306 | //The method re-checks all dimensions, add the missing ones and force update component. 307 | forceUpdateComponent() { 308 | this.__didUpdate(true); 309 | } 310 | //Append new dimensions of list item 311 | _testDimensions() { 312 | let nodes = this.el.querySelector('.virtual-slot').childNodes; 313 | if (nodes.length > 0) { 314 | for (let vindex = 0; vindex <= nodes.length - 1; vindex++) { 315 | let node = nodes[vindex]; 316 | let rindex = node['id']; 317 | let d = this.listDimensions.filter(f => f.rindex == rindex)[0]; 318 | if (d && (d.height != node['offsetHeight'])) { 319 | //console.warn("One or more nodes change height after calculation dimensions. Check scroll", rindex); 320 | //console.log('node', node); 321 | //console.log('this.listDimensions[index]', d); 322 | } 323 | } 324 | } 325 | } 326 | componentDidUpdate() { 327 | this.__didUpdate(false); 328 | } 329 | __didUpdate(upd) { 330 | //after component render, need to add new dimensions if virtual nodes, change height 331 | //if is init render need call update virtual, 332 | //if is not init check update height. If height change render again! 333 | let isNewHeight = this._setDimensions(); 334 | // console.log('isNewHeight', isNewHeight) 335 | //if first render finished, recalculate virtual 336 | if (!this.initRender) { 337 | this.initRender = true; 338 | //if use external scroll, need take offset top scroll ellement 339 | if (this.selector.length > 0) { 340 | this.elementOffsetTop = this.el['offsetTop']; 341 | } 342 | this.updateVirtual(); 343 | } 344 | else { 345 | if (isNewHeight || upd) { 346 | //change detection 347 | this.changed = [...this.changed, '']; 348 | } 349 | this._testDimensions(); 350 | } 351 | } 352 | render() { 353 | return (h("div", { class: "vscroll " + (this.selector.length > 0 ? 'external ' : 'inner ') + (this.infinateFinally ? 'infinate-finally ' : ' ') + (this.list.length == 0 ? 'cleared' : '') }, 354 | h("div", { class: "vscroll-back", style: { height: this.totalHeight + 'px' } }), 355 | h("div", { class: "vscroll-content " + (this.selector.length > 0 ? 'external' : 'inner') }, 356 | h("slot", { name: "virtual" })), 357 | h("slot", { name: "loader" }))); 358 | } 359 | static get is() { return "virtual-scroll"; } 360 | static get properties() { return { 361 | "bottomOffset": { 362 | "type": Number, 363 | "attr": "bottom-offset" 364 | }, 365 | "changed": { 366 | "state": true 367 | }, 368 | "clear": { 369 | "method": true 370 | }, 371 | "el": { 372 | "elementRef": true 373 | }, 374 | "forceUpdateComponent": { 375 | "method": true 376 | }, 377 | "list": { 378 | "type": "Any", 379 | "attr": "list", 380 | "watchCallbacks": ["watchHandler"] 381 | }, 382 | "refresh": { 383 | "method": true 384 | }, 385 | "scrollToNode": { 386 | "method": true 387 | }, 388 | "selector": { 389 | "type": String, 390 | "attr": "selector" 391 | }, 392 | "setInfinateFinally": { 393 | "method": true 394 | }, 395 | "setInfinateOn": { 396 | "method": true 397 | }, 398 | "virtualRatio": { 399 | "type": Number, 400 | "attr": "virtual-ratio" 401 | } 402 | }; } 403 | static get events() { return [{ 404 | "name": "toBottom", 405 | "method": "toBottom", 406 | "bubbles": true, 407 | "cancelable": true, 408 | "composed": true 409 | }, { 410 | "name": "update", 411 | "method": "update", 412 | "bubbles": true, 413 | "cancelable": true, 414 | "composed": true 415 | }]; } 416 | static get style() { return "/**style-placeholder:virtual-scroll:**/"; } 417 | } 418 | -------------------------------------------------------------------------------- /dist/collection/components/virtual-scroll/virtual-scroll.scss: -------------------------------------------------------------------------------- 1 | .vscroll.inner { 2 | overflow-y: auto; 3 | height: 100%; 4 | } 5 | 6 | .vscroll.external { 7 | overflow-y: hidden; 8 | } 9 | 10 | .vscroll { 11 | overflow-x: hidden; 12 | position: relative; 13 | display: block; 14 | .vscroll-back { 15 | width: 1px; 16 | opacity: 0; 17 | } 18 | .vscroll-content { 19 | top: 0; 20 | left: 0; 21 | width: 100%; 22 | position: absolute; 23 | } 24 | .vscroll-content.inner { 25 | height: 100%; 26 | } 27 | } 28 | 29 | .infinate-finally { 30 | div[slot='loader'] { 31 | visibility: hidden; 32 | } 33 | } 34 | .cleared { 35 | div[slot='loader'] { 36 | display: none; 37 | } 38 | } 39 | 40 | virual-scroll { 41 | height: 100%; 42 | display: block; 43 | } -------------------------------------------------------------------------------- /dist/collection/index.js: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | -------------------------------------------------------------------------------- /dist/collection/interface.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgnstudio7/stenciljs-virtual-scroll/a041c3f5a4135b131931c6cf156f38ff0f7d1d3d/dist/collection/interface.js -------------------------------------------------------------------------------- /dist/esm/es5/kbufhwni.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | import{h}from"./virtualscroll.core.js";var VirualScrollWebComponent=function(){function t(){this.list=[],this.selector="",this.bottomOffset=0,this.virtualRatio=3,this.changed=[],this.position=0,this.parentScrollHeight=0,this.vscrollOffsetTop=0,this.elementOffsetTop=0,this.infinateOn=!0,this.infinateFinally=!1,this.totalHeight=0,this.listDimensions=[],this.initRender=!1,this.toNextUpdateDimensions=!1,this.scrollEventDispatch=function(){}}return t.prototype.watchHandler=function(t,i){var e=this;if(i.length>0){var n=i.filter(function(i){return 0==t.filter(function(t){return t.index==i.index}).length});n.length>0&&n.map(function(t){e._deleteDimension(t.index)})}this.list.map(function(t,i){t.index||(t.index=i)}),this.updateVirtual(!0),this._setDimensions()},t.prototype.componentDidLoad=function(){var t=this;this._setDefParams(),this.selector.length>0?this.parentScroll=this.el.closest("."+this.selector):this.parentScroll=this.el.querySelector(".vscroll"),this.parentScrollHeight=this.parentScroll.offsetHeight,this.contentEl=this.el.querySelector(".vscroll-content");var i=this.el.querySelector(".vscroll");this.vscrollOffsetTop=i?i.offsetTop:0,this.scrollEventDispatch=this.parentScroll.addEventListener("scroll",function(){t.parentScroll.scrollTop-t.vscrollOffsetTop-t.elementOffsetTop+t.parentScrollHeight<0||(t.position=t.parentScroll.scrollTop-t.vscrollOffsetTop-t.elementOffsetTop,t.updateVirtual())},!1)},t.prototype.unwatch=function(){this.parentScroll&&this.parentScroll.removeEventListener("scroll",this._listener)},t.prototype._listener=function(){this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop,this.updateVirtual()},t.prototype.componentDidUnload=function(){this.unwatch(),this.scrollEventDispatch&&(this.scrollEventDispatch(),this.scrollEventDispatch=null)},t.prototype.componentWillLoad=function(){},t.prototype._setDefParams=function(){this.first=null,this.last=null,this.listDimensions=[],this.totalHeight=0,this.position=0,this.infinateOn=!0,this.infinateFinally=!1},t.prototype.updateVirtual=function(t){var i=this;void 0===t&&(t=!1);var e=this.first?this.first.rindex:0,n=this.last?this.last.rindex:0;if(this.first=this.listDimensions.filter(function(t){return i.position>=t.start&&i.position=t.start&&i.position+i.parentScroll.clientHeight=this.list.length?this.list.length:this.last.rindex+this.virtualRatio,o=this.first.rindex-this.virtualRatio<0?0:this.first.rindex-this.virtualRatio;s==this.list.length&&this.totalHeight-this.position-this.parentScrollHeight<0&&(o=e-this.virtualRatio<0?0:e-this.virtualRatio,this.first=this.listDimensions.filter(function(t){return t.rindex==e})[0]);var l=[];this.list.length>0&&(l=this.list.slice(o,s)),(e!=this.first.rindex||n!=this.last.rindex||t)&&(requestAnimationFrame(function(){var e=i.listDimensions.filter(function(t){return t.rindex==o})[0];e&&(i.contentEl.style.transform="translateY("+e.start+"px)",i.contentEl.style.webkitTransform="translateY("+e.start+"px)"),i.update.emit(l),t&&(i.changed=i.changed.concat([""]))}),this.changed=this.changed.concat([""]))}else if(this.list.length>0){var r=this.list.slice(0,20);this.update.emit(r),this.changed=this.changed.concat([""])}this.last&&this.last.rindex>=this.list.length-1-this.bottomOffset&&this.infinateOn&&!this.infinateFinally&&this.list.length>0&&(this.infinateOn=!1,this.toBottom.emit(this.position))},t.prototype.setInfinateOn=function(){this.infinateOn=!0},t.prototype.setInfinateFinally=function(){this.infinateFinally=!0},t.prototype.clear=function(){var t=this;this._setDefParams(),requestAnimationFrame(function(){t.list=[],t.contentEl.style.transform="translateY(0px)",t.contentEl.style.webkitTransform="translateY(0px)",t.changed=t.changed.concat([""])})},t.prototype.scrollToNode=function(t,i,e){if(void 0===e&&(e=0),this.parentScroll)if(t<=this.listDimensions.length-1){var n=this.listDimensions.filter(function(i){return i.rindex==t})[0];this._scrollTo(n.start+e,i)}else this._scrollToIndex(t)},t.prototype._scrollToIndex=function(t){var i=this;setTimeout(function(){i.parentScroll.scrollTop=i.parentScroll.scrollTop+100,i.first&&i.first.rindex===t||i._scrollToIndex(t)},10)},t.prototype._scrollTo=function(t,i){var e=this;if(!(i<=0)){var n=(t-this.parentScroll.scrollTop)/i*10;setTimeout(function(){e.parentScroll.scrollTop=e.parentScroll.scrollTop+n,e.parentScroll.scrollTop!==t&&e._scrollTo(t,i-10)},10)}},t.prototype._setDimensions=function(){var t=this.totalHeight;this.toNextUpdateDimensions&&(this.listDimensions=[]),this.toNextUpdateDimensions=!1;var i=this.el.querySelectorAll(".virtual-slot .virtual-item");if(i.length>0)for(var e=function(t){var e=i[t],s=e.id;n.listDimensions.filter(function(t){return t.rindex==s})[0]||(n._addNewDimensionToEnd(e.offsetHeight,s),n.totalHeight=n.listDimensions[n.listDimensions.length-1].end)},n=this,s=0;s<=i.length-1;s++)e(s);return this.totalHeight!=t},t.prototype._addNewDimensionToEnd=function(t,i){var e=this.listDimensions.length>0?this.listDimensions[this.listDimensions.length-1].end:0;this.listDimensions.push({height:t,start:e,end:e+t,rindex:parseInt(i)})},t.prototype._deleteDimension=function(t){var i=this.listDimensions.filter(function(i){return i.rindex==t})[0];if(i){i.start=0,i.end=0;for(var e=t+1;e<=this.listDimensions.length-1;e++)this.listDimensions[e].start=this.listDimensions[e].start-i.height,this.listDimensions[e].end=this.listDimensions[e].end-i.height;var n=this.listDimensions.filter(function(t){return t.end>0});0==n.length?this.totalHeight=0:this.totalHeight=n[n.length-1].end}},t.prototype.refresh=function(){this.toNextUpdateDimensions=!0},t.prototype.forceUpdateComponent=function(){this.__didUpdate(!0)},t.prototype._testDimensions=function(){var t=this.el.querySelector(".virtual-slot").childNodes;if(t.length>0)for(var i=function(i){var n=t[i],s=n.id,o=e.listDimensions.filter(function(t){return t.rindex==s})[0];o&&(o.height,n.offsetHeight)},e=this,n=0;n<=t.length-1;n++)i(n)},t.prototype.componentDidUpdate=function(){this.__didUpdate(!1)},t.prototype.__didUpdate=function(t){var i=this._setDimensions();this.initRender?((i||t)&&(this.changed=this.changed.concat([""])),this._testDimensions()):(this.initRender=!0,this.selector.length>0&&(this.elementOffsetTop=this.el.offsetTop),this.updateVirtual())},t.prototype.render=function(){return h("div",{class:"vscroll "+(this.selector.length>0?"external ":"inner ")+(this.infinateFinally?"infinate-finally ":" ")+(0==this.list.length?"cleared":"")},h("div",{class:"vscroll-back",style:{height:this.totalHeight+"px"}}),h("div",{class:"vscroll-content "+(this.selector.length>0?"external":"inner")},h("slot",{name:"virtual"})),h("slot",{name:"loader"}))},Object.defineProperty(t,"is",{get:function(){return"virtual-scroll"},enumerable:!0,configurable:!0}),Object.defineProperty(t,"properties",{get:function(){return{bottomOffset:{type:Number,attr:"bottom-offset"},changed:{state:!0},clear:{method:!0},el:{elementRef:!0},forceUpdateComponent:{method:!0},list:{type:"Any",attr:"list",watchCallbacks:["watchHandler"]},refresh:{method:!0},scrollToNode:{method:!0},selector:{type:String,attr:"selector"},setInfinateFinally:{method:!0},setInfinateOn:{method:!0},virtualRatio:{type:Number,attr:"virtual-ratio"}}},enumerable:!0,configurable:!0}),Object.defineProperty(t,"events",{get:function(){return[{name:"toBottom",method:"toBottom",bubbles:!0,cancelable:!0,composed:!0},{name:"update",method:"update",bubbles:!0,cancelable:!0,composed:!0}]},enumerable:!0,configurable:!0}),Object.defineProperty(t,"style",{get:function(){return".vscroll.inner{overflow-y:auto;height:100%}.vscroll.external{overflow-y:hidden}.vscroll{overflow-x:hidden;position:relative;display:block}.vscroll .vscroll-back{width:1px;opacity:0}.vscroll .vscroll-content{top:0;left:0;width:100%;position:absolute}.vscroll .vscroll-content.inner{height:100%}.infinate-finally div[slot=loader]{visibility:hidden}.cleared div[slot=loader]{display:none}virual-scroll{height:100%;display:block}"},enumerable:!0,configurable:!0}),t}();export{VirualScrollWebComponent as VirtualScroll}; -------------------------------------------------------------------------------- /dist/esm/es5/nqhdrz5d.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | import{h}from"./virtualscroll.core.js";var FetchHelperWebComponent=function(){function e(){this.list=[],this.selector="",this.virtual=[],this.changed=[]}return e.prototype.componentWillLoad=function(){this.request()},e.prototype.request=function(){var e=this,t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json",token:"kRuGZ3Xd"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,n.addEventListener("toBottom",function(){e.lazyRequest()}),n.addEventListener("update",function(t){console.log("update"),e.virtual=t.detail,e.changed=e.changed.concat([""])})})},e.prototype.lazyRequest=function(){var e=this,t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){setTimeout(function(){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,e.list.length>200?n.setInfinateFinally():n.setInfinateOn()},3e3)})},e.prototype.reload=function(){var e=this,t=this.el.querySelector("virtual-scroll");t.list=[],t.clear(),this.changed=this.changed.concat([""]),setTimeout(function(){var t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,e.list.length>200?n.setInfinateFinally():n.setInfinateOn()})},2e3)},e.prototype.scrolling=function(){this.el.querySelector("virtual-scroll").scrollToNode(25,1e3,-50)},e.prototype.render=function(){return[h("div",{onClick:this.reload.bind(this),class:"reload"},"reload"),h("div",{onClick:this.scrolling.bind(this),class:"scrolling"},"scrolling"),h("div",{class:"virtual-container"},h("virtual-scroll",{"bottom-offset":"5","virtual-ratio":"15",selector:this.selector},h("div",{slot:"virtual",class:"virtual-slot"},this.virtual.map(function(e){return h("div",{class:"offer virtual-item",id:e.index},h("div",{style:{backgroundImage:"url("+e.thumbnailUrl+")"},class:"cover"}),h("div",{class:"title"},e.index),h("div",{class:"title"},e.title))})),h("div",{slot:"loader"},"loading...")))]},Object.defineProperty(e,"is",{get:function(){return"fetch-helper"},enumerable:!0,configurable:!0}),Object.defineProperty(e,"properties",{get:function(){return{changed:{state:!0},el:{elementRef:!0},list:{state:!0},selector:{type:String,attr:"selector"}}},enumerable:!0,configurable:!0}),Object.defineProperty(e,"style",{get:function(){return".cover{position:relative;width:150px;height:150px;background-size:cover;margin:0 auto}.title{font-size:15px;height:40px;text-align:center}.cover:after{content:\"\";display:block;padding-bottom:67%}.reload,.scrolling{position:absolute;top:0;margin:10px;padding:10px;background:#ccc;cursor:pointer;z-index:1}.scrolling{right:0}.reload{left:0}"},enumerable:!0,configurable:!0}),e}();export{FetchHelperWebComponent as FetchHelper}; -------------------------------------------------------------------------------- /dist/esm/es5/polyfills/array.js: -------------------------------------------------------------------------------- 1 | export function applyPolyfill(window, document) { 2 | /*! 3 | Array.prototype.find 4 | */ 5 | Array.prototype.find||Object.defineProperty(Array.prototype,"find",{writable:!0,configurable:!0,value:function(c,e){if(null==this)throw new TypeError('"this" is null or not defined');var b=Object(this),f=b.length>>>0;if("function"!==typeof c)throw new TypeError("predicate must be a function");for(var a=0;a>>0;if(0===n)return!1;var i,o,a=0|e,u=Math.max(0<=a?a:n-Math.abs(a),0);for(;u1)&&Zt(this)}}}),ot(u,h,{value:function(e){-1<_.call(a,e)&&o[h].apply(this,arguments)}}),o[d]&&ot(u,p,{value:o[d]}),o[v]&&ot(u,g,{value:o[v]}),i&&(f[c]=i),e=e.toUpperCase(),G[e]={constructor:t,create:i?[i,et(e)]:[e]},Z.set(t,e),n[s](e.toLowerCase(),f),en(e),Y[e].r()}function Gt(e){var t=G[e.toUpperCase()];return t&&t.constructor}function Yt(e){return typeof e=="string"?e:e&&e.is||""}function Zt(e){var t=e[h],n=t?e.attributes:j,r=n.length,i;while(r--)i=n[r],t.call(e,i.name||i.nodeName,null,i.value||i.nodeValue)}function en(e){return e=e.toUpperCase(),e in Y||(Y[e]={},Y[e].p=new K(function(t){Y[e].r=t})),Y[e].p}function tn(){X&&delete e.customElements,B(e,"customElements",{configurable:!0,value:new Kt}),B(e,"CustomElementRegistry",{configurable:!0,value:Kt});for(var t=function(t){var r=e[t];if(r){e[t]=function(t){var i,s;return t||(t=this),t[W]||(Q=!0,i=G[Z.get(t.constructor)],s=V&&i.create.length===1,t=s?Reflect.construct(r,j,i.constructor):n.createElement.apply(n,i.create),t[W]=!0,Q=!1,s||Zt(t)),t},e[t].prototype=r.prototype;try{r.prototype.constructor=e[t]}catch(i){z=!0,B(r,W,{value:e[t]})}}},r=i.get(/^HTML[A-Z]*[a-z]/),o=r.length;o--;t(r[o]));n.createElement=function(e,t){var n=Yt(t);return n?gt.call(this,e,et(n)):gt.call(this,e)},St||(Tt=!0,n[s](""))}var n=e.document,r=e.Object,i=function(e){var t=/^[A-Z]+[a-z]/,n=function(e){var t=[],n;for(n in s)e.test(n)&&t.push(n);return t},i=function(e,t){t=t.toLowerCase(),t in s||(s[e]=(s[e]||[]).concat(t),s[t]=s[t.toUpperCase()]=e)},s=(r.create||r)(null),o={},u,a,f,l;for(a in e)for(l in e[a]){f=e[a][l],s[l]=f;for(u=0;u>0),u="addEventListener",a="attached",f="Callback",l="detached",c="extends",h="attributeChanged"+f,p=a+f,d="connected"+f,v="disconnected"+f,m="created"+f,g=l+f,y="ADDITION",b="MODIFICATION",w="REMOVAL",E="DOMAttrModified",S="DOMContentLoaded",x="DOMSubtreeModified",T="<",N="=",C=/^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,k=["ANNOTATION-XML","COLOR-PROFILE","FONT-FACE","FONT-FACE-SRC","FONT-FACE-URI","FONT-FACE-FORMAT","FONT-FACE-NAME","MISSING-GLYPH"],L=[],A=[],O="",M=n.documentElement,_=L.indexOf||function(e){for(var t=this.length;t--&&this[t]!==e;);return t},D=r.prototype,P=D.hasOwnProperty,H=D.isPrototypeOf,B=r.defineProperty,j=[],F=r.getOwnPropertyDescriptor,I=r.getOwnPropertyNames,q=r.getPrototypeOf,R=r.setPrototypeOf,U=!!r.__proto__,z=!1,W="__dreCEv1",X=e.customElements,V=!/^force/.test(t.type)&&!!(X&&X.define&&X.get&&X.whenDefined),$=r.create||r,J=e.Map||function(){var t=[],n=[],r;return{get:function(e){return n[_.call(t,e)]},set:function(e,i){r=_.call(t,e),r<0?n[t.push(e)-1]=i:n[r]=i}}},K=e.Promise||function(e){function i(e){n=!0;while(t.length)t.shift()(e)}var t=[],n=!1,r={"catch":function(){return r},then:function(e){return t.push(e),n&&setTimeout(i,1),r}};return e(i),r},Q=!1,G=$(null),Y=$(null),Z=new J,et=function(e){return e.toLowerCase()},tt=r.create||function sn(e){return e?(sn.prototype=e,new sn):this},nt=R||(U?function(e,t){return e.__proto__=t,e}:I&&F?function(){function e(e,t){for(var n,r=I(t),i=0,s=r.length;ithis.status;this.statusText="statusText"in b?b.statusText:"OK";this.headers=new d(b.headers);this.url=b.url||"";this._initBody(a)}if(!e.fetch){var D="Symbol"in e&&"iterator"in Symbol,m;if(m="FileReader"in e&&"Blob"in e)try{new Blob,m=!0}catch(a){m=!1}var g={searchParams:"URLSearchParams"in e,iterable:D, 16 | blob:m,formData:"FormData"in e,arrayBuffer:"ArrayBuffer"in e};if(g.arrayBuffer){var E="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";");var y=function(a){return a&&DataView.prototype.isPrototypeOf(a)};var z=ArrayBuffer.isView||function(a){return a&&-1this.length)a=this.length;return this.substring(a-b.length,a)===b}}); 6 | /*! 7 | String.prototype.includes 8 | */ 9 | String.prototype.includes||(String.prototype.includes=function(b,a){"number"!==typeof a&&(a=0);return a+b.length>this.length?!1:-1!==this.indexOf(b,a)}); 10 | /*! 11 | String.prototype.startsWith 12 | */ 13 | String.prototype.startsWith||Object.defineProperty(String.prototype,"startsWith",{writable:!0,configurable:!0,value:function(b,a){return this.substr(!a||0>a?0:+a,b.length)===b}}); 14 | } -------------------------------------------------------------------------------- /dist/esm/es5/virtualscroll.components.js: -------------------------------------------------------------------------------- 1 | // virtualscroll: Host Data, ES Module/ES5 Target 2 | 3 | export var FetchHelperWebComponent = ["fetch-helper",function(){return(import("./nqhdrz5d.js")).then(function(m){return m.FetchHelper})},1,[["changed",5],["el",7],["list",5],["selector",1,0,1,2]]]; 4 | 5 | export var VirualScrollWebComponent = ["virtual-scroll",function(){return(import("./kbufhwni.js")).then(function(m){return m.VirtualScroll})},1,[["bottomOffset",1,0,"bottom-offset",4],["changed",5],["clear",6],["el",7],["forceUpdateComponent",6],["list",1],["refresh",6],["scrollToNode",6],["selector",1,0,1,2],["setInfinateFinally",6],["setInfinateOn",6],["virtualRatio",1,0,"virtual-ratio",4]]]; -------------------------------------------------------------------------------- /dist/esm/es5/virtualscroll.define.js: -------------------------------------------------------------------------------- 1 | // virtualscroll: Custom Elements Define Library, ES Module/ES5 Target 2 | import { defineCustomElement } from './virtualscroll.core.js'; 3 | import { 4 | FetchHelperWebComponent, 5 | VirualScrollWebComponent 6 | } from './virtualscroll.components.js'; 7 | 8 | export function defineCustomElements(window, opts) { 9 | defineCustomElement(window, [ 10 | FetchHelperWebComponent, 11 | VirualScrollWebComponent 12 | ], opts); 13 | } -------------------------------------------------------------------------------- /dist/esm/es5/virtualscroll.global.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | export default function appGlobal(namespace, Context, window, document, resourcesUrl, hydratedCssClass) { 3 | } -------------------------------------------------------------------------------- /dist/esm/index.js: -------------------------------------------------------------------------------- 1 | // virtualscroll: ES Module 2 | export * from './es5/virtualscroll.define.js'; 3 | export * from '../collection/index.js'; -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | // virtualscroll: CommonJS Main -------------------------------------------------------------------------------- /dist/types/components.d.ts: -------------------------------------------------------------------------------- 1 | import './stencil.core'; 2 | /** 3 | * This is an autogenerated file created by the Stencil compiler. 4 | * It contains typing information for all components that exist in this project. 5 | */ 6 | 7 | import './stencil.core'; 8 | 9 | declare global { 10 | namespace JSX { 11 | interface Element {} 12 | export interface IntrinsicElements {} 13 | } 14 | namespace JSXElements {} 15 | 16 | interface HTMLElement { 17 | componentOnReady?: () => Promise; 18 | } 19 | 20 | interface HTMLStencilElement extends HTMLElement { 21 | componentOnReady(): Promise; 22 | 23 | forceUpdate(): void; 24 | } 25 | 26 | interface HTMLAttributes {} 27 | } 28 | 29 | import { 30 | EventEmitter, 31 | } from './stencil.core'; 32 | 33 | declare global { 34 | 35 | namespace StencilComponents { 36 | interface FetchHelper { 37 | 'selector': string; 38 | } 39 | } 40 | 41 | interface HTMLFetchHelperElement extends StencilComponents.FetchHelper, HTMLStencilElement {} 42 | 43 | var HTMLFetchHelperElement: { 44 | prototype: HTMLFetchHelperElement; 45 | new (): HTMLFetchHelperElement; 46 | }; 47 | interface HTMLElementTagNameMap { 48 | 'fetch-helper': HTMLFetchHelperElement; 49 | } 50 | interface ElementTagNameMap { 51 | 'fetch-helper': HTMLFetchHelperElement; 52 | } 53 | namespace JSX { 54 | interface IntrinsicElements { 55 | 'fetch-helper': JSXElements.FetchHelperAttributes; 56 | } 57 | } 58 | namespace JSXElements { 59 | export interface FetchHelperAttributes extends HTMLAttributes { 60 | 'selector'?: string; 61 | } 62 | } 63 | } 64 | 65 | 66 | declare global { 67 | 68 | namespace StencilComponents { 69 | interface VirtualScroll { 70 | 'bottomOffset': number; 71 | 'clear': () => void; 72 | 'forceUpdateComponent': () => void; 73 | 'list': Array; 74 | 'refresh': () => void; 75 | 'scrollToNode': (index: number, speed: number, offset?: number) => void; 76 | 'selector': string; 77 | 'setInfinateFinally': () => void; 78 | 'setInfinateOn': () => void; 79 | 'virtualRatio': number; 80 | } 81 | } 82 | 83 | interface HTMLVirtualScrollElement extends StencilComponents.VirtualScroll, HTMLStencilElement {} 84 | 85 | var HTMLVirtualScrollElement: { 86 | prototype: HTMLVirtualScrollElement; 87 | new (): HTMLVirtualScrollElement; 88 | }; 89 | interface HTMLElementTagNameMap { 90 | 'virtual-scroll': HTMLVirtualScrollElement; 91 | } 92 | interface ElementTagNameMap { 93 | 'virtual-scroll': HTMLVirtualScrollElement; 94 | } 95 | namespace JSX { 96 | interface IntrinsicElements { 97 | 'virtual-scroll': JSXElements.VirtualScrollAttributes; 98 | } 99 | } 100 | namespace JSXElements { 101 | export interface VirtualScrollAttributes extends HTMLAttributes { 102 | 'bottomOffset'?: number; 103 | 'list'?: Array; 104 | 'onToBottom'?: (event: CustomEvent) => void; 105 | 'onUpdate'?: (event: CustomEvent>) => void; 106 | 'selector'?: string; 107 | 'virtualRatio'?: number; 108 | } 109 | } 110 | } 111 | 112 | declare global { namespace JSX { interface StencilJSX {} } } 113 | 114 | export declare function defineCustomElements(window: any): void; -------------------------------------------------------------------------------- /dist/types/components/fetch-helper/fetch-helper.d.ts: -------------------------------------------------------------------------------- 1 | export declare class FetchHelperWebComponent { 2 | list: Array; 3 | el: HTMLElement; 4 | selector: string; 5 | private virtual; 6 | changed: string[]; 7 | componentWillLoad(): void; 8 | request(): void; 9 | lazyRequest(): void; 10 | reload(): void; 11 | scrolling(): void; 12 | render(): JSX.Element[]; 13 | } 14 | -------------------------------------------------------------------------------- /dist/types/components/virtual-scroll/virtual-scroll.d.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from '@stencil/core'; 2 | export declare class VirualScrollWebComponent { 3 | list: Array; 4 | selector: string; 5 | bottomOffset: number; 6 | virtualRatio: number; 7 | changed: string[]; 8 | el: HTMLElement; 9 | private contentEl; 10 | private position; 11 | private parentScroll; 12 | private parentScrollHeight; 13 | private vscrollOffsetTop; 14 | private elementOffsetTop; 15 | toBottom: EventEmitter; 16 | update: EventEmitter>; 17 | private infinateOn; 18 | private infinateFinally; 19 | private totalHeight; 20 | private first; 21 | private last; 22 | private listDimensions; 23 | private initRender; 24 | private toNextUpdateDimensions; 25 | private scrollEventDispatch; 26 | watchHandler(newValue: Array, oldValue: Array): void; 27 | componentDidLoad(): void; 28 | unwatch(): void; 29 | private _listener; 30 | componentDidUnload(): void; 31 | componentWillLoad(): void; 32 | private _setDefParams; 33 | updateVirtual(update?: boolean): void; 34 | setInfinateOn(): void; 35 | setInfinateFinally(): void; 36 | clear(): void; 37 | scrollToNode(index: number, speed: number, offset?: number): void; 38 | private _scrollToIndex; 39 | private _scrollTo; 40 | private _setDimensions; 41 | private _addNewDimensionToEnd; 42 | private _deleteDimension; 43 | refresh(): void; 44 | forceUpdateComponent(): void; 45 | private _testDimensions; 46 | componentDidUpdate(): void; 47 | __didUpdate(upd: any): void; 48 | render(): JSX.Element; 49 | } 50 | -------------------------------------------------------------------------------- /dist/types/index.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgnstudio7/stenciljs-virtual-scroll/a041c3f5a4135b131931c6cf156f38ff0f7d1d3d/dist/types/index.d.ts -------------------------------------------------------------------------------- /dist/types/stencil.core.d.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface ComponentWillLoad { 3 | componentWillLoad: () => Promise | void; 4 | } 5 | 6 | export interface ComponentDidLoad { 7 | componentDidLoad: () => void; 8 | } 9 | 10 | export interface ComponentWillUpdate { 11 | componentWillUpdate: () => Promise | void; 12 | } 13 | 14 | export interface ComponentDidUpdate { 15 | componentDidUpdate: () => void; 16 | } 17 | 18 | export interface ComponentDidUnload { 19 | componentDidUnload: () => void; 20 | } 21 | 22 | export interface EventEmitter { 23 | emit: (data?: T) => void; 24 | } 25 | 26 | export interface EventListenerEnable { 27 | (instance: any, eventName: string, enabled: boolean, attachTo?: string|Element, passive?: boolean): void; 28 | } 29 | 30 | declare global { 31 | namespace JSX { 32 | interface Element {} 33 | export interface IntrinsicElements {} 34 | } 35 | namespace JSXElements {} 36 | 37 | interface HTMLStencilElement extends HTMLElement { 38 | componentOnReady(): Promise; 39 | componentOnReady(done: (ele?: this) => void): void; 40 | } 41 | 42 | interface HTMLAttributes {} 43 | } 44 | -------------------------------------------------------------------------------- /dist/virtualscroll.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Built with http://stenciljs.com 3 | * 2018-05-26T07:12:00 4 | */ 5 | !function(e,t,r,n,o,s,i,l,c,a,u,d,f,p){for((u=e.virtualscroll=e.virtualscroll||{}).components=c,(f=c.filter(function(e){return e[2]}).map(function(e){return e[0]})).length&&((d=t.createElement("style")).innerHTML=f.join()+"{visibility:hidden}.hydrated{visibility:inherit}",d.setAttribute("data-styles",""),t.head.insertBefore(d,t.head.firstChild)),function(e,t,r){(e["s-apps"]=e["s-apps"]||[]).push("virtualscroll"),r.componentOnReady||(r.componentOnReady=function(){var t=this;function r(r){if(t.nodeName.indexOf("-")>0){for(var n=e["s-apps"],o=0,s=0;s=0&&!(p=f[d]).src&&!p.hasAttribute("data-resources-url");d--);f=p.getAttribute("data-resources-url"),!o&&f&&(o=f),!o&&p.src&&(o=(f=p.src.split("/").slice(0,-1)).join("/")+(f.length?"/":"")+"virtualscroll/"),d=t.createElement("script"),function(e,t,r,n){return!(t.search.indexOf("core=esm")>0)&&(!(!(t.search.indexOf("core=es5")>0||"file:"===t.protocol)&&e.customElements&&e.customElements.define&&e.fetch&&e.CSS&&e.CSS.supports&&e.CSS.supports("color","var(--c)")&&"noModule"in r)||function(e){try{return new Function('import("")'),!1}catch(e){}return!0}())}(e,e.location,d)?d.src=o+"virtualscroll.etffcq0f.js":(d.src=o+"virtualscroll.4u6xzod9.js",d.setAttribute("type","module"),d.setAttribute("crossorigin",!0)),d.setAttribute("data-resources-url",o),d.setAttribute("data-namespace","virtualscroll"),t.head.appendChild(d)}(window,document,0,0,0,0,0,0,[["fetch-helper","nqhdrz5d",1,[["changed",5],["el",7],["list",5],["selector",1,0,1,2]]],["virtual-scroll","kbufhwni",1,[["bottomOffset",1,0,"bottom-offset",4],["changed",5],["clear",6],["el",7],["forceUpdateComponent",6],["list",1],["refresh",6],["scrollToNode",6],["selector",1,0,1,2],["setInfinateFinally",6],["setInfinateOn",6],["virtualRatio",1,0,"virtual-ratio",4]]]],HTMLElement.prototype); -------------------------------------------------------------------------------- /dist/virtualscroll/kbufhwni.es5.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | virtualscroll.loadBundle("kbufhwni",["exports"],function(t){var i=window.virtualscroll.h,e=function(){function t(){this.list=[],this.selector="",this.bottomOffset=0,this.virtualRatio=3,this.changed=[],this.position=0,this.parentScrollHeight=0,this.vscrollOffsetTop=0,this.elementOffsetTop=0,this.infinateOn=!0,this.infinateFinally=!1,this.totalHeight=0,this.listDimensions=[],this.initRender=!1,this.toNextUpdateDimensions=!1,this.scrollEventDispatch=function(){}}return t.prototype.watchHandler=function(t,i){var e=this;if(i.length>0){var n=i.filter(function(i){return 0==t.filter(function(t){return t.index==i.index}).length});n.length>0&&n.map(function(t){e._deleteDimension(t.index)})}this.list.map(function(t,i){t.index||(t.index=i)}),this.updateVirtual(!0),this._setDimensions()},t.prototype.componentDidLoad=function(){var t=this;this._setDefParams(),this.selector.length>0?this.parentScroll=this.el.closest("."+this.selector):this.parentScroll=this.el.querySelector(".vscroll"),this.parentScrollHeight=this.parentScroll.offsetHeight,this.contentEl=this.el.querySelector(".vscroll-content");var i=this.el.querySelector(".vscroll");this.vscrollOffsetTop=i?i.offsetTop:0,this.scrollEventDispatch=this.parentScroll.addEventListener("scroll",function(){t.parentScroll.scrollTop-t.vscrollOffsetTop-t.elementOffsetTop+t.parentScrollHeight<0||(t.position=t.parentScroll.scrollTop-t.vscrollOffsetTop-t.elementOffsetTop,t.updateVirtual())},!1)},t.prototype.unwatch=function(){this.parentScroll&&this.parentScroll.removeEventListener("scroll",this._listener)},t.prototype._listener=function(){this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop,this.updateVirtual()},t.prototype.componentDidUnload=function(){this.unwatch(),this.scrollEventDispatch&&(this.scrollEventDispatch(),this.scrollEventDispatch=null)},t.prototype.componentWillLoad=function(){},t.prototype._setDefParams=function(){this.first=null,this.last=null,this.listDimensions=[],this.totalHeight=0,this.position=0,this.infinateOn=!0,this.infinateFinally=!1},t.prototype.updateVirtual=function(t){var i=this;void 0===t&&(t=!1);var e=this.first?this.first.rindex:0,n=this.last?this.last.rindex:0;if(this.first=this.listDimensions.filter(function(t){return i.position>=t.start&&i.position=t.start&&i.position+i.parentScroll.clientHeight=this.list.length?this.list.length:this.last.rindex+this.virtualRatio,o=this.first.rindex-this.virtualRatio<0?0:this.first.rindex-this.virtualRatio;s==this.list.length&&this.totalHeight-this.position-this.parentScrollHeight<0&&(o=e-this.virtualRatio<0?0:e-this.virtualRatio,this.first=this.listDimensions.filter(function(t){return t.rindex==e})[0]);var l=[];this.list.length>0&&(l=this.list.slice(o,s)),(e!=this.first.rindex||n!=this.last.rindex||t)&&(requestAnimationFrame(function(){var e=i.listDimensions.filter(function(t){return t.rindex==o})[0];e&&(i.contentEl.style.transform="translateY("+e.start+"px)",i.contentEl.style.webkitTransform="translateY("+e.start+"px)"),i.update.emit(l),t&&(i.changed=i.changed.concat([""]))}),this.changed=this.changed.concat([""]))}else if(this.list.length>0){var r=this.list.slice(0,20);this.update.emit(r),this.changed=this.changed.concat([""])}this.last&&this.last.rindex>=this.list.length-1-this.bottomOffset&&this.infinateOn&&!this.infinateFinally&&this.list.length>0&&(this.infinateOn=!1,this.toBottom.emit(this.position))},t.prototype.setInfinateOn=function(){this.infinateOn=!0},t.prototype.setInfinateFinally=function(){this.infinateFinally=!0},t.prototype.clear=function(){var t=this;this._setDefParams(),requestAnimationFrame(function(){t.list=[],t.contentEl.style.transform="translateY(0px)",t.contentEl.style.webkitTransform="translateY(0px)",t.changed=t.changed.concat([""])})},t.prototype.scrollToNode=function(t,i,e){if(void 0===e&&(e=0),this.parentScroll)if(t<=this.listDimensions.length-1){var n=this.listDimensions.filter(function(i){return i.rindex==t})[0];this._scrollTo(n.start+e,i)}else this._scrollToIndex(t)},t.prototype._scrollToIndex=function(t){var i=this;setTimeout(function(){i.parentScroll.scrollTop=i.parentScroll.scrollTop+100,i.first&&i.first.rindex===t||i._scrollToIndex(t)},10)},t.prototype._scrollTo=function(t,i){var e=this;if(!(i<=0)){var n=(t-this.parentScroll.scrollTop)/i*10;setTimeout(function(){e.parentScroll.scrollTop=e.parentScroll.scrollTop+n,e.parentScroll.scrollTop!==t&&e._scrollTo(t,i-10)},10)}},t.prototype._setDimensions=function(){var t=this.totalHeight;this.toNextUpdateDimensions&&(this.listDimensions=[]),this.toNextUpdateDimensions=!1;var i=this.el.querySelectorAll(".virtual-slot .virtual-item");if(i.length>0)for(var e=function(t){var e=i[t],s=e.id;n.listDimensions.filter(function(t){return t.rindex==s})[0]||(n._addNewDimensionToEnd(e.offsetHeight,s),n.totalHeight=n.listDimensions[n.listDimensions.length-1].end)},n=this,s=0;s<=i.length-1;s++)e(s);return this.totalHeight!=t},t.prototype._addNewDimensionToEnd=function(t,i){var e=this.listDimensions.length>0?this.listDimensions[this.listDimensions.length-1].end:0;this.listDimensions.push({height:t,start:e,end:e+t,rindex:parseInt(i)})},t.prototype._deleteDimension=function(t){var i=this.listDimensions.filter(function(i){return i.rindex==t})[0];if(i){i.start=0,i.end=0;for(var e=t+1;e<=this.listDimensions.length-1;e++)this.listDimensions[e].start=this.listDimensions[e].start-i.height,this.listDimensions[e].end=this.listDimensions[e].end-i.height;var n=this.listDimensions.filter(function(t){return t.end>0});0==n.length?this.totalHeight=0:this.totalHeight=n[n.length-1].end}},t.prototype.refresh=function(){this.toNextUpdateDimensions=!0},t.prototype.forceUpdateComponent=function(){this.__didUpdate(!0)},t.prototype._testDimensions=function(){var t=this.el.querySelector(".virtual-slot").childNodes;if(t.length>0)for(var i=function(i){var n=t[i],s=n.id,o=e.listDimensions.filter(function(t){return t.rindex==s})[0];o&&(o.height,n.offsetHeight)},e=this,n=0;n<=t.length-1;n++)i(n)},t.prototype.componentDidUpdate=function(){this.__didUpdate(!1)},t.prototype.__didUpdate=function(t){var i=this._setDimensions();this.initRender?((i||t)&&(this.changed=this.changed.concat([""])),this._testDimensions()):(this.initRender=!0,this.selector.length>0&&(this.elementOffsetTop=this.el.offsetTop),this.updateVirtual())},t.prototype.render=function(){return i("div",{class:"vscroll "+(this.selector.length>0?"external ":"inner ")+(this.infinateFinally?"infinate-finally ":" ")+(0==this.list.length?"cleared":"")},i("div",{class:"vscroll-back",style:{height:this.totalHeight+"px"}}),i("div",{class:"vscroll-content "+(this.selector.length>0?"external":"inner")},i("slot",{name:"virtual"})),i("slot",{name:"loader"}))},Object.defineProperty(t,"is",{get:function(){return"virtual-scroll"},enumerable:!0,configurable:!0}),Object.defineProperty(t,"properties",{get:function(){return{bottomOffset:{type:Number,attr:"bottom-offset"},changed:{state:!0},clear:{method:!0},el:{elementRef:!0},forceUpdateComponent:{method:!0},list:{type:"Any",attr:"list",watchCallbacks:["watchHandler"]},refresh:{method:!0},scrollToNode:{method:!0},selector:{type:String,attr:"selector"},setInfinateFinally:{method:!0},setInfinateOn:{method:!0},virtualRatio:{type:Number,attr:"virtual-ratio"}}},enumerable:!0,configurable:!0}),Object.defineProperty(t,"events",{get:function(){return[{name:"toBottom",method:"toBottom",bubbles:!0,cancelable:!0,composed:!0},{name:"update",method:"update",bubbles:!0,cancelable:!0,composed:!0}]},enumerable:!0,configurable:!0}),Object.defineProperty(t,"style",{get:function(){return".vscroll.inner{overflow-y:auto;height:100%}.vscroll.external{overflow-y:hidden}.vscroll{overflow-x:hidden;position:relative;display:block}.vscroll .vscroll-back{width:1px;opacity:0}.vscroll .vscroll-content{top:0;left:0;width:100%;position:absolute}.vscroll .vscroll-content.inner{height:100%}.infinate-finally div[slot=loader]{visibility:hidden}.cleared div[slot=loader]{display:none}virual-scroll{height:100%;display:block}"},enumerable:!0,configurable:!0}),t}();t.VirtualScroll=e,Object.defineProperty(t,"__esModule",{value:!0})}); -------------------------------------------------------------------------------- /dist/virtualscroll/kbufhwni.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | const{h:t}=window.virtualscroll;class i{constructor(){this.list=[],this.selector="",this.bottomOffset=0,this.virtualRatio=3,this.changed=[],this.position=0,this.parentScrollHeight=0,this.vscrollOffsetTop=0,this.elementOffsetTop=0,this.infinateOn=!0,this.infinateFinally=!1,this.totalHeight=0,this.listDimensions=[],this.initRender=!1,this.toNextUpdateDimensions=!1,this.scrollEventDispatch=(()=>void 0)}watchHandler(t,i){if(i.length>0){let s=i.filter(i=>0==t.filter(t=>t.index==i.index).length);s.length>0&&s.map(t=>{this._deleteDimension(t.index)})}this.list.map((t,i)=>{t.index||(t.index=i)}),this.updateVirtual(!0),this._setDimensions()}componentDidLoad(){this._setDefParams(),this.selector.length>0?this.parentScroll=this.el.closest("."+this.selector):this.parentScroll=this.el.querySelector(".vscroll"),this.parentScrollHeight=this.parentScroll.offsetHeight,this.contentEl=this.el.querySelector(".vscroll-content");let t=this.el.querySelector(".vscroll");this.vscrollOffsetTop=t?t.offsetTop:0,this.scrollEventDispatch=this.parentScroll.addEventListener("scroll",()=>{this.parentScroll.scrollTop-this.vscrollOffsetTop-this.elementOffsetTop+this.parentScrollHeight<0||(this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop-this.elementOffsetTop,this.updateVirtual())},!1)}unwatch(){this.parentScroll&&this.parentScroll.removeEventListener("scroll",this._listener)}_listener(){this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop,this.updateVirtual()}componentDidUnload(){this.unwatch(),this.scrollEventDispatch&&(this.scrollEventDispatch(),this.scrollEventDispatch=null)}componentWillLoad(){}_setDefParams(){this.first=null,this.last=null,this.listDimensions=[],this.totalHeight=0,this.position=0,this.infinateOn=!0,this.infinateFinally=!1}updateVirtual(t=!1){let i=this.first?this.first.rindex:0,s=this.last?this.last.rindex:0;if(this.first=this.listDimensions.filter(t=>this.position>=t.start&&this.positionthis.position+this.parentScroll.clientHeight>=t.start&&this.position+this.parentScroll.clientHeight=this.list.length?this.list.length:this.last.rindex+this.virtualRatio,l=this.first.rindex-this.virtualRatio<0?0:this.first.rindex-this.virtualRatio;e==this.list.length&&this.totalHeight-this.position-this.parentScrollHeight<0&&(l=i-this.virtualRatio<0?0:i-this.virtualRatio,this.first=this.listDimensions.filter(t=>t.rindex==i)[0]);let n=[];this.list.length>0&&(n=this.list.slice(l,e)),(i!=this.first.rindex||s!=this.last.rindex||t)&&(requestAnimationFrame(()=>{let i=this.listDimensions.filter(t=>t.rindex==l)[0];i&&(this.contentEl.style.transform="translateY("+i.start+"px)",this.contentEl.style.webkitTransform="translateY("+i.start+"px)"),this.update.emit(n),t&&(this.changed=[...this.changed,""])}),this.changed=[...this.changed,""])}else if(this.list.length>0){let t=this.list.slice(0,20);this.update.emit(t),this.changed=[...this.changed,""]}this.last&&this.last.rindex>=this.list.length-1-this.bottomOffset&&this.infinateOn&&!this.infinateFinally&&this.list.length>0&&(this.infinateOn=!1,this.toBottom.emit(this.position))}setInfinateOn(){this.infinateOn=!0}setInfinateFinally(){this.infinateFinally=!0}clear(){this._setDefParams(),requestAnimationFrame(()=>{this.list=[],this.contentEl.style.transform="translateY(0px)",this.contentEl.style.webkitTransform="translateY(0px)",this.changed=[...this.changed,""]})}scrollToNode(t,i,s=0){if(this.parentScroll)if(t<=this.listDimensions.length-1){let e=this.listDimensions.filter(i=>i.rindex==t)[0];this._scrollTo(e.start+s,i)}else this._scrollToIndex(t)}_scrollToIndex(t){setTimeout(()=>{this.parentScroll.scrollTop=this.parentScroll.scrollTop+100,this.first&&this.first.rindex===t||this._scrollToIndex(t)},10)}_scrollTo(t,i){if(i<=0)return;let s=(t-this.parentScroll.scrollTop)/i*10;setTimeout(()=>{this.parentScroll.scrollTop=this.parentScroll.scrollTop+s,this.parentScroll.scrollTop!==t&&this._scrollTo(t,i-10)},10)}_setDimensions(){let t=this.totalHeight;this.toNextUpdateDimensions&&(this.listDimensions=[]),this.toNextUpdateDimensions=!1;let i=this.el.querySelectorAll(".virtual-slot .virtual-item");if(i.length>0)for(let t=0;t<=i.length-1;t++){let s=i[t],e=s.id;this.listDimensions.filter(t=>t.rindex==e)[0]||(this._addNewDimensionToEnd(s.offsetHeight,e),this.totalHeight=this.listDimensions[this.listDimensions.length-1].end)}return this.totalHeight!=t}_addNewDimensionToEnd(t,i){let s=this.listDimensions.length>0?this.listDimensions[this.listDimensions.length-1].end:0;this.listDimensions.push({height:t,start:s,end:s+t,rindex:parseInt(i)})}_deleteDimension(t){let i=this.listDimensions.filter(i=>i.rindex==t)[0];if(i){i.start=0,i.end=0;for(let s=t+1;s<=this.listDimensions.length-1;s++)this.listDimensions[s].start=this.listDimensions[s].start-i.height,this.listDimensions[s].end=this.listDimensions[s].end-i.height;let s=this.listDimensions.filter(t=>t.end>0);0==s.length?this.totalHeight=0:this.totalHeight=s[s.length-1].end}}refresh(){this.toNextUpdateDimensions=!0}forceUpdateComponent(){this.__didUpdate(!0)}_testDimensions(){let t=this.el.querySelector(".virtual-slot").childNodes;if(t.length>0)for(let i=0;i<=t.length-1;i++){let s=t[i],e=s.id,l=this.listDimensions.filter(t=>t.rindex==e)[0];l&&(l.height,s.offsetHeight)}}componentDidUpdate(){this.__didUpdate(!1)}__didUpdate(t){let i=this._setDimensions();this.initRender?((i||t)&&(this.changed=[...this.changed,""]),this._testDimensions()):(this.initRender=!0,this.selector.length>0&&(this.elementOffsetTop=this.el.offsetTop),this.updateVirtual())}render(){return t("div",{class:"vscroll "+(this.selector.length>0?"external ":"inner ")+(this.infinateFinally?"infinate-finally ":" ")+(0==this.list.length?"cleared":"")},t("div",{class:"vscroll-back",style:{height:this.totalHeight+"px"}}),t("div",{class:"vscroll-content "+(this.selector.length>0?"external":"inner")},t("slot",{name:"virtual"})),t("slot",{name:"loader"}))}static get is(){return"virtual-scroll"}static get properties(){return{bottomOffset:{type:Number,attr:"bottom-offset"},changed:{state:!0},clear:{method:!0},el:{elementRef:!0},forceUpdateComponent:{method:!0},list:{type:"Any",attr:"list",watchCallbacks:["watchHandler"]},refresh:{method:!0},scrollToNode:{method:!0},selector:{type:String,attr:"selector"},setInfinateFinally:{method:!0},setInfinateOn:{method:!0},virtualRatio:{type:Number,attr:"virtual-ratio"}}}static get events(){return[{name:"toBottom",method:"toBottom",bubbles:!0,cancelable:!0,composed:!0},{name:"update",method:"update",bubbles:!0,cancelable:!0,composed:!0}]}static get style(){return".vscroll.inner{overflow-y:auto;height:100%}.vscroll.external{overflow-y:hidden}.vscroll{overflow-x:hidden;position:relative;display:block}.vscroll .vscroll-back{width:1px;opacity:0}.vscroll .vscroll-content{top:0;left:0;width:100%;position:absolute}.vscroll .vscroll-content.inner{height:100%}.infinate-finally div[slot=loader]{visibility:hidden}.cleared div[slot=loader]{display:none}virual-scroll{height:100%;display:block}"}}export{i as VirtualScroll}; -------------------------------------------------------------------------------- /dist/virtualscroll/nqhdrz5d.es5.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | virtualscroll.loadBundle("nqhdrz5d",["exports"],function(e){var t=window.virtualscroll.h,n=function(){function e(){this.list=[],this.selector="",this.virtual=[],this.changed=[]}return e.prototype.componentWillLoad=function(){this.request()},e.prototype.request=function(){var e=this,t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json",token:"kRuGZ3Xd"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,n.addEventListener("toBottom",function(){e.lazyRequest()}),n.addEventListener("update",function(t){console.log("update"),e.virtual=t.detail,e.changed=e.changed.concat([""])})})},e.prototype.lazyRequest=function(){var e=this,t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){setTimeout(function(){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,e.list.length>200?n.setInfinateFinally():n.setInfinateOn()},3e3)})},e.prototype.reload=function(){var e=this,t=this.el.querySelector("virtual-scroll");t.list=[],t.clear(),this.changed=this.changed.concat([""]),setTimeout(function(){var t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,e.list.length>200?n.setInfinateFinally():n.setInfinateOn()})},2e3)},e.prototype.scrolling=function(){this.el.querySelector("virtual-scroll").scrollToNode(25,1e3,-50)},e.prototype.render=function(){return[t("div",{onClick:this.reload.bind(this),class:"reload"},"reload"),t("div",{onClick:this.scrolling.bind(this),class:"scrolling"},"scrolling"),t("div",{class:"virtual-container"},t("virtual-scroll",{"bottom-offset":"5","virtual-ratio":"15",selector:this.selector},t("div",{slot:"virtual",class:"virtual-slot"},this.virtual.map(function(e){return t("div",{class:"offer virtual-item",id:e.index},t("div",{style:{backgroundImage:"url("+e.thumbnailUrl+")"},class:"cover"}),t("div",{class:"title"},e.index),t("div",{class:"title"},e.title))})),t("div",{slot:"loader"},"loading...")))]},Object.defineProperty(e,"is",{get:function(){return"fetch-helper"},enumerable:!0,configurable:!0}),Object.defineProperty(e,"properties",{get:function(){return{changed:{state:!0},el:{elementRef:!0},list:{state:!0},selector:{type:String,attr:"selector"}}},enumerable:!0,configurable:!0}),Object.defineProperty(e,"style",{get:function(){return".cover{position:relative;width:150px;height:150px;background-size:cover;margin:0 auto}.title{font-size:15px;height:40px;text-align:center}.cover:after{content:\"\";display:block;padding-bottom:67%}.reload,.scrolling{position:absolute;top:0;margin:10px;padding:10px;background:#ccc;cursor:pointer;z-index:1}.scrolling{right:0}.reload{left:0}"},enumerable:!0,configurable:!0}),e}();e.FetchHelper=n,Object.defineProperty(e,"__esModule",{value:!0})}); -------------------------------------------------------------------------------- /dist/virtualscroll/nqhdrz5d.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | const{h:t}=window.virtualscroll;class e{constructor(){this.list=[],this.selector="",this.virtual=[],this.changed=[]}componentWillLoad(){this.request()}request(){let t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json",token:"kRuGZ3Xd"})},e=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(e).then(t=>t.json()).then(t=>{t.splice(0,50).map(t=>{t.index=this.list.length,this.list=[...this.list,t]});const e=this.el.querySelector("virtual-scroll");e.list=this.list,e.addEventListener("toBottom",()=>{this.lazyRequest()}),e.addEventListener("update",t=>{console.log("update"),this.virtual=t.detail,this.changed=[...this.changed,""]})})}lazyRequest(){let t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},e=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(e).then(t=>t.json()).then(t=>{setTimeout(()=>{t.splice(0,50).map(t=>{t.index=this.list.length,this.list=[...this.list,t]});const e=this.el.querySelector("virtual-scroll");e.list=this.list,this.list.length>200?e.setInfinateFinally():e.setInfinateOn()},3e3)})}reload(){const t=this.el.querySelector("virtual-scroll");t.list=[],t.clear(),this.changed=[...this.changed,""],setTimeout(()=>{let t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},e=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(e).then(t=>t.json()).then(t=>{t.splice(0,50).map(t=>{t.index=this.list.length,this.list=[...this.list,t]});const e=this.el.querySelector("virtual-scroll");e.list=this.list,this.list.length>200?e.setInfinateFinally():e.setInfinateOn()})},2e3)}scrolling(){this.el.querySelector("virtual-scroll").scrollToNode(25,1e3,-50)}render(){return[t("div",{onClick:this.reload.bind(this),class:"reload"},"reload"),t("div",{onClick:this.scrolling.bind(this),class:"scrolling"},"scrolling"),t("div",{class:"virtual-container"},t("virtual-scroll",{"bottom-offset":"5","virtual-ratio":"15",selector:this.selector},t("div",{slot:"virtual",class:"virtual-slot"},this.virtual.map(e=>t("div",{class:"offer virtual-item",id:e.index},t("div",{style:{backgroundImage:"url("+e.thumbnailUrl+")"},class:"cover"}),t("div",{class:"title"},e.index),t("div",{class:"title"},e.title)))),t("div",{slot:"loader"},"loading...")))]}static get is(){return"fetch-helper"}static get properties(){return{changed:{state:!0},el:{elementRef:!0},list:{state:!0},selector:{type:String,attr:"selector"}}}static get style(){return".cover{position:relative;width:150px;height:150px;background-size:cover;margin:0 auto}.title{font-size:15px;height:40px;text-align:center}.cover:after{content:\"\";display:block;padding-bottom:67%}.reload,.scrolling{position:absolute;top:0;margin:10px;padding:10px;background:#ccc;cursor:pointer;z-index:1}.scrolling{right:0}.reload{left:0}"}}export{e as FetchHelper}; -------------------------------------------------------------------------------- /dist/virtualscroll/virtualscroll.4u6xzod9.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | (function(Context,namespace,hydratedCssClass,resourcesUrl,s){"use strict"; 3 | s=document.querySelector("script[data-namespace='virtualscroll']");if(s){resourcesUrl=s.getAttribute('data-resources-url');} 4 | (function(t,e,n,o){"use strict";function i(t){return{t:t[0],e:t[1],n:!!t[2],o:!!t[3],i:!!t[4]}}function r(t,e){if(P(e)&&"object"!=typeof e&&"function"!=typeof e){if(t===Boolean||3===t)return"false"!==e&&(""===e||!!e);if(t===Number||4===t)return parseFloat(e);if(t===String||2===t)return e.toString()}return e}function c(t,e,n,o){const i=t.r.get(e);i&&((o=i["s-ld"]||i.$activeLoading)&&((n=o.indexOf(e))>-1&&o.splice(n,1),o.length||(i["s-init"]&&i["s-init"](),i.$initLoad&&i.$initLoad())),t.r.delete(e))}function s(t,e,n){let o,i,r=null,c=!1,s=!1;for(var f=arguments.length;f-- >2;)L.push(arguments[f]);for(;L.length>0;)if((n=L.pop())&&void 0!==n.pop)for(f=n.length;f--;)L.push(n[f]);else"boolean"==typeof n&&(n=null),(s="function"!=typeof t)&&(null==n?n="":"number"==typeof n?n=String(n):"string"!=typeof n&&(s=!1)),s&&c?r[r.length-1].c+=n:null===r?r=[s?{c:n}:n]:r.push(s?{c:n}:n),c=s;if(null!=e){if(e.className&&(e.class=e.className),"object"==typeof e.class){for(f in e.class)e.class[f]&&L.push(f);e.class=L.join(" "),L.length=0}null!=e.key&&(o=e.key),null!=e.name&&(i=e.name)}return"function"==typeof t?t(Object.assign({},e,{children:r}),q):{s:t,f:r,c:void 0,l:e,u:o,a:i,p:void 0,d:!1}}function f(t,e,n,o){e.split(" ").forEach(e=>{t[e]=!0,n&&(t[`${e}-${n}`]=!0,o&&(t[`${e}-${n}-${o}`]=t[`${e}-${o}`]=!0))})}function l(t,e){t.m.has(e)||(t.m.set(e,!0),t.b?t.queue.write(()=>u(t,e)):t.queue.tick(()=>u(t,e)))}function u(t,e,n,o,i,r){if(t.m.delete(e),!t.v.has(e)){if(o=t.y.get(e),n=!o){if((i=t.r.get(e))&&i.$rendered&&(i["s-rn"]=!0),i&&!i["s-rn"])return(i["s-rc"]=i["s-rc"]||[]).push(()=>{u(t,e)}),void(i.$onRender=i["s-rc"]);o=function c(t,e,n,o,i,r,s){try{(function f(t,e,n,o,i,r,c){for(c in t.w.set(o,n),t.g.has(n)||t.g.set(n,{}),(r=Object.assign({color:{type:String}},e.properties)).mode={type:String},r)p(t,r[c],n,o,c,i)})(t,i=t.M(e).k,e,o=new i,n),function l(t,e,n){if(e){const o=t.w.get(n);e.forEach(e=>{n[e.method]={emit:n=>{t.j(o,e.name,{bubbles:e.bubbles,composed:e.composed,cancelable:e.cancelable,detail:n})}}})}}(t,i.events,o);try{if(r=t.O.get(e)){for(s=0;sa(t,e,o,n)):a(t,e,o,n)}}function a(t,e,n,o){(function i(t,e,n,o){try{const i=e.k.host,r=e.k.encapsulation,c="shadow"===r&&t.N.x;let l,u;if(l=function i(t,e,n){return t&&Object.keys(t).forEach(o=>{t[o].reflectToAttr&&((n=n||{})[o]=e[o])}),n}(e.k.properties,o),u=c?n.shadowRoot:n,!n["s-rn"]){t.A(t,t.N,e,n);const i=n["s-sc"];i&&(t.N.P(n,function r(t){return`${t}-host`}(i),""),o.render||t.N.P(n,function c(t){return`${t}-slot`}(i),""))}if(o.render||o.hostData||i||l){t.T=!0;const a=o.render&&o.render();let p;if((p=o.hostData&&o.hostData())&&e.S){const t=Object.keys(p).reduce((t,n)=>e.S[n]?t.concat(n):e.S[S(n)]?t.concat(S(n)):t,[]);if(t.length>0)throw new Error("The following keys were attempted to be set with hostData() from the "+`${e.R} component: ${t.join(", ")}. `+"If you would like to modify these please set @Prop({ mutable: true, reflectToAttr: true}) on the @Prop() decorator.")}l&&(p=p?Object.assign(p,l):l),t.T=!1,i&&(p=function l(t,e,n){return t=t||{},Object.keys(e).forEach(o=>{"theme"===o?f(t.class=t.class||{},e[o],n.mode,n.color):"class"===o?f(t[o]=t[o]||{},e[o]):t[o]=e[o]}),t}(p,i,o));const d=t.L.get(n)||{};d.p=u;const m=s(null,p,a);m.d=!0,t.L.set(n,t.render(n,d,m,c,r))}t.q&&t.q.D(n),n["s-rn"]=!0,n.$onRender&&(n["s-rc"]=n.$onRender),n["s-rc"]&&(n["s-rc"].forEach(t=>t()),n["s-rc"]=null)}catch(e){t.T=!1,t.C(e,8,n,!0)}})(t,t.M(e),e,n);try{o?e["s-init"]():(n.componentDidUpdate&&n.componentDidUpdate(),g(t.L.get(e)))}catch(n){t.C(n,6,e,!0)}}function p(t,e,n,o,i,c,s,f){if(e.type||e.state){const l=t.g.get(n);e.state||(!e.attr||void 0!==l[i]&&""!==l[i]||(s=c&&c.I)&&P(f=s[e.attr])&&(l[i]=r(e.type,f)),n.hasOwnProperty(i)&&(void 0===l[i]&&(l[i]=r(e.type,n[i])),delete n[i])),o.hasOwnProperty(i)&&void 0===l[i]&&(l[i]=o[i]),e.watchCallbacks&&(l[D+i]=e.watchCallbacks.slice()),h(o,i,function l(e){return(e=t.g.get(t.w.get(this)))&&e[i]},function u(n,o){(o=t.w.get(this))&&(e.state||e.mutable)&&d(t,o,i,n)})}else if(e.elementRef)m(o,i,n);else if(e.method)m(n,i,o[i].bind(o));else if(e.context){const r=t.B(e.context);void 0!==r&&m(o,i,r.H&&r.H(n)||r)}else e.connect&&m(o,i,t.F(e.connect))}function d(t,e,n,o,i,r,c){(i=t.g.get(e))||t.g.set(e,i={});const s=i[n];if(o!==s&&(i[n]=o,r=t.y.get(e))){if(c=i[D+n])for(let t=0;te!==t[s]));for(s=0,f=n.length;s=0;r--)(c=l[r])["s-hn"]!==h&&c["s-ol"]&&(e.rt(c),e.ct(f(c),c,s(c)),e.rt(c["s-ol"]),c["s-ol"]=null,m=!0),i&&o(c,i);t.ot=!1}function i(t,o,i,r,c,f,l,u){const a=t["s-cr"]||t.$defaultHolder;for((l=a&&e.st(a)||t).shadowRoot&&e.ft(l)===h&&(l=l.shadowRoot);c<=f;++c)r[c]&&(u=P(r[c].c)?e.Y(r[c].c):n(null,i,c,t))&&(r[c].p=u,e.ct(l,u,s(o)))}function r(t,n,i,r){for(;n<=i;++n)P(t[n])&&(r=t[n].p,d=!0,r["s-ol"]?e.rt(r["s-ol"]):o(r,!0),e.rt(r))}function c(t,e){return t.s===e.s&&t.u===e.u&&("slot"!==t.s||t.a===e.a)}function s(t){return t&&t["s-ol"]?t["s-ol"]:t}function f(t){return e.st(t["s-ol"]?t["s-ol"]:t)}const l=[];let u,a,p,d,m,h,b;return function v(y,w,g,k,M,j,O,W,x,E,N,A){if(h=e.ft(y),b=y["s-cr"],u=k,a="shadow"!==M?j:null,p=y["s-sc"],m=d=!1,function l(u,a,p){const d=a.p=u.p,m=u.f,h=a.f;H=a.p&&P(e.lt(a.p))&&void 0!==a.p.ownerSVGElement,H="svg"===a.s||"foreignObject"!==a.s&&H,P(a.c)?(p=d["s-cr"]||d.$defaultHolder)?e.ut(e.st(p),a.c):u.c!==a.c&&e.ut(d,a.c):("slot"!==a.s&&$(t,u,a,H),P(m)&&P(h)?function b(t,u,a,p,d,m,h,v){let y=0,$=0,w=u.length-1,g=u[0],k=u[w],M=p.length-1,j=p[0],O=p[M];for(;y<=w&&$<=M;)if(null==g)g=u[++y];else if(null==k)k=u[--w];else if(null==j)j=p[++$];else if(null==O)O=p[--M];else if(c(g,j))l(g,j),g=u[++y],j=p[++$];else if(c(k,O))l(k,O),k=u[--w],O=p[--M];else if(c(g,O))"slot"!==g.s&&"slot"!==O.s||o(e.st(g.p)),l(g,O),e.ct(t,g.p,e.at(k.p)),g=u[++y],O=p[--M];else if(c(k,j))"slot"!==g.s&&"slot"!==O.s||o(e.st(k.p)),l(k,j),e.ct(t,k.p,g.p),k=u[--w],j=p[++$];else{for(d=null,m=y;m<=w;++m)if(u[m]&&P(u[m].u)&&u[m].u===j.u){d=m;break}P(d)?((v=u[d]).s!==j.s?h=n(u&&u[$],a,d,t):(l(v,j),u[d]=void 0,h=v.p),j=p[++$]):(h=n(u&&u[$],a,$,t),j=p[++$]),h&&e.ct(f(g.p),h,s(g.p))}y>w?i(t,null==p[M+1]?null:p[M+1].p,a,p,$,M):$>M&&r(u,y,w)}(d,m,a,h):P(h)?(P(u.c)&&e.ut(d,""),i(d,null,a,h,0,h.length-1)):P(m)&&r(m,0,m.length-1)),H&&"svg"===a.s&&(H=!1)}(w,g),P(a)&&e.P(w.p,C,a),m){for(function t(n,o,i,r,c,s,f,u,a,p){for(c=0,s=(o=e.it(n)).length;c=0;f--)(r=u[f])["s-cn"]||r["s-nr"]||r["s-hn"]===i["s-hn"]||((3===(p=e.pt(r))||8===p)&&""===a||1===p&&null===e.dt(r,"slot")&&""===a||1===p&&e.dt(r,"slot")===a)&&(l.some(t=>t.mt===r)||(d=!0,r["s-sn"]=a,l.push({ht:i,mt:r})));1===e.pt(i)&&t(i)}}(g.p),O=0;O{g(t,e)}))}function k(t,e,n,o,i){const r=t.pt(e);let c,s,f,l;if(i&&1===r){(s=t.dt(e,W))&&(f=s.split("."))[0]===o&&((l={}).s=t.ft(l.p=e),n.f||(n.f=[]),n.f[f[1]]=l,n=l,i=""!==f[2]);for(let r=0;r{const o=t[n];let i;const r={name:n};if(o.state)i="states",r.yt=o.watchCallbacks||[];else if(o.elementRef)i="elements";else if(o.method)i="methods";else{i="props";let t="any";o.type&&(t=o.type,"function"==typeof o.type&&(t=o.type.name)),r.type=t.toLowerCase(),r.mutable=o.mutable||!1,r.connect=o.connect||"-",r.context=o.connect||"-",r.yt=o.watchCallbacks||[]}return e[i].push(r),e},{$t:[],wt:[],gt:[],kt:[]})}(i.properties||{}),s=(o.Mt||[]).map(t=>({jt:t.t,capture:t.i,disabled:t.n,passive:t.o,method:t.e})),f=i.events||[],l=Object.assign({Ot:i.is,Ct:o.Wt||"unknown",encapsulation:i.encapsulation||"none"},r,{events:{xt:f,listeners:s}});return Promise.resolve(l)}function j(t,e,n,o){n.connectedCallback=function(){(function n(t,e,o){t.Et.has(o)||(t.Et.set(o,!0),function i(t,e){const n=t.M(e);n.Mt&&n.Mt.forEach(n=>{n.n||t.N.J(e,n.t,function o(t,e,n,i){return o=>{(i=t.y.get(e))?i[n](o):((i=t.O.get(e)||[]).push(n,o),t.O.set(e,i))}}(t,e,n.e),n.i,n.o)})}(t,o)),t.v.delete(o),t.Nt.has(o)||(t.Nt.set(o,!0),o["s-id"]||(o["s-id"]=t.At()),function r(t,e,n){for(n=e;n=t.N.lt(n);)if(t.Pt(n)){t.Tt.has(e)||(t.r.set(e,n),n.$activeLoading&&(n["s-ld"]=n.$activeLoading),(n["s-ld"]=n["s-ld"]||[]).push(e));break}}(t,o),t.queue.tick(()=>t.St(e,o,function n(t,e,o,i,r){return o.mode||(o.mode=t.Rt(o)),o["s-cr"]||t.dt(o,C)||t.x&&1===e.encapsulation||(o["s-cr"]=t.Y(""),o["s-cr"]["s-cn"]=!0,t.ct(o,o["s-cr"],t.it(o)[0])),t.x||1!==e.encapsulation||"shadowRoot"in HTMLElement.prototype||(o.shadowRoot=o),1===e.encapsulation&&t.x&&(o.shadowRoot,t.Lt(o,{mode:"open"})),i={qt:o["s-id"],I:{}},e.S&&Object.keys(e.S).forEach(n=>{(r=e.S[n].z)&&(i.I[r]=t.dt(o,r))}),i}(t.N,e,o))))})(t,e,this)},n.attributeChangedCallback=function(t,n,o){(function i(t,e,n,o,c,s,f){if(t&&o!==c)for(s in t)if((f=t[s]).z&&T(f.z)===T(n)){e[s]=r(f.Q,c);break}})(e.S,this,t,n,o)},n.disconnectedCallback=function(){(function e(t,n){if(!t.ot&&function o(t,e){for(;e;){if(!t.st(e))return 9!==t.pt(e);e=t.st(e)}}(t.N,n)){t.v.set(n,!0),c(t,n),g(t.L.get(n),!0),t.N.K(n),t.Et.delete(n);{const e=t.y.get(n);e&&e.componentDidUnload&&e.componentDidUnload()}t.q&&t.q.Dt(n),[t.r,t.It,t.W].forEach(t=>t.delete(n))}})(t,this)},n["s-init"]=function(){(function e(t,n,o,i,r){if(!t.Tt.has(n)&&(i=t.y.get(n))&&!t.v.has(n)&&(!n["s-ld"]||!n["s-ld"].length)){delete n["s-ld"],t.Tt.set(n,!0);try{g(t.L.get(n)),(r=t.It.get(n))&&(r.forEach(t=>t(n)),t.It.delete(n)),i.componentDidLoad&&i.componentDidLoad()}catch(e){t.C(e,4,n)}n.classList.add(o),c(t,n)}})(t,this,o)},n.forceUpdate=function(){l(t,this)},function i(t,e,n){e&&Object.keys(e).forEach(o=>{const i=e[o],c=i.Bt;1===c||2===c?h(n,o,function e(){return(t.g.get(this)||{})[o]},function e(n){d(t,this,o,r(i.Q,n))}):6===c&&m(n,o,R)})}(t,e.S,n)}function O(t,e,n,o){return function(){const i=arguments;return function r(t,e,n){let o=e[n];return o||(o=t.Ht.querySelector(n)),o||(o=e[n]=t.tt(n),t.et(t.Ht,o)),o.componentOnReady()}(t,e,n).then(t=>t[o].apply(t,i))}}const C="data-ssrv",W="data-ssrc",x="$",E={},N=[],A={enter:13,escape:27,space:32,tab:9,left:37,up:38,right:39,down:40},P=t=>null!=t,T=t=>t.toLowerCase(),S=t=>T(t).split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(""),R=()=>{},L=[],q={getAttributes:t=>t.l,replaceAttributes:(t,e)=>t.l=e},D="wc-",I={allowfullscreen:1,async:1,autofocus:1,autoplay:1,checked:1,controls:1,disabled:1,enabled:1,formnovalidate:1,hidden:1,multiple:1,noresize:1,readonly:1,required:1,selected:1,spellcheck:1},B="http://www.w3.org/1999/xlink";let H=!1;(function F(t,e,n,o,r,c){function f(t,e){if(!n.customElements.get(t.R)){j(v,u[t.R]=t,e.prototype,c);{const n=e.observedAttributes=[];for(const e in t.S)t.S[e].z&&n.push(t.S[e].z)}n.customElements.define(t.R,e)}}const u={html:{}},a={},p=n[t]=n[t]||{},d=function m(t,e,n){t.Ft||(t.Ft=((t,e,n,o)=>t.addEventListener(e,n,o)),t.Ut=((t,e,n,o)=>t.removeEventListener(e,n,o)));const o=new WeakMap,i={zt:n.documentElement,Qt:n.head,Ht:n.body,Zt:!1,pt:t=>t.nodeType,tt:t=>n.createElement(t),_:(t,e)=>n.createElementNS(t,e),Y:t=>n.createTextNode(t),nt:t=>n.createComment(t),ct:(t,e,n)=>t.insertBefore(e,n),rt:t=>t.remove(),et:(t,e)=>t.appendChild(e),it:t=>t.childNodes,st:t=>t.parentNode,at:t=>t.nextSibling,bt:t=>t.previousSibling,ft:t=>T(t.nodeName),vt:t=>t.textContent,ut:(t,e)=>t.textContent=e,dt:(t,e)=>t.getAttribute(e),P:(t,e,n)=>t.setAttribute(e,n),Gt:(t,e,n,o)=>t.setAttributeNS(e,n,o),G:(t,e)=>t.removeAttribute(e),Z:(t,e)=>t.hasAttribute(e),Rt:e=>e.getAttribute("mode")||(t.Context||{}).mode,Jt:(t,o)=>"child"===o?t.firstElementChild:"parent"===o?i.lt(t):"body"===o?i.Ht:"document"===o?n:"window"===o?e:t,J:(e,n,r,c,s,f,l,u)=>{const a=n;let p=e,d=o.get(e);if(d&&d[a]&&d[a](),"string"==typeof f?p=i.Jt(e,f):"object"==typeof f?p=f:(u=n.split(":")).length>1&&(p=i.Jt(e,u[0]),n=u[1]),!p)return;let m=r;(u=n.split(".")).length>1&&(n=u[0],m=(t=>{t.keyCode===A[u[1]]&&r(t)})),l=i.Zt?{capture:!!c,passive:!!s}:!!c,t.Ft(p,n,m,l),d||o.set(e,d={}),d[a]=(()=>{p&&t.Ut(p,n,m,l),d[a]=null})},K:(t,e)=>{const n=o.get(t);n&&(e?n[e]&&n[e]():Object.keys(n).forEach(t=>{n[t]&&n[t]()}))},Lt:(t,e)=>t.attachShadow(e)};i.x=!!i.zt.attachShadow,e.location.search.indexOf("shadow=false")>0&&(i.x=!1),i.Kt=((t,n,o)=>t&&t.dispatchEvent(new e.CustomEvent(n,o)));try{e.addEventListener("e",null,Object.defineProperty({},"passive",{get:()=>i.Zt=!0}))}catch(t){}return i.lt=((t,e)=>(e=i.st(t))&&11===i.pt(e)?e.host:e),i}(p,n,o);e.isServer=e.isPrerender=!(e.isClient=!0),e.window=n,e.location=n.location,e.document=o,e.resourcesUrl=e.publicPath=r,e.enableListener=((t,e,n,o,i)=>(function r(t,e,n,o,i,c){if(e){const r=t.w.get(e),s=t.M(r);if(s&&s.Mt)if(o){const o=s.Mt.find(t=>t.t===n);o&&t.N.J(r,n,t=>e[o.e](t),o.i,void 0===c?o.o:!!c,i)}else t.N.K(r,n)}})(v,t,e,n,o,i)),e.emit=((t,n,o)=>d.Kt(t,e.eventNameFn?e.eventNameFn(n):n,o)),p.h=s,p.Context=e;const h=n["s-defined"]=n.$definedCmps=n["s-defined"]||n.$definedCmps||{};let b=0;const v={N:d,Vt:f,j:e.emit,M:t=>u[d.ft(t)],B:t=>e[t],isClient:!0,Pt:t=>!(!h[d.ft(t)]&&!v.M(t)),At:()=>t+b++,C:(t,e,n)=>void 0,F:t=>(function e(t,n,o){return{create:O(t,n,o,"create"),componentOnReady:O(t,n,o,"componentOnReady")}})(d,a,t),queue:e.queue=function y(t,e){function n(t){for(let e=0;e0&&(u.push(...l),l.length=0),(p=f.length+l.length+u.length>0)?t.raf(i):a=0}const r=()=>e.performance.now(),c=Promise.resolve(),s=[],f=[],l=[],u=[];let a=0,p=!1;return t.raf||(t.raf=e.requestAnimationFrame.bind(e)),{tick(t){s.push(t),1===s.length&&c.then(()=>n(s))},read(e){f.push(e),p||(p=!0,t.raf(i))},write(e){l.push(e),p||(p=!0,t.raf(i))}}}(p,n),St:function $(t,e){if(t.k)l(v,e);else{const n="string"==typeof t.Wt?t.Wt:t.Wt[e.mode],o=2===t.encapsulation||1===t.encapsulation&&!d.x;import(r+n+(o?".sc":"")+".js").then(n=>{try{(function o(t,e,n){const o=n.style;if(o){const i=n.is+(n.styleMode||x);if(!e[i]){const n=t.tt("template");e[i]=n,t.P(n,"data-tmpl-style-id",i),n.innerHTML=``,t.et(t.Qt,n)}}})(d,t,t.k=n[S(t.R)])}catch(e){t.k=class{}}l(v,e)}).catch(t=>void 0)}},r:new WeakMap,Xt:new WeakMap,Nt:new WeakMap,Et:new WeakMap,Tt:new WeakMap,w:new WeakMap,W:new WeakMap,y:new WeakMap,v:new WeakMap,m:new WeakMap,It:new WeakMap,O:new WeakMap,L:new WeakMap,g:new WeakMap};v.render=w(v,d);const g=d.zt;g["s-ld"]=[],g["s-rn"]=!0,g["s-init"]=(()=>{v.Tt.set(g,p.loaded=v.b=!0),d.Kt(n,"appload",{detail:{namespace:t}})}),function W(t,e,n){const o=n.querySelectorAll(`[${C}]`),i=o.length;let r,c,s,f,l,u;if(i>0)for(t.Tt.set(n,!0),f=0;f{(function i(t,e,n,o){const i=n.k.styleMode,r=n.encapsulation;(2===r||1===r&&!t.N.x)&&(o["s-sc"]=function c(t,e){const n=`data-${t.R}`;return e&&e!==x?`${n}-${e}`:n}(n,i));const s=n.R+(i||x),f=n[s];if(f){let n=e.Qt;if(e.x)if(1===r)n=o.shadowRoot;else{let t=o;for(;t=e.st(t);)if(t.host&&t.host.shadowRoot){n=t.host.shadowRoot;break}}let i=t.Xt.get(n);if(i||t.Xt.set(n,i={}),!i[s]){let t;{t=f.content.cloneNode(!0),i[s]=!0;const o=n.querySelectorAll("[data-styles]");e.ct(n,t,o.length&&o[o.length-1].nextSibling||n.firstChild)}}}})(t,e,n,o)}),function E(t,e,n,o){const i=n.Yt=n.Yt||{};return i._t=i._t||[],i._t.push(function r(t,e,n){return{namespace:e,te:t=>t&&t.tagName?Promise.all([M(n,t.tagName),function e(t,n){return Promise.resolve(t.y.get(n))}(n,t)]).then(t=>t[0]&&t[1]?{ee:t[0],ne:t[1]}:null):Promise.resolve(null),oe:t=>M(n,t),ie:()=>Promise.all(t.components.map(t=>M(n,t[0]))).then(t=>t.filter(t=>t))}}(t,e,o)),i.te||(i.te=(t=>Promise.all(i._t.map(e=>e.te(t))).then(t=>t.find(t=>!!t)))),i.ie||(i.ie=(()=>{const t=[];return i._t.forEach(e=>{t.push(e.ie())}),Promise.all(t).then(t=>{const e=[];return t.forEach(t=>{t.forEach(t=>{e.push(t)})}),e})})),i}(p,t,n,v),(p.components||[]).map(t=>{const e=function n(t,e,o){const r={R:t[0],S:{color:{z:"color"}}};r.Wt=t[1];const c=t[3];if(c)for(e=0;ef(t,class extends HTMLElement{})),function N(t,e,n,o,i,r){if(e.componentOnReady=((e,n)=>{if(!e.nodeName.includes("-"))return n(null),!1;const o=t.M(e);if(o)if(t.Tt.has(e))n(e);else{const o=t.It.get(e)||[];o.push(n),t.It.set(e,o)}return!!o}),i){for(r=i.length-1;r>=0;r--)e.componentOnReady(i[r][0],i[r][1])&&i.splice(r,1);for(r=0;r/node_modules/@stencil/core/testing/jest.preprocessor.js" 51 | }, 52 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", 53 | "moduleFileExtensions": [ 54 | "ts", 55 | "tsx", 56 | "js", 57 | "json", 58 | "jsx" 59 | ] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![Built With Stencil](https://img.shields.io/badge/-Built%20With%20Stencil-16161d.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI%2BCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI%2BCgkuc3Qwe2ZpbGw6I0ZGRkZGRjt9Cjwvc3R5bGU%2BCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00MjQuNywzNzMuOWMwLDM3LjYtNTUuMSw2OC42LTkyLjcsNjguNkgxODAuNGMtMzcuOSwwLTkyLjctMzAuNy05Mi43LTY4LjZ2LTMuNmgzMzYuOVYzNzMuOXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTQyNC43LDI5Mi4xSDE4MC40Yy0zNy42LDAtOTIuNy0zMS05Mi43LTY4LjZ2LTMuNkgzMzJjMzcuNiwwLDkyLjcsMzEsOTIuNyw2OC42VjI5Mi4xeiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNDI0LjcsMTQxLjdIODcuN3YtMy42YzAtMzcuNiw1NC44LTY4LjYsOTIuNy02OC42SDMzMmMzNy45LDAsOTIuNywzMC43LDkyLjcsNjguNlYxNDEuN3oiLz4KPC9zdmc%2BCg%3D%3D&colorA=16161d&style=flat-square) 2 | 3 | # Stenciljs-virtual-scroll 4 | 5 | This is a project for building a standalone Virtual Scroll Web Component using Stencil. 6 | Project contain collection of two components: 7 | 8 | **1.** virtual-scroll (VirtualScrollWebComponent). 9 | This component render subset of elements with **DIFFERENT** height, required to fill the viewport 10 | 11 | **2.** fetch-helper (FetchHelperWebComponent) 12 | This component show you, how to use virtual scroll without framework. 13 | 14 | 15 | ## Get Started with Angular5 (Ionic 3) 16 | 17 | **Step 1.** Install Stenciljs-virtual-scroll 18 | 19 | ```sh 20 | npm install stenciljs-virtual-scroll --save 21 | ``` 22 | 23 | **Step 2.** Import virtual scroll component into your angular app module 24 | 25 | ```ts 26 | .... 27 | import 'stenciljs-virtual-scroll/dist/virtualscroll'; 28 | .... 29 | 30 | ``` 31 | 32 | **Step 3.** Import CUSTOM_ELEMENTS_SCHEMA into your angular app module 33 | 34 | ```ts 35 | .... 36 | import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; 37 | .... 38 | 39 | @NgModule({ 40 | ... 41 | schemas: [ CUSTOM_ELEMENTS_SCHEMA ] 42 | .... 43 | }) 44 | export class AppModule { } 45 | 46 | ``` 47 | 48 | **Step 4.** Copying the Components 49 | 50 | For Angular2+ 51 | 52 | During the build, the components need to be copied to the build output directory. The easiest way to do this is to modify include the collection in the assets array of the .angular-cli.json file. 53 | 54 | ```json 55 | "assets": [ 56 | "assets", 57 | "favicon.ico", 58 | { "glob": "**/*", "input": "../node_modules/stenciljs-virtual-scroll/dist/virtualscroll", "output": "./virtualscroll" } 59 | ] 60 | 61 | ``` 62 | 63 | For Ionic2+ 64 | 65 | You must use app-script to copy web component files in www directory 66 | 67 | 1. Add in package.json 68 | ```json 69 | "config": { 70 | "ionic_copy": "./config/copy.config.js" 71 | } 72 | ``` 73 | 74 | 2. Create config/copy.config.js and put in 75 | 76 | ```ts 77 | // this is a custom dictionary to make it easy to extend/override 78 | // provide a name for an entry, it can be anything such as 'copyAssets' or 'copyFonts' 79 | // then provide an object with a `src` array of globs and a `dest` string 80 | module.exports = { 81 | copyAssets: { 82 | src: ['{{SRC}}/assets/**/*'], 83 | dest: '{{WWW}}/assets' 84 | }, 85 | copyIndexContent: { 86 | src: ['{{SRC}}/index.html', '{{SRC}}/manifest.json', '{{SRC}}/service-worker.js'], 87 | dest: '{{WWW}}' 88 | }, 89 | copyFonts: { 90 | src: ['{{ROOT}}/node_modules/ionicons/dist/fonts/**/*', '{{ROOT}}/node_modules/ionic-angular/fonts/**/*'], 91 | dest: '{{WWW}}/assets/fonts' 92 | }, 93 | copyPolyfills: { 94 | src: [`{{ROOT}}/node_modules/ionic-angular/polyfills/${process.env.IONIC_POLYFILL_FILE_NAME}`], 95 | dest: '{{BUILD}}' 96 | }, 97 | copySwToolbox: { 98 | src: ['{{ROOT}}/node_modules/sw-toolbox/sw-toolbox.js'], 99 | dest: '{{BUILD}}' 100 | }, 101 | copyVirtualScrollCore: { 102 | src: ['{{ROOT}}/node_modules/stenciljs-virtual-scroll/dist/virtualscroll/**/*'], 103 | dest: '{{BUILD}}/virtualscroll' 104 | }, 105 | copyVirtualScroll: { 106 | src: ['{{ROOT}}/node_modules/stenciljs-virtual-scroll/dist/virtualscroll.js'], 107 | dest: '{{BUILD}}' 108 | } 109 | } 110 | ``` 111 | 112 | before copyVirtualScrollCore property set standart app-script copy.config properties (if you are modify self config or my version is outdated, get only last 2 properties and put in your) 113 | 114 | 3. And register component in app module 115 | 116 | ```ts 117 | .... 118 | import 'stenciljs-virtual-scroll/dist/virtualscroll'; 119 | .... 120 | 121 | ``` 122 | 123 | 4. rebuild 124 | 125 | # Usage 126 | 127 | 128 | ```html 129 | .... 130 |
131 | 132 | 133 |
134 |
135 |
136 |
137 |
{{item.index}}
138 |
{{item.title}}
139 |
140 |
141 |
loading...
142 |
143 |
144 | .... 145 | ``` 146 | 147 | OR without selector 148 | 149 | ```html 150 | .... 151 |
152 | 153 | 154 |
155 |
156 | {{item.index}} 157 |
158 |
loading...
159 | 160 |
161 | .... 162 | ``` 163 | 164 | 165 | ```ts 166 | .... 167 | export class ExamplePage { 168 | 169 | @ViewChild('scroll') vscroll: ElementRef; 170 | private virtual: Array = []; 171 | .... 172 | 173 | initVScroll() { 174 | 175 | this.vscroll.nativeElement.addEventListener('update', (event) => { 176 | this.virtual = event.detail; 177 | //this.changeDetector.detectChanges(); if need 178 | }); 179 | 180 | this.vscroll.nativeElement.addEventListener('toBottom', (event) => { 181 | this.http.get('https://jsonplaceholder.typicode.com/photos', {}).map(res => res.json()).subscribe(data => { 182 | this.vscroll.nativeElement.list = this.vscroll.nativeElement.list.concat(data.splice(0, 50)) 183 | 184 | if (this.vscroll.nativeElement.list.length > 200) { 185 | this.vscroll.nativeElement.setInfinateFinally(); 186 | } 187 | else { 188 | this.vscroll.nativeElement.setInfinateOn(); 189 | } 190 | //this.changeDetector.detectChanges(); if need 191 | }); 192 | }); 193 | 194 | this.http.get('https://jsonplaceholder.typicode.com/photos', {}).map(res => res.json()).subscribe(data => { 195 | this.vscroll.nativeElement.list = data.splice(0, 50); 196 | //this.changeDetector.detectChanges(); if need 197 | }); 198 | 199 | 200 | } 201 | } 202 | 203 | .... 204 | ``` 205 | 206 | ```css 207 | virtual-scroll { 208 | display: block; 209 | } 210 | ``` 211 | 212 | If you need to use it without framework, watch fetch-helper component. 213 | 214 | 215 | # Ionic 3 example 216 | 217 | [stenciljs ionic-virtual-scroll-example](https://github.com/mgnstudio7/ionic-virtual-scroll-example) 218 | 219 | # API 220 | 221 | **Selector** 222 | 223 | In this attribute you must set selector of scrollable container (ionic application example). 224 | If attribute is empty, component use inner scroll container. 225 | 226 | **bottom-offset** 227 | 228 | offset of elements to fired toBottom() event 229 | 230 | **toBottom()** 231 | 232 | this event is fired if scroll came to the end 233 | 234 | **update()** 235 | 236 | this event is fired every time when virtual scroll data is changed 237 | 238 | **setInfinateOn()** 239 | 240 | this method must call every time when lazy load data is finish. 241 | If this method do not call. toBottom event never fired again 242 | 243 | **setInfinateFinally()** 244 | 245 | this method must call if lazy load finally and never fired toBottom() evend, and hide loader element 246 | 247 | **clear()** 248 | 249 | this method clear all need params of component, but not list 250 | 251 | ```ts 252 | .... 253 | this.vscroll.nativeElement.list = []; 254 | this.vscroll.nativeElement.clear(); 255 | //this.changeDetector.detectChanges(); if need 256 | .... 257 | ``` 258 | 259 | **scrollToNode()** 260 | 261 | set list item index, duration, offset 262 | 263 | ```ts 264 | .... 265 | this.vscroll.nativeElement.scrollToNode(25, 1000, -50); 266 | .... 267 | ``` 268 | 269 | **forceUpdateComponent()** 270 | 271 | this method re-checks all dimensions, add the missing ones and force update component 272 | 273 | ```ts 274 | .... 275 | this.vscroll.nativeElement.forceUpdateComponent(); 276 | .... 277 | ``` 278 | 279 | **virtual-ratio** 280 | 281 | add nodes after last and before first viewed nodes in viewport. 282 | 283 | # WARN 284 | 285 | nodes(list items) index must be different. Component set different index but if you change it, or if your list contain dublicates there may be problems. -------------------------------------------------------------------------------- /src/components.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is an autogenerated file created by the Stencil compiler. 3 | * It contains typing information for all components that exist in this project. 4 | */ 5 | 6 | import '@stencil/core'; 7 | 8 | declare global { 9 | namespace JSX { 10 | interface Element {} 11 | export interface IntrinsicElements {} 12 | } 13 | namespace JSXElements {} 14 | 15 | interface HTMLElement { 16 | componentOnReady?: () => Promise; 17 | } 18 | 19 | interface HTMLStencilElement extends HTMLElement { 20 | componentOnReady(): Promise; 21 | 22 | forceUpdate(): void; 23 | } 24 | 25 | interface HTMLAttributes {} 26 | } 27 | 28 | import { 29 | EventEmitter, 30 | } from '@stencil/core'; 31 | 32 | declare global { 33 | 34 | namespace StencilComponents { 35 | interface FetchHelper { 36 | 'selector': string; 37 | } 38 | } 39 | 40 | interface HTMLFetchHelperElement extends StencilComponents.FetchHelper, HTMLStencilElement {} 41 | 42 | var HTMLFetchHelperElement: { 43 | prototype: HTMLFetchHelperElement; 44 | new (): HTMLFetchHelperElement; 45 | }; 46 | interface HTMLElementTagNameMap { 47 | 'fetch-helper': HTMLFetchHelperElement; 48 | } 49 | interface ElementTagNameMap { 50 | 'fetch-helper': HTMLFetchHelperElement; 51 | } 52 | namespace JSX { 53 | interface IntrinsicElements { 54 | 'fetch-helper': JSXElements.FetchHelperAttributes; 55 | } 56 | } 57 | namespace JSXElements { 58 | export interface FetchHelperAttributes extends HTMLAttributes { 59 | 'selector'?: string; 60 | } 61 | } 62 | } 63 | 64 | 65 | declare global { 66 | 67 | namespace StencilComponents { 68 | interface VirtualScroll { 69 | 'bottomOffset': number; 70 | 'clear': () => void; 71 | 'forceUpdateComponent': () => void; 72 | 'list': Array; 73 | 'refresh': () => void; 74 | 'scrollToNode': (index: number, speed: number, offset?: number) => void; 75 | 'selector': string; 76 | 'setInfinateFinally': () => void; 77 | 'setInfinateOn': () => void; 78 | 'virtualRatio': number; 79 | } 80 | } 81 | 82 | interface HTMLVirtualScrollElement extends StencilComponents.VirtualScroll, HTMLStencilElement {} 83 | 84 | var HTMLVirtualScrollElement: { 85 | prototype: HTMLVirtualScrollElement; 86 | new (): HTMLVirtualScrollElement; 87 | }; 88 | interface HTMLElementTagNameMap { 89 | 'virtual-scroll': HTMLVirtualScrollElement; 90 | } 91 | interface ElementTagNameMap { 92 | 'virtual-scroll': HTMLVirtualScrollElement; 93 | } 94 | namespace JSX { 95 | interface IntrinsicElements { 96 | 'virtual-scroll': JSXElements.VirtualScrollAttributes; 97 | } 98 | } 99 | namespace JSXElements { 100 | export interface VirtualScrollAttributes extends HTMLAttributes { 101 | 'bottomOffset'?: number; 102 | 'list'?: Array; 103 | 'onToBottom'?: (event: CustomEvent) => void; 104 | 'onUpdate'?: (event: CustomEvent>) => void; 105 | 'selector'?: string; 106 | 'virtualRatio'?: number; 107 | } 108 | } 109 | } 110 | 111 | declare global { namespace JSX { interface StencilJSX {} } } 112 | 113 | export declare function defineCustomElements(window: any): void; -------------------------------------------------------------------------------- /src/components/fetch-helper/fetch-helper.scss: -------------------------------------------------------------------------------- 1 | 2 | .cover { 3 | position: relative; 4 | width: 150px; 5 | height: 150px; 6 | background-size: cover; 7 | margin: 0 auto; 8 | } 9 | .title { 10 | font-size: 15px; 11 | height: 40px; 12 | text-align: center; 13 | } 14 | .cover:after { 15 | content: ""; 16 | display: block; 17 | padding-bottom: 67%; 18 | } 19 | 20 | .reload, .scrolling { 21 | position: absolute; 22 | top: 0; 23 | margin: 10px; 24 | padding: 10px; 25 | background: #ccc; 26 | cursor: pointer; 27 | z-index: 1; 28 | } 29 | 30 | .scrolling { 31 | right: 0; 32 | } 33 | 34 | .reload { 35 | left: 0; 36 | } -------------------------------------------------------------------------------- /src/components/fetch-helper/fetch-helper.spec.ts: -------------------------------------------------------------------------------- 1 | import { flush, render } from '@stencil/core/testing'; 2 | import { FetchHelperWebComponent } from './fetch-helper'; 3 | 4 | describe('my-component', () => { 5 | it('should build', () => { 6 | expect(new FetchHelperWebComponent()).toBeTruthy(); 7 | }); 8 | 9 | describe('rendering', () => { 10 | let element; 11 | beforeEach(async () => { 12 | element = await render({ 13 | components: [FetchHelperWebComponent], 14 | html: '' 15 | }); 16 | }); 17 | 18 | it('should work without parameters', () => { 19 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m'); 20 | }); 21 | 22 | it('should work with a first name', async () => { 23 | element.first = 'Peter'; 24 | await flush(element); 25 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m Peter'); 26 | }); 27 | 28 | it('should work with a last name', async () => { 29 | element.last = 'Parker'; 30 | await flush(element); 31 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m Parker'); 32 | }); 33 | 34 | it('should work with both a first and a last name', async () => { 35 | element.first = 'Peter' 36 | element.last = 'Parker'; 37 | await flush(element); 38 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m Peter Parker'); 39 | }); 40 | }); 41 | }); -------------------------------------------------------------------------------- /src/components/fetch-helper/fetch-helper.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Prop, State, Element } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'fetch-helper', 5 | styleUrl: 'fetch-helper.scss', 6 | //shadow: true 7 | }) 8 | export class FetchHelperWebComponent { 9 | 10 | @State() list: Array = []; 11 | 12 | @Element() el: HTMLElement; 13 | 14 | //class selector 15 | @Prop() selector: string = ''; 16 | 17 | private virtual: Array = []; 18 | 19 | //change detection strategy 20 | @State() changed: string[] = []; 21 | 22 | componentWillLoad() { 23 | this.request(); 24 | } 25 | 26 | request() { 27 | 28 | let headers = { 29 | } 30 | 31 | headers['Content-Type'] = 'application/json'; 32 | headers['token'] = 'kRuGZ3Xd'; 33 | 34 | 35 | let mode: RequestMode = "cors"; 36 | let options = { 37 | method: 'GET', 38 | mode: mode, 39 | headers: new Headers(headers) 40 | }; 41 | let request = new Request("https://jsonplaceholder.typicode.com/photos", options); 42 | 43 | fetch(request).then(response => { return response.json(); }).then(r => { 44 | 45 | r.splice(0, 50).map(m => { 46 | m.index = this.list.length 47 | this.list = [...this.list, m]; 48 | }); 49 | 50 | const scrollTag: any = this.el.querySelector('virtual-scroll'); 51 | scrollTag.list = this.list; 52 | 53 | scrollTag.addEventListener('toBottom', () => { 54 | 55 | this.lazyRequest(); 56 | }); 57 | 58 | scrollTag.addEventListener('update', (event) => { 59 | console.log('update') 60 | this.virtual = event.detail; 61 | this.changed = [...this.changed, '']; 62 | }); 63 | }); 64 | } 65 | 66 | lazyRequest() { 67 | 68 | let headers = { 69 | } 70 | 71 | headers['Content-Type'] = 'application/json'; 72 | let mode: RequestMode = "cors"; 73 | 74 | let options = { 75 | method: 'GET', 76 | mode: mode, 77 | headers: new Headers(headers) 78 | }; 79 | let request = new Request("https://jsonplaceholder.typicode.com/photos", options); 80 | fetch(request).then(response => { return response.json(); }).then(r => { 81 | 82 | setTimeout(() => { 83 | r.splice(0, 50).map(m => { 84 | m.index = this.list.length 85 | this.list = [...this.list, m]; 86 | }); 87 | const scrollTag: any = this.el.querySelector('virtual-scroll'); 88 | scrollTag.list = this.list; 89 | 90 | if (this.list.length > 200) { 91 | scrollTag.setInfinateFinally(); 92 | } 93 | else { 94 | scrollTag.setInfinateOn(); 95 | } 96 | }, 3000); 97 | }); 98 | } 99 | 100 | reload() { 101 | 102 | const scrollTag: any = this.el.querySelector('virtual-scroll'); 103 | scrollTag.list = []; 104 | scrollTag.clear(); 105 | this.changed = [...this.changed, '']; 106 | 107 | setTimeout(() => { 108 | 109 | let headers = { 110 | } 111 | 112 | headers['Content-Type'] = 'application/json'; 113 | let mode: RequestMode = "cors"; 114 | 115 | let options = { 116 | method: 'GET', 117 | mode: mode, 118 | headers: new Headers(headers) 119 | }; 120 | let request = new Request("https://jsonplaceholder.typicode.com/photos", options); 121 | fetch(request).then(response => { return response.json(); }).then(r => { 122 | 123 | r.splice(0, 50).map(m => { 124 | m.index = this.list.length 125 | this.list = [...this.list, m]; 126 | }); 127 | const scrollTag: any = this.el.querySelector('virtual-scroll'); 128 | scrollTag.list = this.list; 129 | 130 | if (this.list.length > 200) { 131 | scrollTag.setInfinateFinally(); 132 | } 133 | else { 134 | scrollTag.setInfinateOn(); 135 | } 136 | }); 137 | }, 2000) 138 | } 139 | 140 | scrolling() { 141 | 142 | const scrollTag: any = this.el.querySelector('virtual-scroll'); 143 | // scrollTag.list.splice(2, 1); 144 | // scrollTag.refresh(); 145 | // this.changed = [...this.changed, '']; 146 | scrollTag.scrollToNode(25, 1000, -50); 147 | } 148 | 149 | render() { 150 | 151 | return ([ 152 |
reload
, 153 |
scrolling
, 154 |
155 | 156 |
157 | { 158 | this.virtual.map((item) => 159 |
160 |
161 |
162 |
{item.index}
163 |
{item.title}
164 |
165 | ) 166 | } 167 |
168 |
loading...
169 |
170 |
171 | ]); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/components/virtual-scroll/virtual-scroll.scss: -------------------------------------------------------------------------------- 1 | .vscroll.inner { 2 | overflow-y: auto; 3 | height: 100%; 4 | } 5 | 6 | .vscroll.external { 7 | overflow-y: hidden; 8 | } 9 | 10 | .vscroll { 11 | overflow-x: hidden; 12 | position: relative; 13 | display: block; 14 | .vscroll-back { 15 | width: 1px; 16 | opacity: 0; 17 | } 18 | .vscroll-content { 19 | top: 0; 20 | left: 0; 21 | width: 100%; 22 | position: absolute; 23 | } 24 | .vscroll-content.inner { 25 | height: 100%; 26 | } 27 | } 28 | 29 | .infinate-finally { 30 | div[slot='loader'] { 31 | visibility: hidden; 32 | } 33 | } 34 | .cleared { 35 | div[slot='loader'] { 36 | display: none; 37 | } 38 | } 39 | 40 | virual-scroll { 41 | height: 100%; 42 | display: block; 43 | } -------------------------------------------------------------------------------- /src/components/virtual-scroll/virtual-scroll.spec.ts: -------------------------------------------------------------------------------- 1 | import { flush, render } from '@stencil/core/testing'; 2 | import { VirualScrollWebComponent } from './virtual-scroll'; 3 | 4 | describe('my-component', () => { 5 | it('should build', () => { 6 | expect(new VirualScrollWebComponent()).toBeTruthy(); 7 | }); 8 | 9 | describe('rendering', () => { 10 | let element; 11 | beforeEach(async () => { 12 | element = await render({ 13 | components: [VirualScrollWebComponent], 14 | html: '' 15 | }); 16 | }); 17 | 18 | it('should work without parameters', () => { 19 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m'); 20 | }); 21 | 22 | it('should work with a first name', async () => { 23 | element.first = 'Peter'; 24 | await flush(element); 25 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m Peter'); 26 | }); 27 | 28 | it('should work with a last name', async () => { 29 | element.last = 'Parker'; 30 | await flush(element); 31 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m Parker'); 32 | }); 33 | 34 | it('should work with both a first and a last name', async () => { 35 | element.first = 'Peter' 36 | element.last = 'Parker'; 37 | await flush(element); 38 | expect(element.textContent.trim()).toEqual('Hello, World! I\'m Peter Parker'); 39 | }); 40 | }); 41 | }); -------------------------------------------------------------------------------- /src/components/virtual-scroll/virtual-scroll.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | logic of this component base on 3 | ... 4 | */ 5 | 6 | import { Component, Prop, State, Element, Watch, Event, EventEmitter, Method } from '@stencil/core'; 7 | 8 | @Component({ 9 | tag: 'virtual-scroll', 10 | styleUrl: 'virtual-scroll.scss' 11 | }) 12 | export class VirualScrollWebComponent { 13 | 14 | //list og imported values 15 | @Prop() list: Array = []; 16 | 17 | //class selector 18 | @Prop() selector: string = ''; 19 | 20 | //offset bottom event 21 | @Prop() bottomOffset: number = 0; 22 | 23 | //reserve of the bootom rows 24 | @Prop() virtualRatio = 3; 25 | 26 | //change detection strategy 27 | @State() changed: string[] = []; 28 | 29 | /*ROOT DIMENSIONS*/ 30 | //root html 31 | @Element() el: HTMLElement; 32 | //content element 33 | private contentEl: HTMLElement; 34 | //position of scroll element 35 | private position: number = 0; 36 | //scrolled html element 37 | private parentScroll: any; 38 | private parentScrollHeight: number = 0; 39 | //offset of scroll 40 | private vscrollOffsetTop: number = 0; 41 | //private contentOffsetTop: number = 0; 42 | private elementOffsetTop: number = 0; 43 | /*ROOT DIMENSIONS^^^*/ 44 | 45 | /*EVENTS*/ 46 | @Event() toBottom: EventEmitter; 47 | @Event() update: EventEmitter>; 48 | /*EVENTS^^^*/ 49 | 50 | /*LAZYLOAD*/ 51 | //state to enable bottom infinate event 52 | private infinateOn: boolean = true; 53 | //state to common disable bottom infinate event 54 | private infinateFinally: boolean = false; 55 | /*LAZYLOAD^^^*/ 56 | 57 | //full height of component 58 | private totalHeight: number = 0; 59 | 60 | //first and last viewed rows 61 | private first: any; 62 | private last: any; 63 | 64 | //list items dimensions 65 | private listDimensions: Array = []; 66 | 67 | //bool state to detect init render 68 | private initRender: boolean = false; 69 | 70 | private toNextUpdateDimensions: boolean = false; 71 | // private stackToDelete: Array = []; 72 | 73 | private scrollEventDispatch = () => undefined; 74 | 75 | //change list event2 76 | @Watch('list') 77 | watchHandler(newValue: Array, oldValue: Array) { 78 | 79 | if (oldValue.length > 0) { 80 | 81 | let deleted = oldValue.filter(f => newValue.filter(f2 => f2.index == f.index).length == 0); 82 | if (deleted.length > 0) { 83 | deleted.map(m => { 84 | this._deleteDimension(m.index); 85 | }) 86 | } 87 | } 88 | //let edited = newValue.filter(f => oldValue.filter(f2 => f2.index == f.index).length == 0); 89 | //console.log('let deleted', deleted); 90 | //console.log('let edited', edited); 91 | //console.log('let list', edited); 92 | 93 | this.list.map((m, i) => { 94 | if (!m.index) { 95 | m.index = i; 96 | } 97 | }) 98 | this.updateVirtual(true); 99 | //recalculation dimesions of list items 100 | this._setDimensions(); 101 | } 102 | 103 | //life cicle methods 104 | componentDidLoad() { 105 | 106 | this._setDefParams(); 107 | 108 | //get scroll element 109 | if (this.selector.length > 0) { 110 | this.parentScroll = this.el.closest('.' + this.selector); 111 | } 112 | else { 113 | this.parentScroll = this.el.querySelector('.vscroll'); 114 | } 115 | 116 | //get scroll element height 117 | this.parentScrollHeight = this.parentScroll['offsetHeight']; 118 | 119 | //get scroll element offset top 120 | //this.contentOffsetTop = (this.parentScroll) ? this.parentScroll['offsetTop'] : 0; 121 | 122 | //get content element 123 | this.contentEl = this.el.querySelector('.vscroll-content'); 124 | 125 | let vscroll = this.el.querySelector('.vscroll'); 126 | this.vscrollOffsetTop = (vscroll) ? vscroll['offsetTop'] : 0; 127 | 128 | 129 | this.scrollEventDispatch = this.parentScroll.addEventListener('scroll', () => { 130 | 131 | //console.log(this.parentScroll['scrollTop'] - this.vscrollOffsetTop - this.elementOffsetTop + this.parentScrollHeight); 132 | if (this.parentScroll['scrollTop'] - this.vscrollOffsetTop - this.elementOffsetTop + this.parentScrollHeight < 0) { 133 | return; 134 | } 135 | 136 | this.position = this.parentScroll['scrollTop'] - this.vscrollOffsetTop - this.elementOffsetTop; 137 | // console.log(this.position); 138 | // console.log('-----'); 139 | this.updateVirtual(); 140 | }, false); 141 | 142 | } 143 | 144 | //dispatch listener of scroll on unload 145 | unwatch() { 146 | if (this.parentScroll) { 147 | this.parentScroll.removeEventListener('scroll', this._listener); 148 | } 149 | } 150 | private _listener() { 151 | this.position = this.parentScroll['scrollTop'] - this.vscrollOffsetTop; 152 | this.updateVirtual(); 153 | } 154 | 155 | //life cicle methods 156 | componentDidUnload() { 157 | this.unwatch(); 158 | 159 | if (this.scrollEventDispatch) { 160 | this.scrollEventDispatch(); 161 | this.scrollEventDispatch = null; 162 | } 163 | 164 | // this.el.remove(); 165 | // this.contentEl.remove(); 166 | // this.parentScroll.remove(); 167 | // this.list = null; 168 | // this.listDimensions = null; 169 | 170 | } 171 | 172 | //life cicle methods 173 | componentWillLoad() { 174 | } 175 | 176 | 177 | private _setDefParams() { 178 | this.first = null; 179 | this.last = null; 180 | this.listDimensions = []; 181 | this.totalHeight = 0; 182 | this.position = 0; 183 | this.infinateOn = true; 184 | this.infinateFinally = false; 185 | } 186 | 187 | //update virtual list items 188 | updateVirtual(update: boolean = false) { 189 | 190 | let findex = (this.first) ? this.first.rindex : 0; 191 | let lindex = (this.last) ? this.last.rindex : 0; 192 | 193 | //get first and last viewed nodes by position 194 | this.first = this.listDimensions.filter(f => this.position >= f.start && this.position < f.end)[0]; 195 | this.last = this.listDimensions.filter(f => this.position + this.parentScroll.clientHeight >= f.start && this.position + this.parentScroll.clientHeight < f.end)[0]; 196 | //if last node by position is null, take last of list 197 | if (!this.last) { 198 | this.last = this.listDimensions[this.listDimensions.length - 1]; 199 | } 200 | 201 | // console.log('this.first', this.first) 202 | // console.log('this.last', this.last) 203 | 204 | //if first/last exist, set topPadding(content transformY). 205 | //virtual list set ... 206 | if (this.first && this.last) { 207 | 208 | let lastOffsetIndex = (this.last.rindex + this.virtualRatio) >= this.list.length ? this.list.length : this.last.rindex + this.virtualRatio 209 | 210 | let firstOffsetIndex = (this.first.rindex - this.virtualRatio) < 0 ? 0 : this.first.rindex - this.virtualRatio; 211 | if (lastOffsetIndex == this.list.length && (this.totalHeight - this.position - this.parentScrollHeight) < 0) { 212 | firstOffsetIndex = (findex - this.virtualRatio) < 0 ? 0 : findex - this.virtualRatio; 213 | this.first = this.listDimensions.filter(f => f.rindex == findex)[0]; 214 | } 215 | 216 | let v = []; 217 | if (this.list.length > 0) { 218 | v = this.list.slice(firstOffsetIndex, lastOffsetIndex); 219 | } 220 | 221 | if ((findex != this.first.rindex || lindex != this.last.rindex) || update) { 222 | 223 | requestAnimationFrame(() => { 224 | let d = this.listDimensions.filter(f => f.rindex == firstOffsetIndex)[0]; 225 | if (d) { 226 | this.contentEl.style.transform = 'translateY(' + d.start + 'px)'; 227 | this.contentEl.style.webkitTransform = 'translateY(' + d.start + 'px)'; 228 | } 229 | //this.virtual = v; 230 | this.update.emit(v); 231 | 232 | if (update) { 233 | //change detection 234 | this.changed = [...this.changed, '']; 235 | } 236 | }) 237 | 238 | //change detection 239 | this.changed = [...this.changed, '']; 240 | 241 | } 242 | } 243 | else { 244 | if (this.list.length > 0) { 245 | let v = this.list.slice(0, 20); 246 | //console.log('v2', v) 247 | //this.virtual = v; 248 | this.update.emit(v); 249 | 250 | //change detection 251 | this.changed = [...this.changed, '']; 252 | } 253 | } 254 | 255 | //bottom event 256 | if (this.last && this.last.rindex >= this.list.length - 1 - this.bottomOffset) { 257 | if (this.infinateOn && !this.infinateFinally && this.list.length > 0) { 258 | this.infinateOn = false; 259 | this.toBottom.emit(this.position); 260 | } 261 | } 262 | 263 | } 264 | 265 | //set infinate on status to send events 266 | @Method() 267 | setInfinateOn() { 268 | this.infinateOn = true; 269 | } 270 | 271 | //set infinate off status to send events 272 | @Method() 273 | setInfinateFinally() { 274 | this.infinateFinally = true; 275 | } 276 | 277 | //clear component data 278 | @Method() 279 | clear() { 280 | 281 | this._setDefParams(); 282 | requestAnimationFrame(() => { 283 | this.list = []; 284 | this.contentEl.style.transform = 'translateY(' + 0 + 'px)'; 285 | this.contentEl.style.webkitTransform = 'translateY(' + 0 + 'px)'; 286 | this.changed = [...this.changed, '']; 287 | }) 288 | 289 | } 290 | 291 | 292 | //scroll to element method at index 293 | @Method() 294 | scrollToNode(index: number, speed: number, offset: number = 0) { 295 | if (this.parentScroll) { 296 | if (index <= this.listDimensions.length - 1) { 297 | let dimension = this.listDimensions.filter(f => f.rindex == index)[0]; 298 | this._scrollTo(dimension.start + offset, speed); 299 | } 300 | else { 301 | this._scrollToIndex(index); 302 | } 303 | } 304 | } 305 | 306 | // //scroll to element method 307 | // @Method() 308 | // refresh() { 309 | 310 | // let missing = this.list.filter(item => this.list.indexOf(item) < 0); 311 | // console.log(missing); 312 | 313 | // let v = this.list.slice(this.first.rindex, this.last.rindex + this.bottomOffsetIndex); 314 | // this.update.emit(v); 315 | // //change detection 316 | // this.changed = [...this.changed, '']; 317 | // } 318 | 319 | private _scrollToIndex(index) { 320 | let perTick = 100; 321 | setTimeout(() => { 322 | this.parentScroll['scrollTop'] = this.parentScroll['scrollTop'] + perTick; 323 | if (this.first && this.first.rindex === index) return; 324 | this._scrollToIndex(index); 325 | }, 10); 326 | } 327 | 328 | private _scrollTo(to, duration) { 329 | if (duration <= 0) return; 330 | let difference = to - this.parentScroll['scrollTop']; 331 | let perTick = difference / duration * 10; 332 | 333 | setTimeout(() => { 334 | this.parentScroll['scrollTop'] = this.parentScroll['scrollTop'] + perTick; 335 | if (this.parentScroll['scrollTop'] === to) return; 336 | this._scrollTo(to, duration - 10); 337 | }, 10); 338 | } 339 | 340 | //recalculation dimesions of list items 341 | private _setDimensions(): boolean { 342 | let oldTotal = this.totalHeight; 343 | 344 | if (this.toNextUpdateDimensions) { 345 | this.listDimensions = []; 346 | } 347 | this.toNextUpdateDimensions = false; 348 | 349 | let nodes = this.el.querySelectorAll('.virtual-slot .virtual-item'); 350 | // console.log('_setDimensions', nodes) 351 | if (nodes.length > 0) { 352 | for (let vindex = 0; vindex <= nodes.length - 1; vindex++) { 353 | let node = nodes[vindex]; 354 | let rindex = node['id']; 355 | let d = this.listDimensions.filter(f => f.rindex == rindex)[0]; 356 | if (!d) { 357 | this._addNewDimensionToEnd(node['offsetHeight'], rindex); 358 | this.totalHeight = this.listDimensions[this.listDimensions.length - 1].end; 359 | } 360 | } 361 | } 362 | 363 | return (this.totalHeight != oldTotal); 364 | } 365 | 366 | //Append new dimensions of list item 367 | private _addNewDimensionToEnd(height: number, rindex) { 368 | let parentEnd = (this.listDimensions.length > 0) ? this.listDimensions[this.listDimensions.length - 1].end : 0; 369 | 370 | this.listDimensions.push({ 371 | height: height, 372 | start: parentEnd, 373 | end: parentEnd + height, 374 | rindex: parseInt(rindex) 375 | }); 376 | 377 | } 378 | 379 | private _deleteDimension(rindex) { 380 | //this index from list -> [index], if i get index from listDimensions -> filter().. 381 | let d = this.listDimensions.filter(f => f.rindex == rindex)[0]; 382 | if (d) { 383 | d.start = 0; 384 | d.end = 0; 385 | for (let i = rindex + 1; i <= this.listDimensions.length - 1; i++) { 386 | this.listDimensions[i].start = this.listDimensions[i].start - d.height; 387 | this.listDimensions[i].end = this.listDimensions[i].end - d.height; 388 | } 389 | 390 | let notDeleted = this.listDimensions.filter(f => f.end > 0); 391 | if (notDeleted.length == 0) { 392 | this.totalHeight = 0; 393 | } 394 | else { 395 | this.totalHeight = notDeleted[notDeleted.length - 1].end; 396 | } 397 | } 398 | } 399 | 400 | @Method() 401 | refresh() { 402 | this.toNextUpdateDimensions = true; 403 | } 404 | 405 | //this method may be called if something is wrong in framework logic. For example: in ionic 3, the page component not updated with new data on the inactive tab page. 406 | //The method re-checks all dimensions, add the missing ones and force update component. 407 | @Method() 408 | forceUpdateComponent() { 409 | this.__didUpdate(true); 410 | } 411 | 412 | //Append new dimensions of list item 413 | private _testDimensions() { 414 | let nodes = this.el.querySelector('.virtual-slot').childNodes; 415 | if (nodes.length > 0) { 416 | for (let vindex = 0; vindex <= nodes.length - 1; vindex++) { 417 | let node = nodes[vindex]; 418 | let rindex = node['id']; 419 | let d = this.listDimensions.filter(f => f.rindex == rindex)[0]; 420 | if (d && (d.height != node['offsetHeight'])) { 421 | //console.warn("One or more nodes change height after calculation dimensions. Check scroll", rindex); 422 | //console.log('node', node); 423 | //console.log('this.listDimensions[index]', d); 424 | } 425 | } 426 | } 427 | } 428 | 429 | componentDidUpdate() { 430 | this.__didUpdate(false); 431 | } 432 | 433 | __didUpdate(upd) { 434 | 435 | //after component render, need to add new dimensions if virtual nodes, change height 436 | //if is init render need call update virtual, 437 | //if is not init check update height. If height change render again! 438 | 439 | let isNewHeight = this._setDimensions(); 440 | // console.log('isNewHeight', isNewHeight) 441 | 442 | //if first render finished, recalculate virtual 443 | if (!this.initRender) { 444 | this.initRender = true; 445 | 446 | //if use external scroll, need take offset top scroll ellement 447 | if (this.selector.length > 0) { 448 | this.elementOffsetTop = this.el['offsetTop']; 449 | } 450 | 451 | this.updateVirtual(); 452 | } 453 | else { 454 | if (isNewHeight || upd) { 455 | //change detection 456 | this.changed = [...this.changed, '']; 457 | } 458 | this._testDimensions(); 459 | } 460 | } 461 | 462 | 463 | render() { 464 | return ( 465 |
0 ? 'external ' : 'inner ') + (this.infinateFinally ? 'infinate-finally ' : ' ') + (this.list.length == 0 ? 'cleared' : '')}> 466 |
467 | 468 |
469 |
0 ? 'external' : 'inner')}> 470 | 471 |
472 | 473 |
474 | ); 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgnstudio7/stenciljs-virtual-scroll/a041c3f5a4135b131931c6cf156f38ff0f7d1d3d/src/index.d.ts -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Stencil Component Starter 8 | 9 | 10 | 11 | 12 | 41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | -------------------------------------------------------------------------------- /stencil.config.js: -------------------------------------------------------------------------------- 1 | const sass = require('@stencil/sass'); 2 | 3 | exports.config = { 4 | namespace: 'virtualscroll', 5 | bundles: [ 6 | {components: ['virtual-scroll'] }, 7 | {components: ['fetch-helper'] } 8 | ], 9 | outputTargets:[ 10 | { 11 | type: 'dist' 12 | }, 13 | { 14 | type: 'www', 15 | serviceWorker: false 16 | } 17 | ], 18 | plugins: [ 19 | sass() 20 | ] 21 | }; 22 | 23 | exports.devServer = { 24 | root: 'www', 25 | watchGlob: '**/**' 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "allowUnreachableCode": false, 5 | "declaration": false, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "dom", 9 | "es2015" 10 | ], 11 | "moduleResolution": "node", 12 | "module": "es2015", 13 | "target": "es2015", 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "jsx": "react", 17 | "jsxFactory": "h" 18 | }, 19 | "include": [ 20 | "src", 21 | "types/jsx.d.ts" 22 | ], 23 | "exclude": [ 24 | "node_modules" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /www/build/virtualscroll.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Built with http://stenciljs.com 3 | * 2018-05-26T07:12:00 4 | */ 5 | !function(e,t,r,n,o,s,i,l,c,a,u,d,f,p){for((u=e.virtualscroll=e.virtualscroll||{}).components=c,(f=c.filter(function(e){return e[2]}).map(function(e){return e[0]})).length&&((d=t.createElement("style")).innerHTML=f.join()+"{visibility:hidden}.hydrated{visibility:inherit}",d.setAttribute("data-styles",""),t.head.insertBefore(d,t.head.firstChild)),function(e,t,r){(e["s-apps"]=e["s-apps"]||[]).push("virtualscroll"),r.componentOnReady||(r.componentOnReady=function(){var t=this;function r(r){if(t.nodeName.indexOf("-")>0){for(var n=e["s-apps"],o=0,s=0;s=0&&!(p=f[d]).src&&!p.hasAttribute("data-resources-url");d--);f=p.getAttribute("data-resources-url"),!o&&f&&(o=f),!o&&p.src&&(o=(f=p.src.split("/").slice(0,-1)).join("/")+(f.length?"/":"")+"virtualscroll/"),d=t.createElement("script"),function(e,t,r,n){return!(t.search.indexOf("core=esm")>0)&&(!(!(t.search.indexOf("core=es5")>0||"file:"===t.protocol)&&e.customElements&&e.customElements.define&&e.fetch&&e.CSS&&e.CSS.supports&&e.CSS.supports("color","var(--c)")&&"noModule"in r)||function(e){try{return new Function('import("")'),!1}catch(e){}return!0}())}(e,e.location,d)?d.src=o+"virtualscroll.etffcq0f.js":(d.src=o+"virtualscroll.4u6xzod9.js",d.setAttribute("type","module"),d.setAttribute("crossorigin",!0)),d.setAttribute("data-resources-url",o),d.setAttribute("data-namespace","virtualscroll"),t.head.appendChild(d)}(window,document,0,0,0,0,0,0,[["fetch-helper","nqhdrz5d",1,[["changed",5],["el",7],["list",5],["selector",1,0,1,2]]],["virtual-scroll","kbufhwni",1,[["bottomOffset",1,0,"bottom-offset",4],["changed",5],["clear",6],["el",7],["forceUpdateComponent",6],["list",1],["refresh",6],["scrollToNode",6],["selector",1,0,1,2],["setInfinateFinally",6],["setInfinateOn",6],["virtualRatio",1,0,"virtual-ratio",4]]]],HTMLElement.prototype); -------------------------------------------------------------------------------- /www/build/virtualscroll/kbufhwni.es5.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | virtualscroll.loadBundle("kbufhwni",["exports"],function(t){var i=window.virtualscroll.h,e=function(){function t(){this.list=[],this.selector="",this.bottomOffset=0,this.virtualRatio=3,this.changed=[],this.position=0,this.parentScrollHeight=0,this.vscrollOffsetTop=0,this.elementOffsetTop=0,this.infinateOn=!0,this.infinateFinally=!1,this.totalHeight=0,this.listDimensions=[],this.initRender=!1,this.toNextUpdateDimensions=!1,this.scrollEventDispatch=function(){}}return t.prototype.watchHandler=function(t,i){var e=this;if(i.length>0){var n=i.filter(function(i){return 0==t.filter(function(t){return t.index==i.index}).length});n.length>0&&n.map(function(t){e._deleteDimension(t.index)})}this.list.map(function(t,i){t.index||(t.index=i)}),this.updateVirtual(!0),this._setDimensions()},t.prototype.componentDidLoad=function(){var t=this;this._setDefParams(),this.selector.length>0?this.parentScroll=this.el.closest("."+this.selector):this.parentScroll=this.el.querySelector(".vscroll"),this.parentScrollHeight=this.parentScroll.offsetHeight,this.contentEl=this.el.querySelector(".vscroll-content");var i=this.el.querySelector(".vscroll");this.vscrollOffsetTop=i?i.offsetTop:0,this.scrollEventDispatch=this.parentScroll.addEventListener("scroll",function(){t.parentScroll.scrollTop-t.vscrollOffsetTop-t.elementOffsetTop+t.parentScrollHeight<0||(t.position=t.parentScroll.scrollTop-t.vscrollOffsetTop-t.elementOffsetTop,t.updateVirtual())},!1)},t.prototype.unwatch=function(){this.parentScroll&&this.parentScroll.removeEventListener("scroll",this._listener)},t.prototype._listener=function(){this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop,this.updateVirtual()},t.prototype.componentDidUnload=function(){this.unwatch(),this.scrollEventDispatch&&(this.scrollEventDispatch(),this.scrollEventDispatch=null)},t.prototype.componentWillLoad=function(){},t.prototype._setDefParams=function(){this.first=null,this.last=null,this.listDimensions=[],this.totalHeight=0,this.position=0,this.infinateOn=!0,this.infinateFinally=!1},t.prototype.updateVirtual=function(t){var i=this;void 0===t&&(t=!1);var e=this.first?this.first.rindex:0,n=this.last?this.last.rindex:0;if(this.first=this.listDimensions.filter(function(t){return i.position>=t.start&&i.position=t.start&&i.position+i.parentScroll.clientHeight=this.list.length?this.list.length:this.last.rindex+this.virtualRatio,o=this.first.rindex-this.virtualRatio<0?0:this.first.rindex-this.virtualRatio;s==this.list.length&&this.totalHeight-this.position-this.parentScrollHeight<0&&(o=e-this.virtualRatio<0?0:e-this.virtualRatio,this.first=this.listDimensions.filter(function(t){return t.rindex==e})[0]);var l=[];this.list.length>0&&(l=this.list.slice(o,s)),(e!=this.first.rindex||n!=this.last.rindex||t)&&(requestAnimationFrame(function(){var e=i.listDimensions.filter(function(t){return t.rindex==o})[0];e&&(i.contentEl.style.transform="translateY("+e.start+"px)",i.contentEl.style.webkitTransform="translateY("+e.start+"px)"),i.update.emit(l),t&&(i.changed=i.changed.concat([""]))}),this.changed=this.changed.concat([""]))}else if(this.list.length>0){var r=this.list.slice(0,20);this.update.emit(r),this.changed=this.changed.concat([""])}this.last&&this.last.rindex>=this.list.length-1-this.bottomOffset&&this.infinateOn&&!this.infinateFinally&&this.list.length>0&&(this.infinateOn=!1,this.toBottom.emit(this.position))},t.prototype.setInfinateOn=function(){this.infinateOn=!0},t.prototype.setInfinateFinally=function(){this.infinateFinally=!0},t.prototype.clear=function(){var t=this;this._setDefParams(),requestAnimationFrame(function(){t.list=[],t.contentEl.style.transform="translateY(0px)",t.contentEl.style.webkitTransform="translateY(0px)",t.changed=t.changed.concat([""])})},t.prototype.scrollToNode=function(t,i,e){if(void 0===e&&(e=0),this.parentScroll)if(t<=this.listDimensions.length-1){var n=this.listDimensions.filter(function(i){return i.rindex==t})[0];this._scrollTo(n.start+e,i)}else this._scrollToIndex(t)},t.prototype._scrollToIndex=function(t){var i=this;setTimeout(function(){i.parentScroll.scrollTop=i.parentScroll.scrollTop+100,i.first&&i.first.rindex===t||i._scrollToIndex(t)},10)},t.prototype._scrollTo=function(t,i){var e=this;if(!(i<=0)){var n=(t-this.parentScroll.scrollTop)/i*10;setTimeout(function(){e.parentScroll.scrollTop=e.parentScroll.scrollTop+n,e.parentScroll.scrollTop!==t&&e._scrollTo(t,i-10)},10)}},t.prototype._setDimensions=function(){var t=this.totalHeight;this.toNextUpdateDimensions&&(this.listDimensions=[]),this.toNextUpdateDimensions=!1;var i=this.el.querySelectorAll(".virtual-slot .virtual-item");if(i.length>0)for(var e=function(t){var e=i[t],s=e.id;n.listDimensions.filter(function(t){return t.rindex==s})[0]||(n._addNewDimensionToEnd(e.offsetHeight,s),n.totalHeight=n.listDimensions[n.listDimensions.length-1].end)},n=this,s=0;s<=i.length-1;s++)e(s);return this.totalHeight!=t},t.prototype._addNewDimensionToEnd=function(t,i){var e=this.listDimensions.length>0?this.listDimensions[this.listDimensions.length-1].end:0;this.listDimensions.push({height:t,start:e,end:e+t,rindex:parseInt(i)})},t.prototype._deleteDimension=function(t){var i=this.listDimensions.filter(function(i){return i.rindex==t})[0];if(i){i.start=0,i.end=0;for(var e=t+1;e<=this.listDimensions.length-1;e++)this.listDimensions[e].start=this.listDimensions[e].start-i.height,this.listDimensions[e].end=this.listDimensions[e].end-i.height;var n=this.listDimensions.filter(function(t){return t.end>0});0==n.length?this.totalHeight=0:this.totalHeight=n[n.length-1].end}},t.prototype.refresh=function(){this.toNextUpdateDimensions=!0},t.prototype.forceUpdateComponent=function(){this.__didUpdate(!0)},t.prototype._testDimensions=function(){var t=this.el.querySelector(".virtual-slot").childNodes;if(t.length>0)for(var i=function(i){var n=t[i],s=n.id,o=e.listDimensions.filter(function(t){return t.rindex==s})[0];o&&(o.height,n.offsetHeight)},e=this,n=0;n<=t.length-1;n++)i(n)},t.prototype.componentDidUpdate=function(){this.__didUpdate(!1)},t.prototype.__didUpdate=function(t){var i=this._setDimensions();this.initRender?((i||t)&&(this.changed=this.changed.concat([""])),this._testDimensions()):(this.initRender=!0,this.selector.length>0&&(this.elementOffsetTop=this.el.offsetTop),this.updateVirtual())},t.prototype.render=function(){return i("div",{class:"vscroll "+(this.selector.length>0?"external ":"inner ")+(this.infinateFinally?"infinate-finally ":" ")+(0==this.list.length?"cleared":"")},i("div",{class:"vscroll-back",style:{height:this.totalHeight+"px"}}),i("div",{class:"vscroll-content "+(this.selector.length>0?"external":"inner")},i("slot",{name:"virtual"})),i("slot",{name:"loader"}))},Object.defineProperty(t,"is",{get:function(){return"virtual-scroll"},enumerable:!0,configurable:!0}),Object.defineProperty(t,"properties",{get:function(){return{bottomOffset:{type:Number,attr:"bottom-offset"},changed:{state:!0},clear:{method:!0},el:{elementRef:!0},forceUpdateComponent:{method:!0},list:{type:"Any",attr:"list",watchCallbacks:["watchHandler"]},refresh:{method:!0},scrollToNode:{method:!0},selector:{type:String,attr:"selector"},setInfinateFinally:{method:!0},setInfinateOn:{method:!0},virtualRatio:{type:Number,attr:"virtual-ratio"}}},enumerable:!0,configurable:!0}),Object.defineProperty(t,"events",{get:function(){return[{name:"toBottom",method:"toBottom",bubbles:!0,cancelable:!0,composed:!0},{name:"update",method:"update",bubbles:!0,cancelable:!0,composed:!0}]},enumerable:!0,configurable:!0}),Object.defineProperty(t,"style",{get:function(){return".vscroll.inner{overflow-y:auto;height:100%}.vscroll.external{overflow-y:hidden}.vscroll{overflow-x:hidden;position:relative;display:block}.vscroll .vscroll-back{width:1px;opacity:0}.vscroll .vscroll-content{top:0;left:0;width:100%;position:absolute}.vscroll .vscroll-content.inner{height:100%}.infinate-finally div[slot=loader]{visibility:hidden}.cleared div[slot=loader]{display:none}virual-scroll{height:100%;display:block}"},enumerable:!0,configurable:!0}),t}();t.VirtualScroll=e,Object.defineProperty(t,"__esModule",{value:!0})}); -------------------------------------------------------------------------------- /www/build/virtualscroll/kbufhwni.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | const{h:t}=window.virtualscroll;class i{constructor(){this.list=[],this.selector="",this.bottomOffset=0,this.virtualRatio=3,this.changed=[],this.position=0,this.parentScrollHeight=0,this.vscrollOffsetTop=0,this.elementOffsetTop=0,this.infinateOn=!0,this.infinateFinally=!1,this.totalHeight=0,this.listDimensions=[],this.initRender=!1,this.toNextUpdateDimensions=!1,this.scrollEventDispatch=(()=>void 0)}watchHandler(t,i){if(i.length>0){let s=i.filter(i=>0==t.filter(t=>t.index==i.index).length);s.length>0&&s.map(t=>{this._deleteDimension(t.index)})}this.list.map((t,i)=>{t.index||(t.index=i)}),this.updateVirtual(!0),this._setDimensions()}componentDidLoad(){this._setDefParams(),this.selector.length>0?this.parentScroll=this.el.closest("."+this.selector):this.parentScroll=this.el.querySelector(".vscroll"),this.parentScrollHeight=this.parentScroll.offsetHeight,this.contentEl=this.el.querySelector(".vscroll-content");let t=this.el.querySelector(".vscroll");this.vscrollOffsetTop=t?t.offsetTop:0,this.scrollEventDispatch=this.parentScroll.addEventListener("scroll",()=>{this.parentScroll.scrollTop-this.vscrollOffsetTop-this.elementOffsetTop+this.parentScrollHeight<0||(this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop-this.elementOffsetTop,this.updateVirtual())},!1)}unwatch(){this.parentScroll&&this.parentScroll.removeEventListener("scroll",this._listener)}_listener(){this.position=this.parentScroll.scrollTop-this.vscrollOffsetTop,this.updateVirtual()}componentDidUnload(){this.unwatch(),this.scrollEventDispatch&&(this.scrollEventDispatch(),this.scrollEventDispatch=null)}componentWillLoad(){}_setDefParams(){this.first=null,this.last=null,this.listDimensions=[],this.totalHeight=0,this.position=0,this.infinateOn=!0,this.infinateFinally=!1}updateVirtual(t=!1){let i=this.first?this.first.rindex:0,s=this.last?this.last.rindex:0;if(this.first=this.listDimensions.filter(t=>this.position>=t.start&&this.positionthis.position+this.parentScroll.clientHeight>=t.start&&this.position+this.parentScroll.clientHeight=this.list.length?this.list.length:this.last.rindex+this.virtualRatio,l=this.first.rindex-this.virtualRatio<0?0:this.first.rindex-this.virtualRatio;e==this.list.length&&this.totalHeight-this.position-this.parentScrollHeight<0&&(l=i-this.virtualRatio<0?0:i-this.virtualRatio,this.first=this.listDimensions.filter(t=>t.rindex==i)[0]);let n=[];this.list.length>0&&(n=this.list.slice(l,e)),(i!=this.first.rindex||s!=this.last.rindex||t)&&(requestAnimationFrame(()=>{let i=this.listDimensions.filter(t=>t.rindex==l)[0];i&&(this.contentEl.style.transform="translateY("+i.start+"px)",this.contentEl.style.webkitTransform="translateY("+i.start+"px)"),this.update.emit(n),t&&(this.changed=[...this.changed,""])}),this.changed=[...this.changed,""])}else if(this.list.length>0){let t=this.list.slice(0,20);this.update.emit(t),this.changed=[...this.changed,""]}this.last&&this.last.rindex>=this.list.length-1-this.bottomOffset&&this.infinateOn&&!this.infinateFinally&&this.list.length>0&&(this.infinateOn=!1,this.toBottom.emit(this.position))}setInfinateOn(){this.infinateOn=!0}setInfinateFinally(){this.infinateFinally=!0}clear(){this._setDefParams(),requestAnimationFrame(()=>{this.list=[],this.contentEl.style.transform="translateY(0px)",this.contentEl.style.webkitTransform="translateY(0px)",this.changed=[...this.changed,""]})}scrollToNode(t,i,s=0){if(this.parentScroll)if(t<=this.listDimensions.length-1){let e=this.listDimensions.filter(i=>i.rindex==t)[0];this._scrollTo(e.start+s,i)}else this._scrollToIndex(t)}_scrollToIndex(t){setTimeout(()=>{this.parentScroll.scrollTop=this.parentScroll.scrollTop+100,this.first&&this.first.rindex===t||this._scrollToIndex(t)},10)}_scrollTo(t,i){if(i<=0)return;let s=(t-this.parentScroll.scrollTop)/i*10;setTimeout(()=>{this.parentScroll.scrollTop=this.parentScroll.scrollTop+s,this.parentScroll.scrollTop!==t&&this._scrollTo(t,i-10)},10)}_setDimensions(){let t=this.totalHeight;this.toNextUpdateDimensions&&(this.listDimensions=[]),this.toNextUpdateDimensions=!1;let i=this.el.querySelectorAll(".virtual-slot .virtual-item");if(i.length>0)for(let t=0;t<=i.length-1;t++){let s=i[t],e=s.id;this.listDimensions.filter(t=>t.rindex==e)[0]||(this._addNewDimensionToEnd(s.offsetHeight,e),this.totalHeight=this.listDimensions[this.listDimensions.length-1].end)}return this.totalHeight!=t}_addNewDimensionToEnd(t,i){let s=this.listDimensions.length>0?this.listDimensions[this.listDimensions.length-1].end:0;this.listDimensions.push({height:t,start:s,end:s+t,rindex:parseInt(i)})}_deleteDimension(t){let i=this.listDimensions.filter(i=>i.rindex==t)[0];if(i){i.start=0,i.end=0;for(let s=t+1;s<=this.listDimensions.length-1;s++)this.listDimensions[s].start=this.listDimensions[s].start-i.height,this.listDimensions[s].end=this.listDimensions[s].end-i.height;let s=this.listDimensions.filter(t=>t.end>0);0==s.length?this.totalHeight=0:this.totalHeight=s[s.length-1].end}}refresh(){this.toNextUpdateDimensions=!0}forceUpdateComponent(){this.__didUpdate(!0)}_testDimensions(){let t=this.el.querySelector(".virtual-slot").childNodes;if(t.length>0)for(let i=0;i<=t.length-1;i++){let s=t[i],e=s.id,l=this.listDimensions.filter(t=>t.rindex==e)[0];l&&(l.height,s.offsetHeight)}}componentDidUpdate(){this.__didUpdate(!1)}__didUpdate(t){let i=this._setDimensions();this.initRender?((i||t)&&(this.changed=[...this.changed,""]),this._testDimensions()):(this.initRender=!0,this.selector.length>0&&(this.elementOffsetTop=this.el.offsetTop),this.updateVirtual())}render(){return t("div",{class:"vscroll "+(this.selector.length>0?"external ":"inner ")+(this.infinateFinally?"infinate-finally ":" ")+(0==this.list.length?"cleared":"")},t("div",{class:"vscroll-back",style:{height:this.totalHeight+"px"}}),t("div",{class:"vscroll-content "+(this.selector.length>0?"external":"inner")},t("slot",{name:"virtual"})),t("slot",{name:"loader"}))}static get is(){return"virtual-scroll"}static get properties(){return{bottomOffset:{type:Number,attr:"bottom-offset"},changed:{state:!0},clear:{method:!0},el:{elementRef:!0},forceUpdateComponent:{method:!0},list:{type:"Any",attr:"list",watchCallbacks:["watchHandler"]},refresh:{method:!0},scrollToNode:{method:!0},selector:{type:String,attr:"selector"},setInfinateFinally:{method:!0},setInfinateOn:{method:!0},virtualRatio:{type:Number,attr:"virtual-ratio"}}}static get events(){return[{name:"toBottom",method:"toBottom",bubbles:!0,cancelable:!0,composed:!0},{name:"update",method:"update",bubbles:!0,cancelable:!0,composed:!0}]}static get style(){return".vscroll.inner{overflow-y:auto;height:100%}.vscroll.external{overflow-y:hidden}.vscroll{overflow-x:hidden;position:relative;display:block}.vscroll .vscroll-back{width:1px;opacity:0}.vscroll .vscroll-content{top:0;left:0;width:100%;position:absolute}.vscroll .vscroll-content.inner{height:100%}.infinate-finally div[slot=loader]{visibility:hidden}.cleared div[slot=loader]{display:none}virual-scroll{height:100%;display:block}"}}export{i as VirtualScroll}; -------------------------------------------------------------------------------- /www/build/virtualscroll/nqhdrz5d.es5.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | virtualscroll.loadBundle("nqhdrz5d",["exports"],function(e){var t=window.virtualscroll.h,n=function(){function e(){this.list=[],this.selector="",this.virtual=[],this.changed=[]}return e.prototype.componentWillLoad=function(){this.request()},e.prototype.request=function(){var e=this,t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json",token:"kRuGZ3Xd"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,n.addEventListener("toBottom",function(){e.lazyRequest()}),n.addEventListener("update",function(t){console.log("update"),e.virtual=t.detail,e.changed=e.changed.concat([""])})})},e.prototype.lazyRequest=function(){var e=this,t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){setTimeout(function(){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,e.list.length>200?n.setInfinateFinally():n.setInfinateOn()},3e3)})},e.prototype.reload=function(){var e=this,t=this.el.querySelector("virtual-scroll");t.list=[],t.clear(),this.changed=this.changed.concat([""]),setTimeout(function(){var t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},n=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(n).then(function(e){return e.json()}).then(function(t){t.splice(0,50).map(function(t){t.index=e.list.length,e.list=e.list.concat([t])});var n=e.el.querySelector("virtual-scroll");n.list=e.list,e.list.length>200?n.setInfinateFinally():n.setInfinateOn()})},2e3)},e.prototype.scrolling=function(){this.el.querySelector("virtual-scroll").scrollToNode(25,1e3,-50)},e.prototype.render=function(){return[t("div",{onClick:this.reload.bind(this),class:"reload"},"reload"),t("div",{onClick:this.scrolling.bind(this),class:"scrolling"},"scrolling"),t("div",{class:"virtual-container"},t("virtual-scroll",{"bottom-offset":"5","virtual-ratio":"15",selector:this.selector},t("div",{slot:"virtual",class:"virtual-slot"},this.virtual.map(function(e){return t("div",{class:"offer virtual-item",id:e.index},t("div",{style:{backgroundImage:"url("+e.thumbnailUrl+")"},class:"cover"}),t("div",{class:"title"},e.index),t("div",{class:"title"},e.title))})),t("div",{slot:"loader"},"loading...")))]},Object.defineProperty(e,"is",{get:function(){return"fetch-helper"},enumerable:!0,configurable:!0}),Object.defineProperty(e,"properties",{get:function(){return{changed:{state:!0},el:{elementRef:!0},list:{state:!0},selector:{type:String,attr:"selector"}}},enumerable:!0,configurable:!0}),Object.defineProperty(e,"style",{get:function(){return".cover{position:relative;width:150px;height:150px;background-size:cover;margin:0 auto}.title{font-size:15px;height:40px;text-align:center}.cover:after{content:\"\";display:block;padding-bottom:67%}.reload,.scrolling{position:absolute;top:0;margin:10px;padding:10px;background:#ccc;cursor:pointer;z-index:1}.scrolling{right:0}.reload{left:0}"},enumerable:!0,configurable:!0}),e}();e.FetchHelper=n,Object.defineProperty(e,"__esModule",{value:!0})}); -------------------------------------------------------------------------------- /www/build/virtualscroll/nqhdrz5d.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | const{h:t}=window.virtualscroll;class e{constructor(){this.list=[],this.selector="",this.virtual=[],this.changed=[]}componentWillLoad(){this.request()}request(){let t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json",token:"kRuGZ3Xd"})},e=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(e).then(t=>t.json()).then(t=>{t.splice(0,50).map(t=>{t.index=this.list.length,this.list=[...this.list,t]});const e=this.el.querySelector("virtual-scroll");e.list=this.list,e.addEventListener("toBottom",()=>{this.lazyRequest()}),e.addEventListener("update",t=>{console.log("update"),this.virtual=t.detail,this.changed=[...this.changed,""]})})}lazyRequest(){let t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},e=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(e).then(t=>t.json()).then(t=>{setTimeout(()=>{t.splice(0,50).map(t=>{t.index=this.list.length,this.list=[...this.list,t]});const e=this.el.querySelector("virtual-scroll");e.list=this.list,this.list.length>200?e.setInfinateFinally():e.setInfinateOn()},3e3)})}reload(){const t=this.el.querySelector("virtual-scroll");t.list=[],t.clear(),this.changed=[...this.changed,""],setTimeout(()=>{let t={method:"GET",mode:"cors",headers:new Headers({"Content-Type":"application/json"})},e=new Request("https://jsonplaceholder.typicode.com/photos",t);fetch(e).then(t=>t.json()).then(t=>{t.splice(0,50).map(t=>{t.index=this.list.length,this.list=[...this.list,t]});const e=this.el.querySelector("virtual-scroll");e.list=this.list,this.list.length>200?e.setInfinateFinally():e.setInfinateOn()})},2e3)}scrolling(){this.el.querySelector("virtual-scroll").scrollToNode(25,1e3,-50)}render(){return[t("div",{onClick:this.reload.bind(this),class:"reload"},"reload"),t("div",{onClick:this.scrolling.bind(this),class:"scrolling"},"scrolling"),t("div",{class:"virtual-container"},t("virtual-scroll",{"bottom-offset":"5","virtual-ratio":"15",selector:this.selector},t("div",{slot:"virtual",class:"virtual-slot"},this.virtual.map(e=>t("div",{class:"offer virtual-item",id:e.index},t("div",{style:{backgroundImage:"url("+e.thumbnailUrl+")"},class:"cover"}),t("div",{class:"title"},e.index),t("div",{class:"title"},e.title)))),t("div",{slot:"loader"},"loading...")))]}static get is(){return"fetch-helper"}static get properties(){return{changed:{state:!0},el:{elementRef:!0},list:{state:!0},selector:{type:String,attr:"selector"}}}static get style(){return".cover{position:relative;width:150px;height:150px;background-size:cover;margin:0 auto}.title{font-size:15px;height:40px;text-align:center}.cover:after{content:\"\";display:block;padding-bottom:67%}.reload,.scrolling{position:absolute;top:0;margin:10px;padding:10px;background:#ccc;cursor:pointer;z-index:1}.scrolling{right:0}.reload{left:0}"}}export{e as FetchHelper}; -------------------------------------------------------------------------------- /www/build/virtualscroll/virtualscroll.4u6xzod9.js: -------------------------------------------------------------------------------- 1 | /*! Built with http://stenciljs.com */ 2 | (function(Context,namespace,hydratedCssClass,resourcesUrl,s){"use strict"; 3 | s=document.querySelector("script[data-namespace='virtualscroll']");if(s){resourcesUrl=s.getAttribute('data-resources-url');} 4 | (function(t,e,n,o){"use strict";function i(t){return{t:t[0],e:t[1],n:!!t[2],o:!!t[3],i:!!t[4]}}function r(t,e){if(P(e)&&"object"!=typeof e&&"function"!=typeof e){if(t===Boolean||3===t)return"false"!==e&&(""===e||!!e);if(t===Number||4===t)return parseFloat(e);if(t===String||2===t)return e.toString()}return e}function c(t,e,n,o){const i=t.r.get(e);i&&((o=i["s-ld"]||i.$activeLoading)&&((n=o.indexOf(e))>-1&&o.splice(n,1),o.length||(i["s-init"]&&i["s-init"](),i.$initLoad&&i.$initLoad())),t.r.delete(e))}function s(t,e,n){let o,i,r=null,c=!1,s=!1;for(var f=arguments.length;f-- >2;)L.push(arguments[f]);for(;L.length>0;)if((n=L.pop())&&void 0!==n.pop)for(f=n.length;f--;)L.push(n[f]);else"boolean"==typeof n&&(n=null),(s="function"!=typeof t)&&(null==n?n="":"number"==typeof n?n=String(n):"string"!=typeof n&&(s=!1)),s&&c?r[r.length-1].c+=n:null===r?r=[s?{c:n}:n]:r.push(s?{c:n}:n),c=s;if(null!=e){if(e.className&&(e.class=e.className),"object"==typeof e.class){for(f in e.class)e.class[f]&&L.push(f);e.class=L.join(" "),L.length=0}null!=e.key&&(o=e.key),null!=e.name&&(i=e.name)}return"function"==typeof t?t(Object.assign({},e,{children:r}),q):{s:t,f:r,c:void 0,l:e,u:o,a:i,p:void 0,d:!1}}function f(t,e,n,o){e.split(" ").forEach(e=>{t[e]=!0,n&&(t[`${e}-${n}`]=!0,o&&(t[`${e}-${n}-${o}`]=t[`${e}-${o}`]=!0))})}function l(t,e){t.m.has(e)||(t.m.set(e,!0),t.b?t.queue.write(()=>u(t,e)):t.queue.tick(()=>u(t,e)))}function u(t,e,n,o,i,r){if(t.m.delete(e),!t.v.has(e)){if(o=t.y.get(e),n=!o){if((i=t.r.get(e))&&i.$rendered&&(i["s-rn"]=!0),i&&!i["s-rn"])return(i["s-rc"]=i["s-rc"]||[]).push(()=>{u(t,e)}),void(i.$onRender=i["s-rc"]);o=function c(t,e,n,o,i,r,s){try{(function f(t,e,n,o,i,r,c){for(c in t.w.set(o,n),t.g.has(n)||t.g.set(n,{}),(r=Object.assign({color:{type:String}},e.properties)).mode={type:String},r)p(t,r[c],n,o,c,i)})(t,i=t.M(e).k,e,o=new i,n),function l(t,e,n){if(e){const o=t.w.get(n);e.forEach(e=>{n[e.method]={emit:n=>{t.j(o,e.name,{bubbles:e.bubbles,composed:e.composed,cancelable:e.cancelable,detail:n})}}})}}(t,i.events,o);try{if(r=t.O.get(e)){for(s=0;sa(t,e,o,n)):a(t,e,o,n)}}function a(t,e,n,o){(function i(t,e,n,o){try{const i=e.k.host,r=e.k.encapsulation,c="shadow"===r&&t.N.x;let l,u;if(l=function i(t,e,n){return t&&Object.keys(t).forEach(o=>{t[o].reflectToAttr&&((n=n||{})[o]=e[o])}),n}(e.k.properties,o),u=c?n.shadowRoot:n,!n["s-rn"]){t.A(t,t.N,e,n);const i=n["s-sc"];i&&(t.N.P(n,function r(t){return`${t}-host`}(i),""),o.render||t.N.P(n,function c(t){return`${t}-slot`}(i),""))}if(o.render||o.hostData||i||l){t.T=!0;const a=o.render&&o.render();let p;if((p=o.hostData&&o.hostData())&&e.S){const t=Object.keys(p).reduce((t,n)=>e.S[n]?t.concat(n):e.S[S(n)]?t.concat(S(n)):t,[]);if(t.length>0)throw new Error("The following keys were attempted to be set with hostData() from the "+`${e.R} component: ${t.join(", ")}. `+"If you would like to modify these please set @Prop({ mutable: true, reflectToAttr: true}) on the @Prop() decorator.")}l&&(p=p?Object.assign(p,l):l),t.T=!1,i&&(p=function l(t,e,n){return t=t||{},Object.keys(e).forEach(o=>{"theme"===o?f(t.class=t.class||{},e[o],n.mode,n.color):"class"===o?f(t[o]=t[o]||{},e[o]):t[o]=e[o]}),t}(p,i,o));const d=t.L.get(n)||{};d.p=u;const m=s(null,p,a);m.d=!0,t.L.set(n,t.render(n,d,m,c,r))}t.q&&t.q.D(n),n["s-rn"]=!0,n.$onRender&&(n["s-rc"]=n.$onRender),n["s-rc"]&&(n["s-rc"].forEach(t=>t()),n["s-rc"]=null)}catch(e){t.T=!1,t.C(e,8,n,!0)}})(t,t.M(e),e,n);try{o?e["s-init"]():(n.componentDidUpdate&&n.componentDidUpdate(),g(t.L.get(e)))}catch(n){t.C(n,6,e,!0)}}function p(t,e,n,o,i,c,s,f){if(e.type||e.state){const l=t.g.get(n);e.state||(!e.attr||void 0!==l[i]&&""!==l[i]||(s=c&&c.I)&&P(f=s[e.attr])&&(l[i]=r(e.type,f)),n.hasOwnProperty(i)&&(void 0===l[i]&&(l[i]=r(e.type,n[i])),delete n[i])),o.hasOwnProperty(i)&&void 0===l[i]&&(l[i]=o[i]),e.watchCallbacks&&(l[D+i]=e.watchCallbacks.slice()),h(o,i,function l(e){return(e=t.g.get(t.w.get(this)))&&e[i]},function u(n,o){(o=t.w.get(this))&&(e.state||e.mutable)&&d(t,o,i,n)})}else if(e.elementRef)m(o,i,n);else if(e.method)m(n,i,o[i].bind(o));else if(e.context){const r=t.B(e.context);void 0!==r&&m(o,i,r.H&&r.H(n)||r)}else e.connect&&m(o,i,t.F(e.connect))}function d(t,e,n,o,i,r,c){(i=t.g.get(e))||t.g.set(e,i={});const s=i[n];if(o!==s&&(i[n]=o,r=t.y.get(e))){if(c=i[D+n])for(let t=0;te!==t[s]));for(s=0,f=n.length;s=0;r--)(c=l[r])["s-hn"]!==h&&c["s-ol"]&&(e.rt(c),e.ct(f(c),c,s(c)),e.rt(c["s-ol"]),c["s-ol"]=null,m=!0),i&&o(c,i);t.ot=!1}function i(t,o,i,r,c,f,l,u){const a=t["s-cr"]||t.$defaultHolder;for((l=a&&e.st(a)||t).shadowRoot&&e.ft(l)===h&&(l=l.shadowRoot);c<=f;++c)r[c]&&(u=P(r[c].c)?e.Y(r[c].c):n(null,i,c,t))&&(r[c].p=u,e.ct(l,u,s(o)))}function r(t,n,i,r){for(;n<=i;++n)P(t[n])&&(r=t[n].p,d=!0,r["s-ol"]?e.rt(r["s-ol"]):o(r,!0),e.rt(r))}function c(t,e){return t.s===e.s&&t.u===e.u&&("slot"!==t.s||t.a===e.a)}function s(t){return t&&t["s-ol"]?t["s-ol"]:t}function f(t){return e.st(t["s-ol"]?t["s-ol"]:t)}const l=[];let u,a,p,d,m,h,b;return function v(y,w,g,k,M,j,O,W,x,E,N,A){if(h=e.ft(y),b=y["s-cr"],u=k,a="shadow"!==M?j:null,p=y["s-sc"],m=d=!1,function l(u,a,p){const d=a.p=u.p,m=u.f,h=a.f;H=a.p&&P(e.lt(a.p))&&void 0!==a.p.ownerSVGElement,H="svg"===a.s||"foreignObject"!==a.s&&H,P(a.c)?(p=d["s-cr"]||d.$defaultHolder)?e.ut(e.st(p),a.c):u.c!==a.c&&e.ut(d,a.c):("slot"!==a.s&&$(t,u,a,H),P(m)&&P(h)?function b(t,u,a,p,d,m,h,v){let y=0,$=0,w=u.length-1,g=u[0],k=u[w],M=p.length-1,j=p[0],O=p[M];for(;y<=w&&$<=M;)if(null==g)g=u[++y];else if(null==k)k=u[--w];else if(null==j)j=p[++$];else if(null==O)O=p[--M];else if(c(g,j))l(g,j),g=u[++y],j=p[++$];else if(c(k,O))l(k,O),k=u[--w],O=p[--M];else if(c(g,O))"slot"!==g.s&&"slot"!==O.s||o(e.st(g.p)),l(g,O),e.ct(t,g.p,e.at(k.p)),g=u[++y],O=p[--M];else if(c(k,j))"slot"!==g.s&&"slot"!==O.s||o(e.st(k.p)),l(k,j),e.ct(t,k.p,g.p),k=u[--w],j=p[++$];else{for(d=null,m=y;m<=w;++m)if(u[m]&&P(u[m].u)&&u[m].u===j.u){d=m;break}P(d)?((v=u[d]).s!==j.s?h=n(u&&u[$],a,d,t):(l(v,j),u[d]=void 0,h=v.p),j=p[++$]):(h=n(u&&u[$],a,$,t),j=p[++$]),h&&e.ct(f(g.p),h,s(g.p))}y>w?i(t,null==p[M+1]?null:p[M+1].p,a,p,$,M):$>M&&r(u,y,w)}(d,m,a,h):P(h)?(P(u.c)&&e.ut(d,""),i(d,null,a,h,0,h.length-1)):P(m)&&r(m,0,m.length-1)),H&&"svg"===a.s&&(H=!1)}(w,g),P(a)&&e.P(w.p,C,a),m){for(function t(n,o,i,r,c,s,f,u,a,p){for(c=0,s=(o=e.it(n)).length;c=0;f--)(r=u[f])["s-cn"]||r["s-nr"]||r["s-hn"]===i["s-hn"]||((3===(p=e.pt(r))||8===p)&&""===a||1===p&&null===e.dt(r,"slot")&&""===a||1===p&&e.dt(r,"slot")===a)&&(l.some(t=>t.mt===r)||(d=!0,r["s-sn"]=a,l.push({ht:i,mt:r})));1===e.pt(i)&&t(i)}}(g.p),O=0;O{g(t,e)}))}function k(t,e,n,o,i){const r=t.pt(e);let c,s,f,l;if(i&&1===r){(s=t.dt(e,W))&&(f=s.split("."))[0]===o&&((l={}).s=t.ft(l.p=e),n.f||(n.f=[]),n.f[f[1]]=l,n=l,i=""!==f[2]);for(let r=0;r{const o=t[n];let i;const r={name:n};if(o.state)i="states",r.yt=o.watchCallbacks||[];else if(o.elementRef)i="elements";else if(o.method)i="methods";else{i="props";let t="any";o.type&&(t=o.type,"function"==typeof o.type&&(t=o.type.name)),r.type=t.toLowerCase(),r.mutable=o.mutable||!1,r.connect=o.connect||"-",r.context=o.connect||"-",r.yt=o.watchCallbacks||[]}return e[i].push(r),e},{$t:[],wt:[],gt:[],kt:[]})}(i.properties||{}),s=(o.Mt||[]).map(t=>({jt:t.t,capture:t.i,disabled:t.n,passive:t.o,method:t.e})),f=i.events||[],l=Object.assign({Ot:i.is,Ct:o.Wt||"unknown",encapsulation:i.encapsulation||"none"},r,{events:{xt:f,listeners:s}});return Promise.resolve(l)}function j(t,e,n,o){n.connectedCallback=function(){(function n(t,e,o){t.Et.has(o)||(t.Et.set(o,!0),function i(t,e){const n=t.M(e);n.Mt&&n.Mt.forEach(n=>{n.n||t.N.J(e,n.t,function o(t,e,n,i){return o=>{(i=t.y.get(e))?i[n](o):((i=t.O.get(e)||[]).push(n,o),t.O.set(e,i))}}(t,e,n.e),n.i,n.o)})}(t,o)),t.v.delete(o),t.Nt.has(o)||(t.Nt.set(o,!0),o["s-id"]||(o["s-id"]=t.At()),function r(t,e,n){for(n=e;n=t.N.lt(n);)if(t.Pt(n)){t.Tt.has(e)||(t.r.set(e,n),n.$activeLoading&&(n["s-ld"]=n.$activeLoading),(n["s-ld"]=n["s-ld"]||[]).push(e));break}}(t,o),t.queue.tick(()=>t.St(e,o,function n(t,e,o,i,r){return o.mode||(o.mode=t.Rt(o)),o["s-cr"]||t.dt(o,C)||t.x&&1===e.encapsulation||(o["s-cr"]=t.Y(""),o["s-cr"]["s-cn"]=!0,t.ct(o,o["s-cr"],t.it(o)[0])),t.x||1!==e.encapsulation||"shadowRoot"in HTMLElement.prototype||(o.shadowRoot=o),1===e.encapsulation&&t.x&&(o.shadowRoot,t.Lt(o,{mode:"open"})),i={qt:o["s-id"],I:{}},e.S&&Object.keys(e.S).forEach(n=>{(r=e.S[n].z)&&(i.I[r]=t.dt(o,r))}),i}(t.N,e,o))))})(t,e,this)},n.attributeChangedCallback=function(t,n,o){(function i(t,e,n,o,c,s,f){if(t&&o!==c)for(s in t)if((f=t[s]).z&&T(f.z)===T(n)){e[s]=r(f.Q,c);break}})(e.S,this,t,n,o)},n.disconnectedCallback=function(){(function e(t,n){if(!t.ot&&function o(t,e){for(;e;){if(!t.st(e))return 9!==t.pt(e);e=t.st(e)}}(t.N,n)){t.v.set(n,!0),c(t,n),g(t.L.get(n),!0),t.N.K(n),t.Et.delete(n);{const e=t.y.get(n);e&&e.componentDidUnload&&e.componentDidUnload()}t.q&&t.q.Dt(n),[t.r,t.It,t.W].forEach(t=>t.delete(n))}})(t,this)},n["s-init"]=function(){(function e(t,n,o,i,r){if(!t.Tt.has(n)&&(i=t.y.get(n))&&!t.v.has(n)&&(!n["s-ld"]||!n["s-ld"].length)){delete n["s-ld"],t.Tt.set(n,!0);try{g(t.L.get(n)),(r=t.It.get(n))&&(r.forEach(t=>t(n)),t.It.delete(n)),i.componentDidLoad&&i.componentDidLoad()}catch(e){t.C(e,4,n)}n.classList.add(o),c(t,n)}})(t,this,o)},n.forceUpdate=function(){l(t,this)},function i(t,e,n){e&&Object.keys(e).forEach(o=>{const i=e[o],c=i.Bt;1===c||2===c?h(n,o,function e(){return(t.g.get(this)||{})[o]},function e(n){d(t,this,o,r(i.Q,n))}):6===c&&m(n,o,R)})}(t,e.S,n)}function O(t,e,n,o){return function(){const i=arguments;return function r(t,e,n){let o=e[n];return o||(o=t.Ht.querySelector(n)),o||(o=e[n]=t.tt(n),t.et(t.Ht,o)),o.componentOnReady()}(t,e,n).then(t=>t[o].apply(t,i))}}const C="data-ssrv",W="data-ssrc",x="$",E={},N=[],A={enter:13,escape:27,space:32,tab:9,left:37,up:38,right:39,down:40},P=t=>null!=t,T=t=>t.toLowerCase(),S=t=>T(t).split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(""),R=()=>{},L=[],q={getAttributes:t=>t.l,replaceAttributes:(t,e)=>t.l=e},D="wc-",I={allowfullscreen:1,async:1,autofocus:1,autoplay:1,checked:1,controls:1,disabled:1,enabled:1,formnovalidate:1,hidden:1,multiple:1,noresize:1,readonly:1,required:1,selected:1,spellcheck:1},B="http://www.w3.org/1999/xlink";let H=!1;(function F(t,e,n,o,r,c){function f(t,e){if(!n.customElements.get(t.R)){j(v,u[t.R]=t,e.prototype,c);{const n=e.observedAttributes=[];for(const e in t.S)t.S[e].z&&n.push(t.S[e].z)}n.customElements.define(t.R,e)}}const u={html:{}},a={},p=n[t]=n[t]||{},d=function m(t,e,n){t.Ft||(t.Ft=((t,e,n,o)=>t.addEventListener(e,n,o)),t.Ut=((t,e,n,o)=>t.removeEventListener(e,n,o)));const o=new WeakMap,i={zt:n.documentElement,Qt:n.head,Ht:n.body,Zt:!1,pt:t=>t.nodeType,tt:t=>n.createElement(t),_:(t,e)=>n.createElementNS(t,e),Y:t=>n.createTextNode(t),nt:t=>n.createComment(t),ct:(t,e,n)=>t.insertBefore(e,n),rt:t=>t.remove(),et:(t,e)=>t.appendChild(e),it:t=>t.childNodes,st:t=>t.parentNode,at:t=>t.nextSibling,bt:t=>t.previousSibling,ft:t=>T(t.nodeName),vt:t=>t.textContent,ut:(t,e)=>t.textContent=e,dt:(t,e)=>t.getAttribute(e),P:(t,e,n)=>t.setAttribute(e,n),Gt:(t,e,n,o)=>t.setAttributeNS(e,n,o),G:(t,e)=>t.removeAttribute(e),Z:(t,e)=>t.hasAttribute(e),Rt:e=>e.getAttribute("mode")||(t.Context||{}).mode,Jt:(t,o)=>"child"===o?t.firstElementChild:"parent"===o?i.lt(t):"body"===o?i.Ht:"document"===o?n:"window"===o?e:t,J:(e,n,r,c,s,f,l,u)=>{const a=n;let p=e,d=o.get(e);if(d&&d[a]&&d[a](),"string"==typeof f?p=i.Jt(e,f):"object"==typeof f?p=f:(u=n.split(":")).length>1&&(p=i.Jt(e,u[0]),n=u[1]),!p)return;let m=r;(u=n.split(".")).length>1&&(n=u[0],m=(t=>{t.keyCode===A[u[1]]&&r(t)})),l=i.Zt?{capture:!!c,passive:!!s}:!!c,t.Ft(p,n,m,l),d||o.set(e,d={}),d[a]=(()=>{p&&t.Ut(p,n,m,l),d[a]=null})},K:(t,e)=>{const n=o.get(t);n&&(e?n[e]&&n[e]():Object.keys(n).forEach(t=>{n[t]&&n[t]()}))},Lt:(t,e)=>t.attachShadow(e)};i.x=!!i.zt.attachShadow,e.location.search.indexOf("shadow=false")>0&&(i.x=!1),i.Kt=((t,n,o)=>t&&t.dispatchEvent(new e.CustomEvent(n,o)));try{e.addEventListener("e",null,Object.defineProperty({},"passive",{get:()=>i.Zt=!0}))}catch(t){}return i.lt=((t,e)=>(e=i.st(t))&&11===i.pt(e)?e.host:e),i}(p,n,o);e.isServer=e.isPrerender=!(e.isClient=!0),e.window=n,e.location=n.location,e.document=o,e.resourcesUrl=e.publicPath=r,e.enableListener=((t,e,n,o,i)=>(function r(t,e,n,o,i,c){if(e){const r=t.w.get(e),s=t.M(r);if(s&&s.Mt)if(o){const o=s.Mt.find(t=>t.t===n);o&&t.N.J(r,n,t=>e[o.e](t),o.i,void 0===c?o.o:!!c,i)}else t.N.K(r,n)}})(v,t,e,n,o,i)),e.emit=((t,n,o)=>d.Kt(t,e.eventNameFn?e.eventNameFn(n):n,o)),p.h=s,p.Context=e;const h=n["s-defined"]=n.$definedCmps=n["s-defined"]||n.$definedCmps||{};let b=0;const v={N:d,Vt:f,j:e.emit,M:t=>u[d.ft(t)],B:t=>e[t],isClient:!0,Pt:t=>!(!h[d.ft(t)]&&!v.M(t)),At:()=>t+b++,C:(t,e,n)=>void 0,F:t=>(function e(t,n,o){return{create:O(t,n,o,"create"),componentOnReady:O(t,n,o,"componentOnReady")}})(d,a,t),queue:e.queue=function y(t,e){function n(t){for(let e=0;e0&&(u.push(...l),l.length=0),(p=f.length+l.length+u.length>0)?t.raf(i):a=0}const r=()=>e.performance.now(),c=Promise.resolve(),s=[],f=[],l=[],u=[];let a=0,p=!1;return t.raf||(t.raf=e.requestAnimationFrame.bind(e)),{tick(t){s.push(t),1===s.length&&c.then(()=>n(s))},read(e){f.push(e),p||(p=!0,t.raf(i))},write(e){l.push(e),p||(p=!0,t.raf(i))}}}(p,n),St:function $(t,e){if(t.k)l(v,e);else{const n="string"==typeof t.Wt?t.Wt:t.Wt[e.mode],o=2===t.encapsulation||1===t.encapsulation&&!d.x;import(r+n+(o?".sc":"")+".js").then(n=>{try{(function o(t,e,n){const o=n.style;if(o){const i=n.is+(n.styleMode||x);if(!e[i]){const n=t.tt("template");e[i]=n,t.P(n,"data-tmpl-style-id",i),n.innerHTML=``,t.et(t.Qt,n)}}})(d,t,t.k=n[S(t.R)])}catch(e){t.k=class{}}l(v,e)}).catch(t=>void 0)}},r:new WeakMap,Xt:new WeakMap,Nt:new WeakMap,Et:new WeakMap,Tt:new WeakMap,w:new WeakMap,W:new WeakMap,y:new WeakMap,v:new WeakMap,m:new WeakMap,It:new WeakMap,O:new WeakMap,L:new WeakMap,g:new WeakMap};v.render=w(v,d);const g=d.zt;g["s-ld"]=[],g["s-rn"]=!0,g["s-init"]=(()=>{v.Tt.set(g,p.loaded=v.b=!0),d.Kt(n,"appload",{detail:{namespace:t}})}),function W(t,e,n){const o=n.querySelectorAll(`[${C}]`),i=o.length;let r,c,s,f,l,u;if(i>0)for(t.Tt.set(n,!0),f=0;f{(function i(t,e,n,o){const i=n.k.styleMode,r=n.encapsulation;(2===r||1===r&&!t.N.x)&&(o["s-sc"]=function c(t,e){const n=`data-${t.R}`;return e&&e!==x?`${n}-${e}`:n}(n,i));const s=n.R+(i||x),f=n[s];if(f){let n=e.Qt;if(e.x)if(1===r)n=o.shadowRoot;else{let t=o;for(;t=e.st(t);)if(t.host&&t.host.shadowRoot){n=t.host.shadowRoot;break}}let i=t.Xt.get(n);if(i||t.Xt.set(n,i={}),!i[s]){let t;{t=f.content.cloneNode(!0),i[s]=!0;const o=n.querySelectorAll("[data-styles]");e.ct(n,t,o.length&&o[o.length-1].nextSibling||n.firstChild)}}}})(t,e,n,o)}),function E(t,e,n,o){const i=n.Yt=n.Yt||{};return i._t=i._t||[],i._t.push(function r(t,e,n){return{namespace:e,te:t=>t&&t.tagName?Promise.all([M(n,t.tagName),function e(t,n){return Promise.resolve(t.y.get(n))}(n,t)]).then(t=>t[0]&&t[1]?{ee:t[0],ne:t[1]}:null):Promise.resolve(null),oe:t=>M(n,t),ie:()=>Promise.all(t.components.map(t=>M(n,t[0]))).then(t=>t.filter(t=>t))}}(t,e,o)),i.te||(i.te=(t=>Promise.all(i._t.map(e=>e.te(t))).then(t=>t.find(t=>!!t)))),i.ie||(i.ie=(()=>{const t=[];return i._t.forEach(e=>{t.push(e.ie())}),Promise.all(t).then(t=>{const e=[];return t.forEach(t=>{t.forEach(t=>{e.push(t)})}),e})})),i}(p,t,n,v),(p.components||[]).map(t=>{const e=function n(t,e,o){const r={R:t[0],S:{color:{z:"color"}}};r.Wt=t[1];const c=t[3];if(c)for(e=0;ef(t,class extends HTMLElement{})),function N(t,e,n,o,i,r){if(e.componentOnReady=((e,n)=>{if(!e.nodeName.includes("-"))return n(null),!1;const o=t.M(e);if(o)if(t.Tt.has(e))n(e);else{const o=t.It.get(e)||[];o.push(n),t.It.set(e,o)}return!!o}),i){for(r=i.length-1;r>=0;r--)e.componentOnReady(i[r][0],i[r][1])&&i.splice(r,1);for(r=0;r Stencil Component Starter
--------------------------------------------------------------------------------