@plcmp/pl-virtual-scroll 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plcmp/pl-virtual-scroll",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Component for lazy list render.",
5
5
  "main": "pl-virtual-scroll.js",
6
6
  "repository": {
@@ -23,7 +23,7 @@
23
23
  }
24
24
  ],
25
25
  "dependencies": {
26
- "polylib": "^1.0.0",
26
+ "polylib": "^1.1.0",
27
27
  "@plcmp/utils": "^0.1.0"
28
28
  }
29
29
  }
@@ -1,5 +1,7 @@
1
- import { html, PlElement, TemplateInstance, createContext } from "polylib";
1
+ import { html, PlElement, TemplateInstance } from "polylib";
2
2
  import { PlaceHolder } from "@plcmp/utils";
3
+ import {ContextMixin} from "polylib/engine/v1/ctx.js";
4
+ import {normalizePath} from "polylib/common.js";
3
5
 
4
6
  /** @typedef VirtualScrollItem
5
7
  * @property {LightDataContext} ctx
@@ -20,7 +22,7 @@ class PlVirtualScroll extends PlElement {
20
22
  renderedStart: { type: Number, value: 0 },
21
23
  renderedCount: { type: Number, value: 0 },
22
24
  phyItems: { type: Array, value: () => [] },
23
- canvas: { type: Object }
25
+ canvas: { type: Object },
24
26
  }
25
27
  static template = html`
26
28
  <style>
@@ -30,48 +32,52 @@ class PlVirtualScroll extends PlElement {
30
32
  display: block;
31
33
  }
32
34
 
33
- pl-virtual-scroll #vsCanvas {
35
+ pl-virtual-scroll #vs-canvas {
34
36
  position: relative;
35
37
  /*noinspection CssUnresolvedCustomProperty*/
36
38
  contain: strict;
37
39
  }
38
40
 
39
- .vsItem {
41
+ .vs-item {
40
42
  position: absolute;
41
43
  left: 0;
42
44
  top: 0;
45
+ width: 100%;
46
+ }
47
+ #vsCanvas {
48
+ position: relative;
43
49
  }
44
50
  </style>
45
- <div id="vsCanvas">
46
- </div>
51
+ <div id="vsCanvas"></div>
47
52
  `;
48
-
53
+ static repTpl = html`<template d:repeat="{{phyItems}}" d:as="[[as]]"><div class="vs-item">[[sTpl]]</div></template>`;
49
54
  connectedCallback() {
50
55
  super.connectedCallback();
51
- let canvas = this.canvas ?? this.$.vsCanvas;
52
- canvas.parentNode.addEventListener('scroll', this.onScroll.bind(this));
53
- let tpl = this.querySelector('template');
54
- this.oTpl = tpl;
55
- this.rTpl = tpl.tpl;//new Template(`<div class="vsItem">${tpl.innerHTML}</div>`);
56
- this._pti = tpl._pti;
57
- this._hti = tpl._hti;
58
- this.pctx = tpl._pti?.ctx;
56
+
57
+ this.canvas = this.canvas ?? this.$.vsCanvas;
58
+ this.canvas.parentNode.addEventListener('scroll', e => this.onScroll(e) );
59
+
60
+ this.sTpl = [...this.childNodes].find( n => n.nodeType === document.COMMENT_NODE && n.textContent.startsWith('tpl:'))?._tpl;
61
+
62
+ /* let ti = new TemplateInstance(PlVirtualScroll.repTpl);
63
+ ti.attach(canvas, this, this);
64
+ */
59
65
  /* render items if them already assigned */
60
- if (Array.isArray(this.items) && this.items.length > 0) {
66
+ /*if (Array.isArray(this.items) && this.items.length > 0) {
61
67
  this.render();
62
- }
68
+ }*/
63
69
  }
64
70
  _dataChanged(data, old, mutation) {
65
71
  // set microtask, element may be not inserted in dom tree yet,
66
72
  // but we need to know viewport height to render
67
- let [, index, ...rest] = mutation.path.split('.');
73
+ let [, index, ...rest] = normalizePath(mutation.path);
68
74
  switch (mutation.action) {
69
75
  case 'upd':
70
76
  if (index !== undefined && +index >= 0) {
71
77
  let el = this.phyPool.find(i => i.index === +index);
72
78
  if (el && rest.length > 0) {
73
79
  let path = [this.as, ...rest].join('.');
74
- el.ti.applyEffects({ ...mutation, path });
80
+ el.ctx.applyEffects({ ...mutation, path });
75
81
  if (this.items[el.index] instanceof PlaceHolder) this.items.load?.(this.items[el.index])
76
82
  }
77
83
  } else {
@@ -89,9 +95,8 @@ class PlVirtualScroll extends PlElement {
89
95
  if (i.index !== null && i.index >= spliceIndex && i.index < this.items.length) {
90
96
  if (this.items[i.index] instanceof PlaceHolder) this.items.load?.(this.items[i.index]);
91
97
  i.ctx.replace(this.items[i.index]);
92
- i.ti.ctx = i.ctx;
93
- i.ti.applyEffects();
94
- i.ti.applyBinds();
98
+ i.ctx.applyEffects();
99
+ i.ctx._ti.applyBinds();
95
100
  } else if (i.index >= this.items.length) {
96
101
  i.index = null;
97
102
  }
@@ -107,9 +112,7 @@ class PlVirtualScroll extends PlElement {
107
112
  * @param {Boolean} [scroll] - render for new scroll position
108
113
  */
109
114
  render(scroll) {
110
- // detect window height
111
- // detect new position,
112
- let canvas = this.canvas ?? this.$.vsCanvas;
115
+ let canvas = this.canvas;
113
116
  let offset = canvas.parentNode.scrollTop;
114
117
  let height = canvas.parentNode.offsetHeight;
115
118
  if (height === 0 || !this.items) return;
@@ -130,12 +133,6 @@ class PlVirtualScroll extends PlElement {
130
133
  let used = [], unused = [];
131
134
  this.phyPool.forEach(x => {
132
135
  if (x.index !== null && shadowBegin <= x.index && x.index <= shadowEnd && x.index < this.items.length) {
133
- if (x.ctx.model !== this.items[x.index]) {
134
- x.ctx.replace(this.items[x.index]);
135
- x.ti.ctx = x.ctx;
136
- x.ti.applyBinds();
137
- x.ti.applyEffects();
138
- }
139
136
  used.push(x);
140
137
  } else {
141
138
  unused.push(x);
@@ -167,7 +164,7 @@ class PlVirtualScroll extends PlElement {
167
164
 
168
165
  unused.forEach(u => {
169
166
  u.index = null;
170
- u.ti._nodes.forEach(i => { if (i.style) i.style.transform = `translateY(-100%)`; });
167
+ u.ctx._ti._nodes.forEach(i => { if (i.style) i.style.transform = `translateY(-100%)`; });
171
168
  });
172
169
 
173
170
  // fill .5 height window in background
@@ -202,14 +199,13 @@ class PlVirtualScroll extends PlElement {
202
199
  target.index = index;
203
200
  if (p_item) {
204
201
  p_item.ctx.replace(this.items[index])
205
- p_item.ti.ctx = p_item.ctx;
206
- p_item.ti.applyBinds();
207
- p_item.ti.applyEffects();
202
+ p_item.ctx._ti.applyBinds();
203
+ p_item.ctx.applyEffects();
208
204
  } else {
209
205
  this.phyPool.push(target);
210
206
  }
211
207
  target.offset = typeof (prev) == 'number' ? prev : (backward ? prev.offset - target.h : prev.offset + prev.h);
212
- target.ti._nodes.forEach(n => {
208
+ target.ctx._ti._nodes.forEach(n => {
213
209
  if (n.style) {
214
210
  n.style.transform = `translateY(${target.offset}px)`;
215
211
  n.style.position = 'absolute';
@@ -218,18 +214,47 @@ class PlVirtualScroll extends PlElement {
218
214
  return target;
219
215
  }
220
216
  createNewItem(v) {
221
- let ctx = createContext(this, v, this.as)
222
- let ti = new TemplateInstance(this.rTpl);
223
- ti._hti = this._hti;
224
- ctx._ti = ti;
225
- ti.attach({ ...ctx, root: this.canvas ?? this.$.vsCanvas }, undefined, this._pti);
226
- let h = this.elementHeight ?? calcNodesRect(ti._nodes).height;
227
-
228
- return { ctx, ti, h };
217
+ if (!this.sTpl) return;
218
+ let inst = new TemplateInstance(this.sTpl);
219
+
220
+ let ctx = new RepeatItem(v, this.as, (ctx, m) => this.onItemChanged(ctx, m) );
221
+ ctx._ti = inst
222
+ inst.attach(this.canvas, undefined, [ctx, ...this.sTpl._hctx ]);
223
+ let h = this.elementHeight ?? calcNodesRect(inst._nodes).height;
224
+
225
+ return { ctx, h };
229
226
  }
230
227
  onScroll() {
231
228
  this.render(true);
232
229
  }
230
+ onItemChanged(ctx, m) {
231
+ // skip replace data call
232
+ if (!m) return;
233
+ let ind = this.items.findIndex( i => i === ctx[this.as]);
234
+ if (ind < 0) console.warn('repeat item not found');
235
+ if (m.path === this.as) {
236
+ this.set(['items', ind], m.value, m.wmh);
237
+ } else {
238
+ this.forwardNotify(m,this.as, 'items.'+ind);
239
+ }
240
+
241
+ }
242
+ }
243
+
244
+ class RepeatItem extends ContextMixin(EventTarget) {
245
+ constructor(item, as, cb) {
246
+ super();
247
+ this.as = as;
248
+ this[as] = item;
249
+ this.addEffect(as, m => cb(this, m))
250
+ }
251
+ get model() {
252
+ return this[this.as];
253
+ }
254
+ replace(v) {
255
+ this[this.as] = v;
256
+ this.wmh = {};
257
+ }
233
258
  }
234
259
 
235
260
  function calcNodesRect(nodes) {