vscroll 1.5.2 → 1.5.3-passive

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.
Files changed (73) hide show
  1. package/dist/bundles/vscroll.esm5.js +120 -62
  2. package/dist/bundles/vscroll.esm5.js.map +1 -1
  3. package/dist/bundles/vscroll.esm5.min.js +2 -2
  4. package/dist/bundles/vscroll.esm5.min.js.map +1 -1
  5. package/dist/bundles/vscroll.esm6.js +115 -56
  6. package/dist/bundles/vscroll.esm6.js.map +1 -1
  7. package/dist/bundles/vscroll.esm6.min.js +2 -2
  8. package/dist/bundles/vscroll.esm6.min.js.map +1 -1
  9. package/dist/bundles/vscroll.umd.js +121 -63
  10. package/dist/bundles/vscroll.umd.js.map +1 -1
  11. package/dist/bundles/vscroll.umd.min.js +2 -2
  12. package/dist/bundles/vscroll.umd.min.js.map +1 -1
  13. package/dist/esm2015/classes/adapter/context.js +11 -5
  14. package/dist/esm2015/classes/adapter/context.js.map +1 -1
  15. package/dist/esm2015/classes/adapter/props.js +4 -2
  16. package/dist/esm2015/classes/adapter/props.js.map +1 -1
  17. package/dist/esm2015/classes/adapter/wanted.js +29 -0
  18. package/dist/esm2015/classes/adapter/wanted.js.map +1 -0
  19. package/dist/esm2015/classes/adapter.js +65 -29
  20. package/dist/esm2015/classes/adapter.js.map +1 -1
  21. package/dist/esm2015/classes/datasource.js +2 -0
  22. package/dist/esm2015/classes/datasource.js.map +1 -1
  23. package/dist/esm2015/classes/domRoutines.js +1 -1
  24. package/dist/esm2015/classes/domRoutines.js.map +1 -1
  25. package/dist/esm2015/classes/logger.js +1 -1
  26. package/dist/esm2015/classes/logger.js.map +1 -1
  27. package/dist/esm2015/inputs/validation.js.map +1 -1
  28. package/dist/esm2015/interfaces/adapter.js.map +1 -1
  29. package/dist/esm2015/interfaces/index.js.map +1 -1
  30. package/dist/esm2015/interfaces/process.js.map +1 -1
  31. package/dist/esm2015/interfaces/workflow.js.map +1 -1
  32. package/dist/esm2015/processes/end.js +5 -18
  33. package/dist/esm2015/processes/end.js.map +1 -1
  34. package/dist/esm2015/scroller.js +1 -1
  35. package/dist/esm2015/scroller.js.map +1 -1
  36. package/dist/esm2015/version.js +1 -1
  37. package/dist/esm2015/version.js.map +1 -1
  38. package/dist/esm2015/workflow.js.map +1 -1
  39. package/dist/esm5/classes/adapter/context.js +11 -6
  40. package/dist/esm5/classes/adapter/context.js.map +1 -1
  41. package/dist/esm5/classes/adapter/props.js +4 -2
  42. package/dist/esm5/classes/adapter/props.js.map +1 -1
  43. package/dist/esm5/classes/adapter/wanted.js +30 -0
  44. package/dist/esm5/classes/adapter/wanted.js.map +1 -0
  45. package/dist/esm5/classes/adapter.js +69 -34
  46. package/dist/esm5/classes/adapter.js.map +1 -1
  47. package/dist/esm5/classes/datasource.js +2 -0
  48. package/dist/esm5/classes/datasource.js.map +1 -1
  49. package/dist/esm5/classes/domRoutines.js +1 -1
  50. package/dist/esm5/classes/domRoutines.js.map +1 -1
  51. package/dist/esm5/classes/logger.js +1 -1
  52. package/dist/esm5/classes/logger.js.map +1 -1
  53. package/dist/esm5/inputs/validation.js.map +1 -1
  54. package/dist/esm5/interfaces/adapter.js.map +1 -1
  55. package/dist/esm5/interfaces/index.js.map +1 -1
  56. package/dist/esm5/interfaces/process.js.map +1 -1
  57. package/dist/esm5/interfaces/workflow.js.map +1 -1
  58. package/dist/esm5/processes/end.js +5 -18
  59. package/dist/esm5/processes/end.js.map +1 -1
  60. package/dist/esm5/scroller.js +1 -1
  61. package/dist/esm5/scroller.js.map +1 -1
  62. package/dist/esm5/version.js +1 -1
  63. package/dist/esm5/version.js.map +1 -1
  64. package/dist/esm5/workflow.js.map +1 -1
  65. package/dist/typings/classes/adapter/wanted.d.ts +14 -0
  66. package/dist/typings/classes/adapter.d.ts +7 -4
  67. package/dist/typings/classes/logger.d.ts +1 -1
  68. package/dist/typings/interfaces/adapter.d.ts +6 -0
  69. package/dist/typings/interfaces/index.d.ts +2 -2
  70. package/dist/typings/interfaces/workflow.d.ts +1 -1
  71. package/dist/typings/processes/end.d.ts +1 -2
  72. package/dist/typings/workflow.d.ts +1 -1
  73. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * vscroll (https://github.com/dhilt/vscroll) FESM2015
3
- * Version: 1.5.2 (2022-09-12T12:01:26.863Z)
3
+ * Version: 1.5.3-passive (2022-11-04T12:11:44.543Z)
4
4
  * Author: Denis Hilt
5
5
  * License: MIT
6
6
  */
@@ -306,12 +306,14 @@ const getDefaultAdapterProps = () => [
306
306
  {
307
307
  type: Type.Reactive,
308
308
  name: Name.firstVisible$,
309
- value: new Reactive(EMPTY_ITEM, { emitOnSubscribe: true })
309
+ value: new Reactive(EMPTY_ITEM, { emitOnSubscribe: true }),
310
+ wanted: true
310
311
  },
311
312
  {
312
313
  type: Type.Reactive,
313
314
  name: Name.lastVisible$,
314
- value: new Reactive(EMPTY_ITEM, { emitOnSubscribe: true })
315
+ value: new Reactive(EMPTY_ITEM, { emitOnSubscribe: true }),
316
+ wanted: true
315
317
  },
316
318
  {
317
319
  type: Type.Reactive,
@@ -328,9 +330,37 @@ const reactiveConfigStorage = new Map();
328
330
 
329
331
  var core = {
330
332
  name: 'vscroll',
331
- version: '1.5.2'
333
+ version: '1.5.3-passive'
332
334
  };
333
335
 
336
+ const getBox = (id) => {
337
+ var _a;
338
+ return (_a = wantedStorage.get(id || -1)) === null || _a === void 0 ? void 0 : _a.box;
339
+ };
340
+ const setBox = ({ name, wanted }, id) => {
341
+ const Wanted = wantedStorage.get(id || -1);
342
+ if (wanted && Wanted && !Wanted.box[name] && !Wanted.block) {
343
+ const { firstVisible: a, firstVisible$: a$ } = AdapterPropName;
344
+ const { lastVisible: b, lastVisible$: b$ } = AdapterPropName;
345
+ Wanted.box[a] = Wanted.box[a$] = [a, a$].some(n => n === name) || Wanted.box[a];
346
+ Wanted.box[b] = Wanted.box[b$] = [b, b$].some(n => n === name) || Wanted.box[b];
347
+ return true;
348
+ }
349
+ return false;
350
+ };
351
+ const setBlock = (value, id) => {
352
+ const Wanted = wantedStorage.get(id || -1);
353
+ if (Wanted) {
354
+ Wanted.block = value;
355
+ }
356
+ };
357
+ const wantedUtils = {
358
+ getBox,
359
+ setBox,
360
+ setBlock
361
+ };
362
+ const wantedStorage = new Map();
363
+
334
364
  let instanceCount$1 = 0;
335
365
  class AdapterContext {
336
366
  constructor(config) {
@@ -338,6 +368,7 @@ class AdapterContext {
338
368
  const id = ++instanceCount$1;
339
369
  const conf = { configurable: true };
340
370
  const reactivePropsStore = {};
371
+ wantedStorage.set(id, { box: {}, block: false });
341
372
  // set up permanent props
342
373
  Object.defineProperty(this, AdapterPropName.id, Object.assign({ get: () => id }, conf));
343
374
  Object.defineProperty(this, AdapterPropName.mock, Object.assign({ get: () => mock }, conf));
@@ -346,20 +377,24 @@ class AdapterContext {
346
377
  // set up default props, they will be reassigned during the Adapter instantiation
347
378
  getDefaultAdapterProps()
348
379
  .filter(({ permanent }) => !permanent)
349
- .forEach(({ name, value, type }) => {
380
+ .forEach(prop => {
381
+ let { value } = prop;
350
382
  // reactive props might be reconfigured by the vscroll consumer
351
- if (reactive && type === AdapterPropType.Reactive) {
352
- const react = reactive[name];
383
+ if (reactive && prop.type === AdapterPropType.Reactive) {
384
+ const react = reactive[prop.name];
353
385
  if (react) {
354
386
  // here we have a configured reactive property that came from the outer config
355
387
  // this prop must be exposed via Adapter, but at the same time we need to
356
388
  // persist the original default value as it will be used by the Adapter internally
357
- reactivePropsStore[name] = Object.assign(Object.assign({}, react), { default: value // persisting the default native Reactive prop
389
+ reactivePropsStore[prop.name] = Object.assign(Object.assign({}, react), { default: value // persisting the default native Reactive prop
358
390
  });
359
391
  value = react.source; // exposing the configured prop instead of the default one
360
392
  }
361
393
  }
362
- Object.defineProperty(this, name, Object.assign({ get: () => value }, conf));
394
+ Object.defineProperty(this, prop.name, Object.assign({ get: () => {
395
+ wantedUtils.setBox(prop, id);
396
+ return value;
397
+ } }, conf));
363
398
  });
364
399
  if (reactive) { // save both configured and default reactive props in the store
365
400
  reactiveConfigStorage.set(id, reactivePropsStore);
@@ -381,6 +416,7 @@ class DatasourceGeneric {
381
416
  }
382
417
  dispose() {
383
418
  reactiveConfigStorage.delete(this.adapter.id);
419
+ wantedStorage.delete(this.adapter.id);
384
420
  }
385
421
  }
386
422
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
@@ -2363,7 +2399,7 @@ class End extends BaseProcessFactory(CommonProcess.end) {
2363
2399
  const { workflow, state: { cycle: { interrupter } } } = scroller;
2364
2400
  if (!error && !interrupter) {
2365
2401
  // set out params accessible via Adapter
2366
- End.calculateParams(scroller, workflow);
2402
+ End.calculateParams(scroller);
2367
2403
  }
2368
2404
  // explicit interruption for we don't want to go through the inner loop finalizing
2369
2405
  if (isInterrupted(workflow)) {
@@ -2378,21 +2414,10 @@ class End extends BaseProcessFactory(CommonProcess.end) {
2378
2414
  payload: Object.assign({}, (interrupter ? { process: interrupter } : {}))
2379
2415
  });
2380
2416
  }
2381
- static calculateParams(scroller, workflow) {
2382
- const { adapter, viewport, buffer: { items } } = scroller;
2383
- if (adapter.wanted.firstVisible) {
2384
- const { item } = viewport.getEdgeVisibleItem(items, Direction.backward);
2385
- if (!item || item.element !== adapter.firstVisible.element) {
2386
- adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
2387
- }
2388
- }
2389
- // the workflow can be interrupter on firstVisible change
2390
- if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
2391
- const { item } = viewport.getEdgeVisibleItem(items, Direction.forward);
2392
- if (!item || item.element !== adapter.lastVisible.element) {
2393
- adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
2394
- }
2395
- }
2417
+ static calculateParams(scroller) {
2418
+ const { adapter, workflow } = scroller;
2419
+ adapter.setFirstOrLastVisible({ first: true, workflow });
2420
+ adapter.setFirstOrLastVisible({ last: true, workflow });
2396
2421
  }
2397
2422
  static shouldContinueRun(scroller, error) {
2398
2423
  const { cycle, fetch, render } = scroller.state;
@@ -2856,7 +2881,7 @@ class Logger {
2856
2881
  }
2857
2882
  }
2858
2883
  }
2859
- // logNow(...args: any[]) {
2884
+ // logNow(...args: unknown[]) {
2860
2885
  // const immediateLog = this.immediateLog;
2861
2886
  // const debug = this.debug;
2862
2887
  // (this as any).debug = true;
@@ -3039,7 +3064,7 @@ class Routines {
3039
3064
  }
3040
3065
  onScroll(handler) {
3041
3066
  const eventReceiver = this.settings.window ? window : this.viewport;
3042
- eventReceiver.addEventListener('scroll', handler);
3067
+ eventReceiver.addEventListener('scroll', handler, { passive: true });
3043
3068
  return () => eventReceiver.removeEventListener('scroll', handler);
3044
3069
  }
3045
3070
  }
@@ -4268,14 +4293,19 @@ class Adapter {
4268
4293
  this.source = {}; // for Reactive props
4269
4294
  this.box = {}; // for Scalars over Reactive props
4270
4295
  this.demand = {}; // for Scalars on demand
4271
- this.wanted = {};
4296
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4297
+ this.setFirstOrLastVisible = (_) => { };
4272
4298
  this.getWorkflow = getWorkflow;
4273
4299
  this.logger = logger;
4274
4300
  this.relax$ = null;
4275
4301
  this.relaxRun = null;
4276
4302
  this.reloadCounter = 0;
4277
- // public context (if exists) should provide access Reactive props configuration by id
4303
+ const contextId = (context === null || context === void 0 ? void 0 : context.id) || -1;
4304
+ // public context (if exists) should provide access to Reactive props config by id
4278
4305
  const reactivePropsStore = context && reactiveConfigStorage.get(context.id) || {};
4306
+ // the Adapter initialization should not trigger "wanted" props setting;
4307
+ // after the initialization is completed, "wanted" functionality must be unblocked
4308
+ wantedUtils.setBlock(true, contextId);
4279
4309
  // make array of the original values from public context if present
4280
4310
  const adapterProps = context
4281
4311
  ? ADAPTER_PROPS_STUB.map(prop => {
@@ -4304,34 +4334,37 @@ class Adapter {
4304
4334
  configurable: true,
4305
4335
  get: () => value
4306
4336
  }));
4307
- // Reactive props
4308
- // 1) store original values in "source" container, to avoid extra .get() calls on scalar twins set
4309
- // 2) "wanted" container is bound with scalars; get() updates it
4337
+ // Reactive props: store original values in "source" container, to avoid extra .get() calls on scalar twins set
4310
4338
  adapterProps
4311
4339
  .filter(prop => prop.type === AdapterPropType.Reactive)
4312
4340
  .forEach(({ name, value }) => {
4313
4341
  this.source[name] = value;
4314
4342
  Object.defineProperty(this, name, {
4315
4343
  configurable: true,
4316
- get: () => {
4317
- const scalarWanted = ADAPTER_PROPS_STUB.find(({ wanted, reactive }) => wanted && reactive === name);
4318
- if (scalarWanted && this.externalContext) {
4319
- this.wanted[scalarWanted.name] = true;
4320
- }
4321
- return this.source[name];
4322
- }
4344
+ get: () => this.source[name]
4323
4345
  });
4324
4346
  });
4347
+ // for "wanted" props that can be explicitly requested for the first time after the Adapter initialization,
4348
+ // an implicit calculation of the initial value is required;
4349
+ // so this method should be called when accessing the "wanted" props through one of the following getters
4350
+ const processWanted = (prop) => {
4351
+ if (wantedUtils.setBox(prop, contextId)) {
4352
+ if ([AdapterPropName.firstVisible, AdapterPropName.firstVisible$].some(n => n === prop.name)) {
4353
+ this.setFirstOrLastVisible({ first: true });
4354
+ }
4355
+ else if ([AdapterPropName.lastVisible, AdapterPropName.lastVisible$].some(n => n === prop.name)) {
4356
+ this.setFirstOrLastVisible({ last: true });
4357
+ }
4358
+ }
4359
+ };
4325
4360
  // Scalar props that have Reactive twins
4326
- // 1) scalars should use "box" container
4327
- // 2) "wanted" should be updated on get
4328
- // 3) reactive props (from "source") are triggered on set
4361
+ // 1) reactive props (from "source") should be triggered on set
4362
+ // 2) scalars should use "box" container on get
4363
+ // 3) "wanted" scalars should also run wanted-related logic on get
4329
4364
  adapterProps
4330
4365
  .filter(prop => prop.type === AdapterPropType.Scalar && !!prop.reactive)
4331
- .forEach(({ name, value, reactive, wanted }) => {
4332
- if (wanted) {
4333
- this.wanted[name] = false;
4334
- }
4366
+ .forEach((prop) => {
4367
+ const { name, value, reactive } = prop;
4335
4368
  this.box[name] = value;
4336
4369
  Object.defineProperty(this, name, {
4337
4370
  configurable: true,
@@ -4347,9 +4380,7 @@ class Adapter {
4347
4380
  }
4348
4381
  },
4349
4382
  get: () => {
4350
- if (wanted && this.externalContext) {
4351
- this.wanted[name] = true;
4352
- }
4383
+ processWanted(prop);
4353
4384
  return this.box[name];
4354
4385
  }
4355
4386
  });
@@ -4371,7 +4402,8 @@ class Adapter {
4371
4402
  }
4372
4403
  // Adapter public context augmentation
4373
4404
  adapterProps
4374
- .forEach(({ name, type, value: defaultValue, permanent }) => {
4405
+ .forEach((prop) => {
4406
+ const { name, type, value: defaultValue, permanent } = prop;
4375
4407
  let value = this[name];
4376
4408
  if (type === AdapterPropType.Function) {
4377
4409
  value = value.bind(this);
@@ -4385,14 +4417,20 @@ class Adapter {
4385
4417
  else if (name === AdapterPropName.augmented) {
4386
4418
  value = true;
4387
4419
  }
4420
+ const nonPermanentScalar = !permanent && type === AdapterPropType.Scalar;
4388
4421
  Object.defineProperty(context, name, {
4389
4422
  configurable: true,
4390
- get: () => !permanent && type === AdapterPropType.Scalar
4391
- ? this[name] // non-permanent Scalars should be taken in runtime
4392
- : value // Reactive props and methods (Functions/WorkflowRunners) can be defined once
4423
+ get: () => {
4424
+ processWanted(prop); // consider accessing "wanted" Reactive props
4425
+ if (nonPermanentScalar) {
4426
+ return this[name]; // non-permanent Scalars should be taken in runtime
4427
+ }
4428
+ return value; // other props (Reactive/Functions/WorkflowRunners) can be defined once
4429
+ }
4393
4430
  });
4394
4431
  });
4395
4432
  this.externalContext = context;
4433
+ wantedUtils.setBlock(false, contextId);
4396
4434
  }
4397
4435
  get workflow() {
4398
4436
  return this.getWorkflow();
@@ -4413,7 +4451,7 @@ class Adapter {
4413
4451
  })
4414
4452
  : defaultMethod.apply(this, args);
4415
4453
  }
4416
- initialize(buffer, state, logger, adapterRun$) {
4454
+ initialize(buffer, state, viewport, logger, adapterRun$) {
4417
4455
  // buffer
4418
4456
  Object.defineProperty(this.demand, AdapterPropName.itemsCount, {
4419
4457
  get: () => buffer.getVisibleItemsCount()
@@ -4441,6 +4479,26 @@ class Adapter {
4441
4479
  state.cycle.innerLoop.busy.on(busy => this.loopPending = busy);
4442
4480
  this.isLoading = state.cycle.busy.get();
4443
4481
  state.cycle.busy.on(busy => this.isLoading = busy);
4482
+ //viewport
4483
+ this.setFirstOrLastVisible = ({ first, last, workflow }) => {
4484
+ var _a, _b, _c;
4485
+ if ((!first && !last) || ((_a = workflow === null || workflow === void 0 ? void 0 : workflow.call) === null || _a === void 0 ? void 0 : _a.interrupted)) {
4486
+ return;
4487
+ }
4488
+ const token = first ? AdapterPropName.firstVisible : AdapterPropName.lastVisible;
4489
+ if (!((_c = wantedUtils.getBox((_b = this.externalContext) === null || _b === void 0 ? void 0 : _b.id)) === null || _c === void 0 ? void 0 : _c[token])) {
4490
+ return;
4491
+ }
4492
+ if (buffer.items.some(({ element }) => !element)) {
4493
+ logger.log('skipping first/lastVisible set because not all buffered items are rendered at this moment');
4494
+ return;
4495
+ }
4496
+ const direction = first ? Direction.backward : Direction.forward;
4497
+ const { item } = viewport.getEdgeVisibleItem(buffer.items, direction);
4498
+ if (!item || item.element !== this[token].element) {
4499
+ this[token] = (item ? item.get() : EMPTY_ITEM);
4500
+ }
4501
+ };
4444
4502
  // logger
4445
4503
  this.logger = logger;
4446
4504
  // self-pending subscription; set up only on the very first init
@@ -4484,7 +4542,8 @@ class Adapter {
4484
4542
  });
4485
4543
  }
4486
4544
  resetContext() {
4487
- const reactiveStore = reactiveConfigStorage.get(this.externalContext.id);
4545
+ var _a;
4546
+ const reactiveStore = reactiveConfigStorage.get((_a = this.externalContext) === null || _a === void 0 ? void 0 : _a.id);
4488
4547
  ADAPTER_PROPS_STUB
4489
4548
  .forEach(({ type, permanent, name, value }) => {
4490
4549
  // assign initial values to non-reactive non-permanent props
@@ -4697,7 +4756,7 @@ class Scroller {
4697
4756
  init(adapterRun$) {
4698
4757
  this.viewport.reset(this.buffer.startIndex);
4699
4758
  this.logger.stat('initialization');
4700
- this.adapter.initialize(this.buffer, this.state, this.logger, adapterRun$);
4759
+ this.adapter.initialize(this.buffer, this.state, this.viewport, this.logger, adapterRun$);
4701
4760
  }
4702
4761
  dispose(forever) {
4703
4762
  if (forever) { // Adapter is not re-instantiated on reset