@fluid-topics/ft-infinite-scroll 0.3.12 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/ft-infinite-scroll.css.d.ts +5 -0
- package/build/ft-infinite-scroll.css.js +41 -0
- package/build/ft-infinite-scroll.d.ts +1 -9
- package/build/ft-infinite-scroll.js +4 -39
- package/build/ft-infinite-scroll.light.js +35 -35
- package/build/ft-infinite-scroll.min.js +35 -35
- package/build/ft-infinite-scroll.properties.d.ts +8 -0
- package/build/ft-infinite-scroll.properties.js +2 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +2 -0
- package/package.json +3 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { css } from "lit";
|
|
2
|
+
import { FtCssVariableFactory } from "@fluid-topics/ft-wc-utils";
|
|
3
|
+
export const FtInfiniteScrollCssVariables = {
|
|
4
|
+
padding: FtCssVariableFactory.create("--ft-infinite-scroll-padding", "SIZE", "0"),
|
|
5
|
+
};
|
|
6
|
+
// language=CSS
|
|
7
|
+
export const styles = css `
|
|
8
|
+
.items-container {
|
|
9
|
+
position: relative;
|
|
10
|
+
padding: ${FtInfiniteScrollCssVariables.padding};
|
|
11
|
+
outline: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.scrollable {
|
|
15
|
+
height: 100%;
|
|
16
|
+
overflow-y: auto;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.item-container {
|
|
20
|
+
height: 100vh;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.item-container + .item-container {
|
|
24
|
+
/*
|
|
25
|
+
We add a gap between items to be sure to hide the content above the targeted item
|
|
26
|
+
When a div is visible (even by a fraction of a pixel) if its height changes
|
|
27
|
+
the browser will try to keep the scroll stable in relation to the first visible element
|
|
28
|
+
By adding this gap we ensure that the previous item will be fully hidden and event if its size changes, it will not impact the scroll offset
|
|
29
|
+
*/
|
|
30
|
+
margin-top: 4px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.scrollable .item-container {
|
|
34
|
+
height: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.resizable:not(.rendered) {
|
|
38
|
+
width: 0;
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
//# sourceMappingURL=ft-infinite-scroll.css.js.map
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { PropertyValues, TemplateResult } from "lit";
|
|
2
2
|
import { FtLitElement } from "@fluid-topics/ft-wc-utils";
|
|
3
|
-
|
|
4
|
-
items: Array<T>;
|
|
5
|
-
renderItem: (item: T, index: number) => TemplateResult | string;
|
|
6
|
-
scrollToItem?: T;
|
|
7
|
-
scrollToIndex?: number;
|
|
8
|
-
}
|
|
9
|
-
export declare const FtInfiniteScrollCssVariables: {
|
|
10
|
-
padding: import("@fluid-topics/ft-wc-utils").FtCssVariable;
|
|
11
|
-
};
|
|
3
|
+
import { FtInfiniteScrollProperties } from "./ft-infinite-scroll.properties";
|
|
12
4
|
export declare type VisibleItems<T> = {
|
|
13
5
|
visibleIndexes: Array<number>;
|
|
14
6
|
visibleItems: Array<T>;
|
|
@@ -4,14 +4,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import {
|
|
7
|
+
import { html } from "lit";
|
|
8
8
|
import { property, query, state } from "lit/decorators.js";
|
|
9
9
|
import { repeat } from "lit/directives/repeat.js";
|
|
10
|
-
import { Debouncer,
|
|
10
|
+
import { Debouncer, FtLitElement, isSafari } from "@fluid-topics/ft-wc-utils";
|
|
11
11
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
12
|
-
|
|
13
|
-
padding: FtCssVariableFactory.create("--ft-infinite-scroll-padding", "SIZE", "0"),
|
|
14
|
-
};
|
|
12
|
+
import { styles } from "./ft-infinite-scroll.css";
|
|
15
13
|
export class VisibleItemsChangeEvent extends CustomEvent {
|
|
16
14
|
constructor(indexes, items) {
|
|
17
15
|
super("visible-items-change", {
|
|
@@ -215,40 +213,7 @@ export class FtInfiniteScroll extends FtLitElement {
|
|
|
215
213
|
}
|
|
216
214
|
}
|
|
217
215
|
// language=CSS
|
|
218
|
-
FtInfiniteScroll.styles =
|
|
219
|
-
.items-container {
|
|
220
|
-
position: relative;
|
|
221
|
-
padding: ${FtInfiniteScrollCssVariables.padding};
|
|
222
|
-
outline: none;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.scrollable {
|
|
226
|
-
height: 100%;
|
|
227
|
-
overflow-y: auto;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.item-container {
|
|
231
|
-
height: 100vh;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.item-container + .item-container {
|
|
235
|
-
/*
|
|
236
|
-
We add a gap between items to be sure to hide the content above the targeted item
|
|
237
|
-
When a div is visible (even by a fraction of a pixel) if its height changes
|
|
238
|
-
the browser will try to keep the scroll stable in relation to the first visible element
|
|
239
|
-
By adding this gap we ensure that the previous item will be fully hidden and event if its size changes, it will not impact the scroll offset
|
|
240
|
-
*/
|
|
241
|
-
margin-top: 4px;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
.scrollable .item-container {
|
|
245
|
-
height: 100%;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.resizable:not(.rendered) {
|
|
249
|
-
width: 0;
|
|
250
|
-
}
|
|
251
|
-
`;
|
|
216
|
+
FtInfiniteScroll.styles = styles;
|
|
252
217
|
__decorate([
|
|
253
218
|
property({ type: Array })
|
|
254
219
|
], FtInfiniteScroll.prototype, "items", void 0);
|
|
@@ -1,4 +1,37 @@
|
|
|
1
|
-
!function(t,e,i,s,l,n){
|
|
1
|
+
!function(t,e,i,s,l,n){const r={padding:e.FtCssVariableFactory.create("--ft-infinite-scroll-padding","SIZE","0")},o=i.css`
|
|
2
|
+
.items-container {
|
|
3
|
+
position: relative;
|
|
4
|
+
padding: ${r.padding};
|
|
5
|
+
outline: none;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.scrollable {
|
|
9
|
+
height: 100%;
|
|
10
|
+
overflow-y: auto;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.item-container {
|
|
14
|
+
height: 100vh;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.item-container + .item-container {
|
|
18
|
+
/*
|
|
19
|
+
We add a gap between items to be sure to hide the content above the targeted item
|
|
20
|
+
When a div is visible (even by a fraction of a pixel) if its height changes
|
|
21
|
+
the browser will try to keep the scroll stable in relation to the first visible element
|
|
22
|
+
By adding this gap we ensure that the previous item will be fully hidden and event if its size changes, it will not impact the scroll offset
|
|
23
|
+
*/
|
|
24
|
+
margin-top: 4px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.scrollable .item-container {
|
|
28
|
+
height: 100%;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.resizable:not(.rendered) {
|
|
32
|
+
width: 0;
|
|
33
|
+
}
|
|
34
|
+
`;var h=function(t,e,i,s){for(var l,n=arguments.length,r=n<3?e:null===s?s=Object.getOwnPropertyDescriptor(e,i):s,o=t.length-1;o>=0;o--)(l=t[o])&&(r=(n<3?l(r):n>3?l(e,i,r):l(e,i))||r);return n>3&&r&&Object.defineProperty(e,i,r),r};class a extends CustomEvent{constructor(t,e){super("visible-items-change",{detail:{visibleIndexes:t,visibleItems:e}})}}class d extends Event{constructor(){super("scrolled-to-target")}}class c extends e.FtLitElement{constructor(){super(...arguments),this.items=[],this.renderItem=()=>i.html``,this.internalScroll=!1,this.renderBeforeFirst=1,this.renderAfterLast=1,this.visibleItems=[],this.scrolledToTarget=!1,this.alreadyRenderedIndexes=new Set,this.scrollDebouncer=new e.Debouncer(5),this.onVisibilityChange=t=>{const e=t.filter((t=>t.intersectionRect.height>1)).map((t=>+t.target.attributes.getNamedItem("data-item-index").value)).filter((t=>!this.visibleItems.includes(t))),i=t.filter((t=>t.intersectionRect.height<=1)).map((t=>+t.target.attributes.getNamedItem("data-item-index").value)).filter((t=>this.visibleItems.includes(t))),s=[...this.visibleItems].filter((t=>!i.includes(t)));this.visibleItems=[...e,...s].sort(((t,e)=>t-e))},this.intersectionObserver=new IntersectionObserver(this.onVisibilityChange),this.onResize=t=>{this.triggerFindScrollableParent();let i=0;t=t.sort(((t,e)=>t.contentRect.top-e.contentRect.top));for(const e of t){const t=+e.target.parentElement.getAttribute("data-item-index"),s=e.target.parentElement.clientHeight,l=e.contentRect.height;this.alreadyRenderedIndexes.has(t)&&(e.target.parentElement.style.height=l+"px",i+=this.scrollable&&this.getOffset(e.target.parentElement)<this.scrollable.scrollTop+i?l-s:0)}this.scrollable&&e.isSafari&&(this.scrollable.scrollTop+=i)},this.resizeObserver=new ResizeObserver(this.onResize),this.onMutation=()=>{[...this.itemsContainer.children].forEach((t=>{this.intersectionObserver.observe(t),this.resizeObserver.observe(t.children.item(0))}))},this.mutationObserver=new MutationObserver(this.onMutation)}get scrollable(){return this.internalScroll?this.internalScrollable:this.firstScrollableParent}render(){return i.html`
|
|
2
35
|
<div class="items-container ${this.internalScroll?"scrollable":""}"
|
|
3
36
|
tabindex="-1"
|
|
4
37
|
@find-scrollable-parent=${this.findScrollableParent}>
|
|
@@ -12,37 +45,4 @@
|
|
|
12
45
|
${l?(()=>{const s=this.renderItem(t,e);return"string"==typeof s?i.html`${n.unsafeHTML(s)}`:s})():null}
|
|
13
46
|
</div>
|
|
14
47
|
</div>
|
|
15
|
-
`}resetScroll(){this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.visibleItems=[],this.scrolledToTarget=!1,this.scrollDebouncer.run((()=>{var t,e;let i=null!==(t=this.scrollToIndex)&&void 0!==t?t:this.scrollToItem?this.items.indexOf(this.scrollToItem):-1;i>=this.items.length&&(i=-1);let s=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector(`#item-${i}`);this.scrollToTarget(s),this.onMutation(),setTimeout((()=>{this.scrolledToTarget=!0}),10)}))}scrollToTarget(t){var e;if(t){let i=+(null!==(e=t.getAttribute("data-item-index"))&&void 0!==e?e:"0");this.scrollable?this.scrollable.scrollTop=i>0?this.getOffset(t)+1:0:t.scrollIntoView({block:"start"})}}getOffset(t){var e;let i=0,s=t;for(;s&&s.offsetParent!==this.scrollable.offsetParent;)i+=s.offsetTop,s=s.offsetParent;return i+(null!==(e=null==s?void 0:s.offsetTop)&&void 0!==e?e:0)-this.scrollable.offsetTop}appendItems(...t){this.items=[...this.items,...t]}prependItems(...t){this.items=[...t,...this.items]}connectedCallback(){super.connectedCallback(),setTimeout((()=>{this.triggerFindScrollableParent(),this.intersectionObserver.disconnect(),this.intersectionObserver=new IntersectionObserver(this.onVisibilityChange,{rootMargin:"-2px",threshold:[0,.01,.1]}),this.mutationObserver.disconnect(),this.mutationObserver.observe(this.itemsContainer,{childList:!0})}),0)}triggerFindScrollableParent(){this.itemsContainer.dispatchEvent(new Event("find-scrollable-parent",{composed:!0}))}findScrollableParent(t){t.stopPropagation();for(let e of t.composedPath()){const t=e;if(t.clientHeight&&t.clientHeight<t.scrollHeight&&["auto","scroll"].includes(getComputedStyle(t).overflowY)){this.firstScrollableParent=t;break}}}disconnectedCallback(){super.disconnectedCallback(),this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.mutationObserver.disconnect()}firstUpdated(t){super.firstUpdated(t),this.resetScroll()}update(t){super.update(t),t.has("items")&&(this.alreadyRenderedIndexes=new Set),(t.has("scrollToItem")||t.has("scrollToIndex"))&&this.resetScroll()}updated(t){super.updated(t),(t.has("visibleItems")||t.has("items"))&&this.dispatchEvent(new
|
|
16
|
-
.items-container {
|
|
17
|
-
position: relative;
|
|
18
|
-
padding: ${o.padding};
|
|
19
|
-
outline: none;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.scrollable {
|
|
23
|
-
height: 100%;
|
|
24
|
-
overflow-y: auto;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.item-container {
|
|
28
|
-
height: 100vh;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.item-container + .item-container {
|
|
32
|
-
/*
|
|
33
|
-
We add a gap between items to be sure to hide the content above the targeted item
|
|
34
|
-
When a div is visible (even by a fraction of a pixel) if its height changes
|
|
35
|
-
the browser will try to keep the scroll stable in relation to the first visible element
|
|
36
|
-
By adding this gap we ensure that the previous item will be fully hidden and event if its size changes, it will not impact the scroll offset
|
|
37
|
-
*/
|
|
38
|
-
margin-top: 4px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.scrollable .item-container {
|
|
42
|
-
height: 100%;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.resizable:not(.rendered) {
|
|
46
|
-
width: 0;
|
|
47
|
-
}
|
|
48
|
-
`,r([s.property({type:Array})],d.prototype,"items",void 0),r([s.property({attribute:!1})],d.prototype,"renderItem",void 0),r([s.property({type:Object})],d.prototype,"scrollToItem",void 0),r([s.property({type:Number})],d.prototype,"scrollToIndex",void 0),r([s.property({type:Boolean})],d.prototype,"internalScroll",void 0),r([s.property({type:Number})],d.prototype,"renderBeforeFirst",void 0),r([s.property({type:Number})],d.prototype,"renderAfterLast",void 0),r([s.state({hasChanged:(t,e)=>null!=t&&null==e||t.length!==e.length||t[0]!==e[0]})],d.prototype,"visibleItems",void 0),r([s.query(".scrollable")],d.prototype,"internalScrollable",void 0),r([s.query(".items-container")],d.prototype,"itemsContainer",void 0),r([s.state()],d.prototype,"scrolledToTarget",void 0),e.customElement("ft-infinite-scroll")(d),t.FtInfiniteScroll=d,t.FtInfiniteScrollCssVariables=o,t.ScrolledToTargetEvent=a,t.VisibleItemsChangeEvent=h,Object.defineProperty(t,"t",{value:!0})}({},ftGlobals.wcUtils,ftGlobals.lit,ftGlobals.litDecorators,ftGlobals.litRepeat,ftGlobals.litUnsafeHTML);
|
|
48
|
+
`}resetScroll(){this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.visibleItems=[],this.scrolledToTarget=!1,this.scrollDebouncer.run((()=>{var t,e;let i=null!==(t=this.scrollToIndex)&&void 0!==t?t:this.scrollToItem?this.items.indexOf(this.scrollToItem):-1;i>=this.items.length&&(i=-1);let s=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector(`#item-${i}`);this.scrollToTarget(s),this.onMutation(),setTimeout((()=>{this.scrolledToTarget=!0}),10)}))}scrollToTarget(t){var e;if(t){let i=+(null!==(e=t.getAttribute("data-item-index"))&&void 0!==e?e:"0");this.scrollable?this.scrollable.scrollTop=i>0?this.getOffset(t)+1:0:t.scrollIntoView({block:"start"})}}getOffset(t){var e;let i=0,s=t;for(;s&&s.offsetParent!==this.scrollable.offsetParent;)i+=s.offsetTop,s=s.offsetParent;return i+(null!==(e=null==s?void 0:s.offsetTop)&&void 0!==e?e:0)-this.scrollable.offsetTop}appendItems(...t){this.items=[...this.items,...t]}prependItems(...t){this.items=[...t,...this.items]}connectedCallback(){super.connectedCallback(),setTimeout((()=>{this.triggerFindScrollableParent(),this.intersectionObserver.disconnect(),this.intersectionObserver=new IntersectionObserver(this.onVisibilityChange,{rootMargin:"-2px",threshold:[0,.01,.1]}),this.mutationObserver.disconnect(),this.mutationObserver.observe(this.itemsContainer,{childList:!0})}),0)}triggerFindScrollableParent(){this.itemsContainer.dispatchEvent(new Event("find-scrollable-parent",{composed:!0}))}findScrollableParent(t){t.stopPropagation();for(let e of t.composedPath()){const t=e;if(t.clientHeight&&t.clientHeight<t.scrollHeight&&["auto","scroll"].includes(getComputedStyle(t).overflowY)){this.firstScrollableParent=t;break}}}disconnectedCallback(){super.disconnectedCallback(),this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.mutationObserver.disconnect()}firstUpdated(t){super.firstUpdated(t),this.resetScroll()}update(t){super.update(t),t.has("items")&&(this.alreadyRenderedIndexes=new Set),(t.has("scrollToItem")||t.has("scrollToIndex"))&&this.resetScroll()}updated(t){super.updated(t),(t.has("visibleItems")||t.has("items"))&&this.dispatchEvent(new a(this.visibleItems,this.visibleItems.map((t=>this.items[t])))),t.has("scrolledToTarget")&&this.scrolledToTarget&&this.dispatchEvent(new d)}}c.styles=o,h([s.property({type:Array})],c.prototype,"items",void 0),h([s.property({attribute:!1})],c.prototype,"renderItem",void 0),h([s.property({type:Object})],c.prototype,"scrollToItem",void 0),h([s.property({type:Number})],c.prototype,"scrollToIndex",void 0),h([s.property({type:Boolean})],c.prototype,"internalScroll",void 0),h([s.property({type:Number})],c.prototype,"renderBeforeFirst",void 0),h([s.property({type:Number})],c.prototype,"renderAfterLast",void 0),h([s.state({hasChanged:(t,e)=>null!=t&&null==e||t.length!==e.length||t[0]!==e[0]})],c.prototype,"visibleItems",void 0),h([s.query(".scrollable")],c.prototype,"internalScrollable",void 0),h([s.query(".items-container")],c.prototype,"itemsContainer",void 0),h([s.state()],c.prototype,"scrolledToTarget",void 0),e.customElement("ft-infinite-scroll")(c),t.FtInfiniteScroll=c,t.FtInfiniteScrollCssVariables=r,t.ScrolledToTargetEvent=d,t.VisibleItemsChangeEvent=a,t.styles=o,Object.defineProperty(t,"t",{value:!0})}({},ftGlobals.wcUtils,ftGlobals.lit,ftGlobals.litDecorators,ftGlobals.litRepeat,ftGlobals.litUnsafeHTML);
|
|
@@ -104,7 +104,40 @@ function(t){return class extends t{createRenderRoot(){const t=this.constructor,{
|
|
|
104
104
|
* Copyright 2017 Google LLC
|
|
105
105
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
106
106
|
*/
|
|
107
|
-
class Rt extends xt{constructor(t){if(super(t),this.it=H,t.type!==bt)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(t){if(t===H||null==t)return this._t=void 0,this.it=t;if(t===D)return t;if("string"!=typeof t)throw Error(this.constructor.directiveName+"() called with a non-string value");if(t===this.it)return this._t;this.it=t;const e=[t];return e.raw=e,this._t={_$litType$:this.constructor.resultType,strings:e,values:[]}}}Rt.directiveName="unsafeHTML",Rt.resultType=1;const St=mt(Rt)
|
|
107
|
+
class Rt extends xt{constructor(t){if(super(t),this.it=H,t.type!==bt)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(t){if(t===H||null==t)return this._t=void 0,this.it=t;if(t===D)return t;if("string"!=typeof t)throw Error(this.constructor.directiveName+"() called with a non-string value");if(t===this.it)return this._t;this.it=t;const e=[t];return e.raw=e,this._t={_$litType$:this.constructor.resultType,strings:e,values:[]}}}Rt.directiveName="unsafeHTML",Rt.resultType=1;const St=mt(Rt),Mt={padding:ht.create("--ft-infinite-scroll-padding","SIZE","0")},Ut=u`
|
|
108
|
+
.items-container {
|
|
109
|
+
position: relative;
|
|
110
|
+
padding: ${Mt.padding};
|
|
111
|
+
outline: none;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.scrollable {
|
|
115
|
+
height: 100%;
|
|
116
|
+
overflow-y: auto;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.item-container {
|
|
120
|
+
height: 100vh;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.item-container + .item-container {
|
|
124
|
+
/*
|
|
125
|
+
We add a gap between items to be sure to hide the content above the targeted item
|
|
126
|
+
When a div is visible (even by a fraction of a pixel) if its height changes
|
|
127
|
+
the browser will try to keep the scroll stable in relation to the first visible element
|
|
128
|
+
By adding this gap we ensure that the previous item will be fully hidden and event if its size changes, it will not impact the scroll offset
|
|
129
|
+
*/
|
|
130
|
+
margin-top: 4px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.scrollable .item-container {
|
|
134
|
+
height: 100%;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.resizable:not(.rendered) {
|
|
138
|
+
width: 0;
|
|
139
|
+
}
|
|
140
|
+
`;var kt=function(t,e,i,s){for(var n,o=arguments.length,r=o<3?e:null===s?s=Object.getOwnPropertyDescriptor(e,i):s,l=t.length-1;l>=0;l--)(n=t[l])&&(r=(o<3?n(r):o>3?n(e,i,r):n(e,i))||r);return o>3&&r&&Object.defineProperty(e,i,r),r};class Tt extends CustomEvent{constructor(t,e){super("visible-items-change",{detail:{visibleIndexes:t,visibleItems:e}})}}class At extends Event{constructor(){super("scrolled-to-target")}}class Ft extends ft{constructor(){super(...arguments),this.items=[],this.renderItem=()=>K``,this.internalScroll=!1,this.renderBeforeFirst=1,this.renderAfterLast=1,this.visibleItems=[],this.scrolledToTarget=!1,this.alreadyRenderedIndexes=new Set,this.scrollDebouncer=new e(5),this.onVisibilityChange=t=>{const e=t.filter((t=>t.intersectionRect.height>1)).map((t=>+t.target.attributes.getNamedItem("data-item-index").value)).filter((t=>!this.visibleItems.includes(t))),i=t.filter((t=>t.intersectionRect.height<=1)).map((t=>+t.target.attributes.getNamedItem("data-item-index").value)).filter((t=>this.visibleItems.includes(t))),s=[...this.visibleItems].filter((t=>!i.includes(t)));this.visibleItems=[...e,...s].sort(((t,e)=>t-e))},this.intersectionObserver=new IntersectionObserver(this.onVisibilityChange),this.onResize=t=>{this.triggerFindScrollableParent();let e=0;t=t.sort(((t,e)=>t.contentRect.top-e.contentRect.top));for(const i of t){const t=+i.target.parentElement.getAttribute("data-item-index"),s=i.target.parentElement.clientHeight,n=i.contentRect.height;this.alreadyRenderedIndexes.has(t)&&(i.target.parentElement.style.height=n+"px",e+=this.scrollable&&this.getOffset(i.target.parentElement)<this.scrollable.scrollTop+e?n-s:0)}this.scrollable&&vt&&(this.scrollable.scrollTop+=e)},this.resizeObserver=new ResizeObserver(this.onResize),this.onMutation=()=>{[...this.itemsContainer.children].forEach((t=>{this.intersectionObserver.observe(t),this.resizeObserver.observe(t.children.item(0))}))},this.mutationObserver=new MutationObserver(this.onMutation)}get scrollable(){return this.internalScroll?this.internalScrollable:this.firstScrollableParent}render(){return K`
|
|
108
141
|
<div class="items-container ${this.internalScroll?"scrollable":""}"
|
|
109
142
|
tabindex="-1"
|
|
110
143
|
@find-scrollable-parent=${this.findScrollableParent}>
|
|
@@ -118,37 +151,4 @@ class Rt extends xt{constructor(t){if(super(t),this.it=H,t.type!==bt)throw Error
|
|
|
118
151
|
${s?(()=>{const i=this.renderItem(t,e);return"string"==typeof i?K`${St(i)}`:i})():null}
|
|
119
152
|
</div>
|
|
120
153
|
</div>
|
|
121
|
-
`}resetScroll(){this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.visibleItems=[],this.scrolledToTarget=!1,this.scrollDebouncer.run((()=>{var t,e;let i=null!==(t=this.scrollToIndex)&&void 0!==t?t:this.scrollToItem?this.items.indexOf(this.scrollToItem):-1;i>=this.items.length&&(i=-1);let s=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector(`#item-${i}`);this.scrollToTarget(s),this.onMutation(),setTimeout((()=>{this.scrolledToTarget=!0}),10)}))}scrollToTarget(t){var e;if(t){let i=+(null!==(e=t.getAttribute("data-item-index"))&&void 0!==e?e:"0");this.scrollable?this.scrollable.scrollTop=i>0?this.getOffset(t)+1:0:t.scrollIntoView({block:"start"})}}getOffset(t){var e;let i=0,s=t;for(;s&&s.offsetParent!==this.scrollable.offsetParent;)i+=s.offsetTop,s=s.offsetParent;return i+(null!==(e=null==s?void 0:s.offsetTop)&&void 0!==e?e:0)-this.scrollable.offsetTop}appendItems(...t){this.items=[...this.items,...t]}prependItems(...t){this.items=[...t,...this.items]}connectedCallback(){super.connectedCallback(),setTimeout((()=>{this.triggerFindScrollableParent(),this.intersectionObserver.disconnect(),this.intersectionObserver=new IntersectionObserver(this.onVisibilityChange,{rootMargin:"-2px",threshold:[0,.01,.1]}),this.mutationObserver.disconnect(),this.mutationObserver.observe(this.itemsContainer,{childList:!0})}),0)}triggerFindScrollableParent(){this.itemsContainer.dispatchEvent(new Event("find-scrollable-parent",{composed:!0}))}findScrollableParent(t){t.stopPropagation();for(let e of t.composedPath()){const t=e;if(t.clientHeight&&t.clientHeight<t.scrollHeight&&["auto","scroll"].includes(getComputedStyle(t).overflowY)){this.firstScrollableParent=t;break}}}disconnectedCallback(){super.disconnectedCallback(),this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.mutationObserver.disconnect()}firstUpdated(t){super.firstUpdated(t),this.resetScroll()}update(t){super.update(t),t.has("items")&&(this.alreadyRenderedIndexes=new Set),(t.has("scrollToItem")||t.has("scrollToIndex"))&&this.resetScroll()}updated(t){super.updated(t),(t.has("visibleItems")||t.has("items"))&&this.dispatchEvent(new
|
|
122
|
-
.items-container {
|
|
123
|
-
position: relative;
|
|
124
|
-
padding: ${Ut.padding};
|
|
125
|
-
outline: none;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.scrollable {
|
|
129
|
-
height: 100%;
|
|
130
|
-
overflow-y: auto;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.item-container {
|
|
134
|
-
height: 100vh;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.item-container + .item-container {
|
|
138
|
-
/*
|
|
139
|
-
We add a gap between items to be sure to hide the content above the targeted item
|
|
140
|
-
When a div is visible (even by a fraction of a pixel) if its height changes
|
|
141
|
-
the browser will try to keep the scroll stable in relation to the first visible element
|
|
142
|
-
By adding this gap we ensure that the previous item will be fully hidden and event if its size changes, it will not impact the scroll offset
|
|
143
|
-
*/
|
|
144
|
-
margin-top: 4px;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.scrollable .item-container {
|
|
148
|
-
height: 100%;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
.resizable:not(.rendered) {
|
|
152
|
-
width: 0;
|
|
153
|
-
}
|
|
154
|
-
`,Mt([s({type:Array})],At.prototype,"items",void 0),Mt([s({attribute:!1})],At.prototype,"renderItem",void 0),Mt([s({type:Object})],At.prototype,"scrollToItem",void 0),Mt([s({type:Number})],At.prototype,"scrollToIndex",void 0),Mt([s({type:Boolean})],At.prototype,"internalScroll",void 0),Mt([s({type:Number})],At.prototype,"renderBeforeFirst",void 0),Mt([s({type:Number})],At.prototype,"renderAfterLast",void 0),Mt([n({hasChanged:(t,e)=>null!=t&&null==e||t.length!==e.length||t[0]!==e[0]})],At.prototype,"visibleItems",void 0),Mt([o(".scrollable")],At.prototype,"internalScrollable",void 0),Mt([o(".items-container")],At.prototype,"itemsContainer",void 0),Mt([n()],At.prototype,"scrolledToTarget",void 0),(Ft="ft-infinite-scroll",t=>{window.customElements.get(Ft)||window.customElements.define(Ft,t)})(At),t.FtInfiniteScroll=At,t.FtInfiniteScrollCssVariables=Ut,t.ScrolledToTargetEvent=Tt,t.VisibleItemsChangeEvent=kt,Object.defineProperty(t,"i",{value:!0})}({});
|
|
154
|
+
`}resetScroll(){this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.visibleItems=[],this.scrolledToTarget=!1,this.scrollDebouncer.run((()=>{var t,e;let i=null!==(t=this.scrollToIndex)&&void 0!==t?t:this.scrollToItem?this.items.indexOf(this.scrollToItem):-1;i>=this.items.length&&(i=-1);let s=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector(`#item-${i}`);this.scrollToTarget(s),this.onMutation(),setTimeout((()=>{this.scrolledToTarget=!0}),10)}))}scrollToTarget(t){var e;if(t){let i=+(null!==(e=t.getAttribute("data-item-index"))&&void 0!==e?e:"0");this.scrollable?this.scrollable.scrollTop=i>0?this.getOffset(t)+1:0:t.scrollIntoView({block:"start"})}}getOffset(t){var e;let i=0,s=t;for(;s&&s.offsetParent!==this.scrollable.offsetParent;)i+=s.offsetTop,s=s.offsetParent;return i+(null!==(e=null==s?void 0:s.offsetTop)&&void 0!==e?e:0)-this.scrollable.offsetTop}appendItems(...t){this.items=[...this.items,...t]}prependItems(...t){this.items=[...t,...this.items]}connectedCallback(){super.connectedCallback(),setTimeout((()=>{this.triggerFindScrollableParent(),this.intersectionObserver.disconnect(),this.intersectionObserver=new IntersectionObserver(this.onVisibilityChange,{rootMargin:"-2px",threshold:[0,.01,.1]}),this.mutationObserver.disconnect(),this.mutationObserver.observe(this.itemsContainer,{childList:!0})}),0)}triggerFindScrollableParent(){this.itemsContainer.dispatchEvent(new Event("find-scrollable-parent",{composed:!0}))}findScrollableParent(t){t.stopPropagation();for(let e of t.composedPath()){const t=e;if(t.clientHeight&&t.clientHeight<t.scrollHeight&&["auto","scroll"].includes(getComputedStyle(t).overflowY)){this.firstScrollableParent=t;break}}}disconnectedCallback(){super.disconnectedCallback(),this.intersectionObserver.disconnect(),this.resizeObserver.disconnect(),this.mutationObserver.disconnect()}firstUpdated(t){super.firstUpdated(t),this.resetScroll()}update(t){super.update(t),t.has("items")&&(this.alreadyRenderedIndexes=new Set),(t.has("scrollToItem")||t.has("scrollToIndex"))&&this.resetScroll()}updated(t){super.updated(t),(t.has("visibleItems")||t.has("items"))&&this.dispatchEvent(new Tt(this.visibleItems,this.visibleItems.map((t=>this.items[t])))),t.has("scrolledToTarget")&&this.scrolledToTarget&&this.dispatchEvent(new At)}}var Lt;Ft.styles=Ut,kt([s({type:Array})],Ft.prototype,"items",void 0),kt([s({attribute:!1})],Ft.prototype,"renderItem",void 0),kt([s({type:Object})],Ft.prototype,"scrollToItem",void 0),kt([s({type:Number})],Ft.prototype,"scrollToIndex",void 0),kt([s({type:Boolean})],Ft.prototype,"internalScroll",void 0),kt([s({type:Number})],Ft.prototype,"renderBeforeFirst",void 0),kt([s({type:Number})],Ft.prototype,"renderAfterLast",void 0),kt([n({hasChanged:(t,e)=>null!=t&&null==e||t.length!==e.length||t[0]!==e[0]})],Ft.prototype,"visibleItems",void 0),kt([o(".scrollable")],Ft.prototype,"internalScrollable",void 0),kt([o(".items-container")],Ft.prototype,"itemsContainer",void 0),kt([n()],Ft.prototype,"scrolledToTarget",void 0),(Lt="ft-infinite-scroll",t=>{window.customElements.get(Lt)||window.customElements.define(Lt,t)})(Ft),t.FtInfiniteScroll=Ft,t.FtInfiniteScrollCssVariables=Mt,t.ScrolledToTargetEvent=At,t.VisibleItemsChangeEvent=Tt,t.styles=Ut,Object.defineProperty(t,"i",{value:!0})}({});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TemplateResult } from "lit";
|
|
2
|
+
export interface FtInfiniteScrollProperties<T> {
|
|
3
|
+
items: Array<T>;
|
|
4
|
+
renderItem: (item: T, index: number) => TemplateResult | string;
|
|
5
|
+
scrollToItem?: T;
|
|
6
|
+
scrollToIndex?: number;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=ft-infinite-scroll.properties.d.ts.map
|
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { customElement } from "@fluid-topics/ft-wc-utils";
|
|
2
2
|
import { FtInfiniteScroll } from "./ft-infinite-scroll";
|
|
3
|
+
export * from "./ft-infinite-scroll.css";
|
|
4
|
+
export * from "./ft-infinite-scroll.properties";
|
|
3
5
|
export * from "./ft-infinite-scroll";
|
|
4
6
|
customElement("ft-infinite-scroll")(FtInfiniteScroll);
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-topics/ft-infinite-scroll",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.13",
|
|
4
4
|
"description": "An infinite scroller.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Lit"
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"url": "ssh://git@scm.mrs.antidot.net:2222/fluidtopics/ft-web-components.git"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@fluid-topics/ft-wc-utils": "0.3.
|
|
22
|
+
"@fluid-topics/ft-wc-utils": "0.3.13",
|
|
23
23
|
"lit": "2.2.8"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "84b5fc920bc5d2bdb646b5da8815ad51caaf228e"
|
|
26
26
|
}
|