virtua 0.52.6 → 0.52.7

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.
@@ -283,6 +283,13 @@ var createVirtualStore = ({ $getRange: getRange, $findIndex: findIndex, $getItem
283
283
  //#endregion
284
284
  //#region src/core/cache.ts
285
285
  var UNCACHED = -1;
286
+ var fill = (array, length, prepend) => {
287
+ const key = prepend ? "unshift" : "push";
288
+ for (let i = 0; i < length; i++) {
289
+ array[key](-1);
290
+ }
291
+ return array;
292
+ };
286
293
  var findIndex = (getOffset, length, offset, low = 0, high = length - 1) => {
287
294
  let found = low;
288
295
  while (low <= high) {
@@ -299,13 +306,6 @@ var findIndex = (getOffset, length, offset, low = 0, high = length - 1) => {
299
306
 
300
307
  //#endregion
301
308
  //#region src/core/layouts/list.ts
302
- var fill = (array, length, prepend) => {
303
- const key = prepend ? "unshift" : "push";
304
- for (let i = 0; i < length; i++) {
305
- array[key](-1);
306
- }
307
- return array;
308
- };
309
309
  var createListLayout = (length, itemSize, snapshot) => {
310
310
  let defaultItemSize = snapshot && snapshot[1] || itemSize || 40;
311
311
  let computedOffsetIndex = -1;
@@ -405,88 +405,140 @@ var createListLayout = (length, itemSize, snapshot) => {
405
405
  var getAxisLength = (axis) => typeof axis === "number" ? axis : axis.length;
406
406
  var getAxisItem = (axis, index) => typeof axis === "number" ? index : axis[index];
407
407
  var createGridLayout = (axis, size, gap = 0) => {
408
+ let length = getAxisLength(axis);
409
+ const isUniform = typeof size === "number";
410
+ const isAuto = size === "auto";
411
+ let defaultItemSize = (isUniform ? size : 40) + gap;
412
+ let computedOffsetIndex = -1;
408
413
  let header = 0;
409
414
  let footer = 0;
410
- const setPinned = (nextHeader = 0, nextFooter = 0) => {
411
- header = nextHeader;
412
- footer = nextFooter;
415
+ let currentSizes = null;
416
+ const sizes = [];
417
+ const offsets = [];
418
+ const autos = [];
419
+ const isMeasurable = (index) => isAuto || !!autos[index];
420
+ const materialize = () => {
421
+ if (!sizes.length) {
422
+ fill(sizes, length);
423
+ }
413
424
  };
414
- const getPinnedStart = (length) => min(header, length);
415
- const getTrailStart = (length) => max(length - footer, getPinnedStart(length));
416
- const pinRange = (getRange, getOffset, length, startOffset, endOffset) => {
417
- const insetStart = getOffset(getPinnedStart(length));
418
- const insetEnd = getOffset(length) - getOffset(getTrailStart(length));
419
- const start = startOffset + (insetStart ? insetStart - gap : 0);
420
- return getRange(start, max(start, endOffset - (insetEnd ? insetEnd - gap : 0)));
425
+ const getSize = (index) => {
426
+ const size = sizes[index];
427
+ return size === -1 ? defaultItemSize : size;
421
428
  };
422
- if (typeof size === "number") {
423
- let length = getAxisLength(axis);
424
- let itemSize = size;
425
- const findIndex = (offset) => itemSize + gap ? clamp(floor(offset / (itemSize + gap)), 0, length - 1) : 0;
426
- const getItemOffset = (index) => index * (itemSize + gap);
427
- const findRange = (startOffset, endOffset) => [findIndex(startOffset), findIndex(endOffset)];
428
- const layout = {
429
- $getRange: (startOffset, endOffset) => pinRange(findRange, getItemOffset, length, startOffset, endOffset),
430
- $findIndex: findIndex,
431
- $getItemOffset: getItemOffset,
432
- $getItemSize: () => itemSize,
433
- $setItemSize: () => false,
434
- $isSizeEqual: () => false,
435
- $getTotalSize: () => length ? length * (itemSize + gap) - gap : 0,
436
- $getLength: () => length,
437
- $setLength: (nextLength) => {
438
- length = nextLength;
439
- return 0;
440
- },
441
- $isMeasurable: () => false,
442
- $setPinned: setPinned,
443
- $getPinnedStart: () => getPinnedStart(length),
444
- $getTrailStart: () => getTrailStart(length),
445
- $getSizes: (_axis, nextSize) => typeof nextSize === "number" ? nextSize : null,
446
- $setAxis: (nextSize, scrollOffset) => {
447
- if (nextSize == null || nextSize === itemSize) {
448
- return;
429
+ const getOffset = (index) => {
430
+ if (!length) return 0;
431
+ if (!sizes.length) {
432
+ return index * defaultItemSize;
433
+ }
434
+ if (computedOffsetIndex >= index) {
435
+ return offsets[index];
436
+ }
437
+ if (computedOffsetIndex < 0) {
438
+ offsets[0] = 0;
439
+ computedOffsetIndex = 0;
440
+ }
441
+ let i = computedOffsetIndex;
442
+ let top = offsets[i];
443
+ while (i < index) {
444
+ top += getSize(i);
445
+ offsets[++i] = top;
446
+ }
447
+ computedOffsetIndex = index;
448
+ return top;
449
+ };
450
+ const setSize = (index, size) => {
451
+ sizes[index] = size;
452
+ computedOffsetIndex = min(index, computedOffsetIndex);
453
+ };
454
+ const find = (offset) => sizes.length ? findIndex(getOffset, length, offset) : defaultItemSize ? clamp(floor(offset / defaultItemSize), 0, length - 1) : 0;
455
+ const getPinnedStart = () => min(header, length);
456
+ const getTrailStart = () => max(length - footer, getPinnedStart());
457
+ return {
458
+ $getRange: (startOffset, endOffset) => {
459
+ const insetStart = getOffset(getPinnedStart());
460
+ const insetEnd = getOffset(length) - getOffset(getTrailStart());
461
+ const start = startOffset + (insetStart ? insetStart - gap : 0);
462
+ return [find(start), find(max(start, endOffset - (insetEnd ? insetEnd - gap : 0)))];
463
+ },
464
+ $findIndex: find,
465
+ $getItemOffset: getOffset,
466
+ $getItemSize: (index) => (sizes.length ? getSize(index) : defaultItemSize) - gap,
467
+ $setItemSize: (index, size) => {
468
+ if (!isMeasurable(index)) {
469
+ return false;
470
+ }
471
+ materialize();
472
+ const isInitialMeasurement = sizes[index] === -1;
473
+ setSize(index, size + gap);
474
+ return isInitialMeasurement;
475
+ },
476
+ $isSizeEqual: (index, size) => (sizes.length ? sizes[index] : -1) === size + gap,
477
+ $getTotalSize: () => length ? getOffset(length) - gap : 0,
478
+ $getLength: () => length,
479
+ $setLength: (nextLength) => {
480
+ const diff = nextLength - length;
481
+ computedOffsetIndex = min(nextLength - 1, computedOffsetIndex);
482
+ length = nextLength;
483
+ if (sizes.length) {
484
+ if (diff > 0) {
485
+ fill(sizes, diff);
486
+ } else {
487
+ sizes.splice(diff);
449
488
  }
450
- const jump = findIndex(scrollOffset) * (nextSize - itemSize);
451
- itemSize = nextSize;
452
- return jump;
453
489
  }
454
- };
455
- return layout;
456
- }
457
- const isAuto = size === "auto";
458
- let currentSizes = null;
459
- const autos = [];
460
- const inner = createListLayout(getAxisLength(axis), undefined, [[], 40 + gap]);
461
- const isMeasurable = (index) => isAuto || !!autos[index];
462
- const layout = {
463
- $getRange: (startOffset, endOffset) => pinRange(inner.$getRange, inner.$getItemOffset, inner.$getLength(), startOffset, endOffset),
464
- $findIndex: inner.$findIndex,
465
- $getItemOffset: inner.$getItemOffset,
466
- $getItemSize: (index) => inner.$getItemSize(index) - gap,
467
- $setItemSize: (index, s) => isMeasurable(index) && inner.$setItemSize(index, s + gap),
468
- $isSizeEqual: (index, s) => inner.$isSizeEqual(index, s + gap),
469
- $getTotalSize: () => inner.$getLength() ? inner.$getTotalSize() - gap : 0,
470
- $getLength: inner.$getLength,
471
- $setLength: inner.$setLength,
472
- $estimateDefaultSize: isAuto ? inner.$estimateDefaultSize : undefined,
490
+ return 0;
491
+ },
492
+ $estimateDefaultSize: isAuto ? (startIndex) => {
493
+ let measuredCountBeforeStart = 0;
494
+ const measuredSizes = [];
495
+ sizes.forEach((s, i) => {
496
+ if (s !== -1) {
497
+ if (s) {
498
+ measuredSizes.push(s);
499
+ }
500
+ if (i < startIndex) {
501
+ measuredCountBeforeStart++;
502
+ }
503
+ }
504
+ });
505
+ computedOffsetIndex = -1;
506
+ sort(measuredSizes);
507
+ const len = measuredSizes.length;
508
+ const mid = len / 2 | 0;
509
+ const median = len % 2 === 0 ? (measuredSizes[mid - 1] + measuredSizes[mid]) / 2 : measuredSizes[mid];
510
+ const prevDefaultItemSize = defaultItemSize;
511
+ return ((defaultItemSize = median) - prevDefaultItemSize) * max(startIndex - measuredCountBeforeStart, 0);
512
+ } : undefined,
473
513
  $isMeasurable: isMeasurable,
474
- $setPinned: setPinned,
475
- $getPinnedStart: () => getPinnedStart(inner.$getLength()),
476
- $getTrailStart: () => getTrailStart(inner.$getLength()),
477
- $getSizes: (nextAxis, nextSize) => isAuto || typeof nextSize !== "string" || nextSize === "auto" ? null : nextAxis.map((item) => item != null ? item[nextSize] : null),
514
+ $setPinned: (nextHeader = 0, nextFooter = 0) => {
515
+ header = nextHeader;
516
+ footer = nextFooter;
517
+ },
518
+ $getPinnedStart: getPinnedStart,
519
+ $getTrailStart: getTrailStart,
520
+ $getSizes: (nextAxis, nextSize) => typeof nextSize === "number" ? isUniform ? nextSize : null : isUniform || isAuto || nextSize === "auto" ? null : nextAxis.map((item) => item != null ? item[nextSize] : null),
478
521
  $setAxis: (nextSizes, scrollOffset) => {
479
- if (!nextSizes) {
522
+ if (nextSizes == null) {
480
523
  return;
481
524
  }
482
- const length = inner.$getLength();
525
+ if (typeof nextSizes === "number") {
526
+ const nextDefaultItemSize = nextSizes + gap;
527
+ if (nextDefaultItemSize === defaultItemSize) {
528
+ return;
529
+ }
530
+ const jump = find(scrollOffset) * (nextDefaultItemSize - defaultItemSize);
531
+ defaultItemSize = nextDefaultItemSize;
532
+ return jump;
533
+ }
483
534
  if (nextSizes === currentSizes && length === autos.length) {
484
535
  return;
485
536
  }
486
537
  currentSizes = nextSizes;
487
538
  autos.length = length;
488
- const anchorIndex = inner.$findIndex(scrollOffset);
489
- const prevOffset = inner.$getItemOffset(anchorIndex);
539
+ materialize();
540
+ const anchorIndex = find(scrollOffset);
541
+ const prevOffset = getOffset(anchorIndex);
490
542
  let changed;
491
543
  for (let i = 0; i < length; i++) {
492
544
  const itemSize = nextSizes[i];
@@ -494,8 +546,8 @@ var createGridLayout = (axis, size, gap = 0) => {
494
546
  if (!isAutoItem || !autos[i]) {
495
547
  autos[i] = isAutoItem;
496
548
  const target = isAutoItem ? -1 : itemSize + gap;
497
- if (!inner.$isSizeEqual(i, target)) {
498
- inner.$setItemSize(i, target);
549
+ if (sizes[i] !== target) {
550
+ setSize(i, target);
499
551
  changed = true;
500
552
  }
501
553
  }
@@ -503,10 +555,9 @@ var createGridLayout = (axis, size, gap = 0) => {
503
555
  if (!changed) {
504
556
  return;
505
557
  }
506
- return inner.$getItemOffset(anchorIndex) - prevOffset;
558
+ return getOffset(anchorIndex) - prevOffset;
507
559
  }
508
560
  };
509
- return layout;
510
561
  };
511
562
 
512
563
  //#endregion