@vaadin/component-base 23.1.0-beta2 → 23.1.0-rc1

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": "@vaadin/component-base",
3
- "version": "23.1.0-beta2",
3
+ "version": "23.1.0-rc1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,5 +42,5 @@
42
42
  "@vaadin/testing-helpers": "^0.3.2",
43
43
  "sinon": "^13.0.2"
44
44
  },
45
- "gitHead": "f11f9245a0b5e6bf912725a501c27c24b74e7c8d"
45
+ "gitHead": "5ecb85e16e938df827fefca4bd2a665a1e29913e"
46
46
  }
package/src/debounce.d.ts CHANGED
@@ -10,8 +10,6 @@
10
10
  import { AsyncInterface } from './async.js';
11
11
 
12
12
  export declare class Debouncer {
13
- constructor();
14
-
15
13
  /**
16
14
  * Creates a debouncer if no debouncer is passed as a parameter
17
15
  * or it cancels an active debouncer otherwise. The following
@@ -48,6 +46,8 @@ export declare class Debouncer {
48
46
  */
49
47
  static debounce(debouncer: Debouncer | null, asyncModule: AsyncInterface, callback: () => any): Debouncer;
50
48
 
49
+ constructor();
50
+
51
51
  /**
52
52
  * Sets the scheduler; that is, a module with the Async interface,
53
53
  * a callback and optional arguments to be passed to the run function
package/src/debounce.js CHANGED
@@ -12,6 +12,52 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
12
12
  * @summary Collapse multiple callbacks into one invocation after a timer.
13
13
  */
14
14
  export class Debouncer {
15
+ /**
16
+ * Creates a debouncer if no debouncer is passed as a parameter
17
+ * or it cancels an active debouncer otherwise. The following
18
+ * example shows how a debouncer can be called multiple times within a
19
+ * microtask and "debounced" such that the provided callback function is
20
+ * called once. Add this method to a custom element:
21
+ *
22
+ * ```js
23
+ * import {microTask} from '@vaadin/component-base/src/async.js';
24
+ * import {Debouncer} from '@vaadin/component-base/src/debounce.js';
25
+ * // ...
26
+ *
27
+ * _debounceWork() {
28
+ * this._debounceJob = Debouncer.debounce(this._debounceJob,
29
+ * microTask, () => this._doWork());
30
+ * }
31
+ * ```
32
+ *
33
+ * If the `_debounceWork` method is called multiple times within the same
34
+ * microtask, the `_doWork` function will be called only once at the next
35
+ * microtask checkpoint.
36
+ *
37
+ * Note: In testing it is often convenient to avoid asynchrony. To accomplish
38
+ * this with a debouncer, you can use `enqueueDebouncer` and
39
+ * `flush`. For example, extend the above example by adding
40
+ * `enqueueDebouncer(this._debounceJob)` at the end of the
41
+ * `_debounceWork` method. Then in a test, call `flush` to ensure
42
+ * the debouncer has completed.
43
+ *
44
+ * @param {Debouncer?} debouncer Debouncer object.
45
+ * @param {!AsyncInterface} asyncModule Object with Async interface
46
+ * @param {function()} callback Callback to run.
47
+ * @return {!Debouncer} Returns a debouncer object.
48
+ */
49
+ static debounce(debouncer, asyncModule, callback) {
50
+ if (debouncer instanceof Debouncer) {
51
+ // Cancel the async callback, but leave in debouncerQueue if it was
52
+ // enqueued, to maintain 1.x flush order
53
+ debouncer._cancelAsync();
54
+ } else {
55
+ debouncer = new Debouncer();
56
+ }
57
+ debouncer.setConfig(asyncModule, callback);
58
+ return debouncer;
59
+ }
60
+
15
61
  constructor() {
16
62
  this._asyncModule = null;
17
63
  this._callback = null;
@@ -85,52 +131,6 @@ export class Debouncer {
85
131
  isActive() {
86
132
  return this._timer != null;
87
133
  }
88
-
89
- /**
90
- * Creates a debouncer if no debouncer is passed as a parameter
91
- * or it cancels an active debouncer otherwise. The following
92
- * example shows how a debouncer can be called multiple times within a
93
- * microtask and "debounced" such that the provided callback function is
94
- * called once. Add this method to a custom element:
95
- *
96
- * ```js
97
- * import {microTask} from '@vaadin/component-base/src/async.js';
98
- * import {Debouncer} from '@vaadin/component-base/src/debounce.js';
99
- * // ...
100
- *
101
- * _debounceWork() {
102
- * this._debounceJob = Debouncer.debounce(this._debounceJob,
103
- * microTask, () => this._doWork());
104
- * }
105
- * ```
106
- *
107
- * If the `_debounceWork` method is called multiple times within the same
108
- * microtask, the `_doWork` function will be called only once at the next
109
- * microtask checkpoint.
110
- *
111
- * Note: In testing it is often convenient to avoid asynchrony. To accomplish
112
- * this with a debouncer, you can use `enqueueDebouncer` and
113
- * `flush`. For example, extend the above example by adding
114
- * `enqueueDebouncer(this._debounceJob)` at the end of the
115
- * `_debounceWork` method. Then in a test, call `flush` to ensure
116
- * the debouncer has completed.
117
- *
118
- * @param {Debouncer?} debouncer Debouncer object.
119
- * @param {!AsyncInterface} asyncModule Object with Async interface
120
- * @param {function()} callback Callback to run.
121
- * @return {!Debouncer} Returns a debouncer object.
122
- */
123
- static debounce(debouncer, asyncModule, callback) {
124
- if (debouncer instanceof Debouncer) {
125
- // Cancel the async callback, but leave in debouncerQueue if it was
126
- // enqueued, to maintain 1.x flush order
127
- debouncer._cancelAsync();
128
- } else {
129
- debouncer = new Debouncer();
130
- }
131
- debouncer.setConfig(asyncModule, callback);
132
- return debouncer;
133
- }
134
134
  }
135
135
 
136
136
  let debouncerQueue = new Set();
@@ -39,7 +39,7 @@ const registered = new Set();
39
39
  export const ElementMixin = (superClass) =>
40
40
  class VaadinElementMixin extends DirMixin(superClass) {
41
41
  static get version() {
42
- return '23.1.0-beta2';
42
+ return '23.1.0-rc1';
43
43
  }
44
44
 
45
45
  /** @protected */
@@ -9,17 +9,17 @@ import { ReactiveController } from 'lit';
9
9
  * A controller for trapping focus within a DOM node.
10
10
  */
11
11
  export class FocusTrapController implements ReactiveController {
12
+ /**
13
+ * The controller host element.
14
+ */
15
+ host: HTMLElement;
16
+
12
17
  constructor(node: HTMLElement);
13
18
 
14
19
  hostConnected(): void;
15
20
 
16
21
  hostDisconnected(): void;
17
22
 
18
- /**
19
- * The controller host element.
20
- */
21
- host: HTMLElement;
22
-
23
23
  /**
24
24
  * Activates a focus trap for a DOM node that will prevent focus from escaping the node.
25
25
  * The trap can be deactivated with the `.releaseFocus()` method.
@@ -115,32 +115,11 @@ export const ironList = {
115
115
  */
116
116
  _maxPages: 2,
117
117
 
118
- /**
119
- * The maximum items per row
120
- */
121
- _itemsPerRow: 1,
122
-
123
- /**
124
- * The width of each grid item
125
- */
126
- _itemWidth: 0,
127
-
128
- /**
129
- * The height of the row in grid layout.
130
- */
131
- _rowHeight: 0,
132
-
133
118
  /**
134
119
  * The cost of stamping a template in ms.
135
120
  */
136
121
  _templateCost: 0,
137
122
 
138
- /**
139
- * Needed to pass event.model property to declarative event handlers -
140
- * see polymer/polymer#4339.
141
- */
142
- _parentModel: true,
143
-
144
123
  /**
145
124
  * The bottom of the physical content.
146
125
  */
@@ -166,8 +145,7 @@ export const ironList = {
166
145
  * The height of the physical content that isn't on the screen.
167
146
  */
168
147
  get _hiddenContentSize() {
169
- const size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
170
- return size - this._viewportHeight;
148
+ return this._physicalSize - this._viewportHeight;
171
149
  },
172
150
 
173
151
  /**
@@ -182,7 +160,7 @@ export const ironList = {
182
160
  * `_physicalStart`.
183
161
  */
184
162
  get _maxVirtualStart() {
185
- const virtualCount = this._convertIndexToCompleteRow(this._virtualCount);
163
+ const virtualCount = this._virtualCount;
186
164
  return Math.max(0, virtualCount - this._physicalCount);
187
165
  },
188
166
 
@@ -192,9 +170,6 @@ export const ironList = {
192
170
 
193
171
  set _virtualStart(val) {
194
172
  val = this._clamp(val, 0, this._maxVirtualStart);
195
- if (this.grid) {
196
- val -= val % this._itemsPerRow;
197
- }
198
173
  this._virtualStartVal = val;
199
174
  },
200
175
 
@@ -210,9 +185,6 @@ export const ironList = {
210
185
  if (val < 0) {
211
186
  val = this._physicalCount + val;
212
187
  }
213
- if (this.grid) {
214
- val -= val % this._itemsPerRow;
215
- }
216
188
  this._physicalStartVal = val;
217
189
  },
218
190
 
@@ -264,11 +236,7 @@ export const ironList = {
264
236
  physicalOffset += this._getPhysicalSizeIncrement(pidx);
265
237
 
266
238
  if (physicalOffset > this._scrollPosition) {
267
- return this.grid ? vidx - (vidx % this._itemsPerRow) : vidx;
268
- }
269
- // Handle a partially rendered final row in grid mode
270
- if (this.grid && this._virtualCount - 1 === vidx) {
271
- return vidx - (vidx % this._itemsPerRow);
239
+ return vidx;
272
240
  }
273
241
  }) || 0;
274
242
  this._firstVisibleIndexVal = idx;
@@ -284,38 +252,19 @@ export const ironList = {
284
252
  get lastVisibleIndex() {
285
253
  let idx = this._lastVisibleIndexVal;
286
254
  if (idx == null) {
287
- if (this.grid) {
288
- idx = Math.min(this._virtualCount, this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1);
289
- } else {
290
- let physicalOffset = this._physicalTop + this._scrollOffset;
291
- this._iterateItems((pidx, vidx) => {
292
- if (physicalOffset < this._scrollBottom) {
293
- idx = vidx;
294
- }
295
- physicalOffset += this._getPhysicalSizeIncrement(pidx);
296
- });
297
- }
255
+ let physicalOffset = this._physicalTop + this._scrollOffset;
256
+ this._iterateItems((pidx, vidx) => {
257
+ if (physicalOffset < this._scrollBottom) {
258
+ idx = vidx;
259
+ }
260
+ physicalOffset += this._getPhysicalSizeIncrement(pidx);
261
+ });
262
+
298
263
  this._lastVisibleIndexVal = idx;
299
264
  }
300
265
  return idx;
301
266
  },
302
267
 
303
- get _defaultScrollTarget() {
304
- return this;
305
- },
306
-
307
- get _virtualRowCount() {
308
- return Math.ceil(this._virtualCount / this._itemsPerRow);
309
- },
310
-
311
- get _estRowsInView() {
312
- return Math.ceil(this._viewportHeight / this._rowHeight);
313
- },
314
-
315
- get _physicalRows() {
316
- return Math.ceil(this._physicalCount / this._itemsPerRow);
317
- },
318
-
319
268
  get _scrollOffset() {
320
269
  return this._scrollerPaddingTop + this.scrollOffset;
321
270
  },
@@ -335,7 +284,7 @@ export const ironList = {
335
284
  // Random access.
336
285
  if (Math.abs(delta) > this._physicalSize && this._physicalSize > 0) {
337
286
  delta -= this._scrollOffset;
338
- const idxAdjustment = Math.round(delta / this._physicalAverage) * this._itemsPerRow;
287
+ const idxAdjustment = Math.round(delta / this._physicalAverage);
339
288
  this._virtualStart += idxAdjustment;
340
289
  this._physicalStart += idxAdjustment;
341
290
  // Estimate new physical offset based on the virtual start index.
@@ -344,10 +293,7 @@ export const ironList = {
344
293
  // more than the scroll position however, since that would result in
345
294
  // the physical items not covering the viewport, and leading to
346
295
  // _increasePoolIfNeeded to run away creating items to try to fill it.
347
- this._physicalTop = Math.min(
348
- Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage,
349
- this._scrollPosition,
350
- );
296
+ this._physicalTop = Math.min(Math.floor(this._virtualStart) * this._physicalAverage, this._scrollPosition);
351
297
  this._update();
352
298
  } else if (this._physicalCount > 0) {
353
299
  const reusables = this._getReusables(isScrollingDown);
@@ -371,7 +317,7 @@ export const ironList = {
371
317
  * @param {boolean} fromTop If the potential reusable items are above the scrolling region.
372
318
  */
373
319
  _getReusables(fromTop) {
374
- let ith, lastIth, offsetContent, physicalItemHeight;
320
+ let ith, offsetContent, physicalItemHeight;
375
321
  const idxs = [];
376
322
  const protectedOffsetContent = this._hiddenContentSize * this._ratio;
377
323
  const virtualStart = this._virtualStart;
@@ -385,12 +331,9 @@ export const ironList = {
385
331
 
386
332
  if (fromTop) {
387
333
  ith = this._physicalStart;
388
- lastIth = this._physicalEnd;
389
334
  offsetContent = scrollTop - top;
390
335
  } else {
391
336
  ith = this._physicalEnd;
392
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
393
- lastIth = this._physicalStart;
394
337
  offsetContent = bottom - scrollBottom;
395
338
  }
396
339
  // eslint-disable-next-line no-constant-condition
@@ -438,7 +381,6 @@ export const ironList = {
438
381
  if ((itemSet && itemSet.length === 0) || this._physicalCount === 0) {
439
382
  return;
440
383
  }
441
- this._manageFocus();
442
384
  this._assignModels(itemSet);
443
385
  this._updateMetrics(itemSet);
444
386
  // Adjust offset after measuring.
@@ -464,19 +406,11 @@ export const ironList = {
464
406
  * Increases the pool size.
465
407
  */
466
408
  _increasePoolIfNeeded(count) {
467
- let nextPhysicalCount = this._clamp(
409
+ const nextPhysicalCount = this._clamp(
468
410
  this._physicalCount + count,
469
411
  DEFAULT_PHYSICAL_COUNT,
470
412
  this._virtualCount - this._virtualStart,
471
413
  );
472
- nextPhysicalCount = this._convertIndexToCompleteRow(nextPhysicalCount);
473
- if (this.grid) {
474
- const correction = nextPhysicalCount % this._itemsPerRow;
475
- if (correction && nextPhysicalCount - correction <= this._physicalCount) {
476
- nextPhysicalCount += this._itemsPerRow;
477
- }
478
- nextPhysicalCount -= correction;
479
- }
480
414
  const delta = nextPhysicalCount - this._physicalCount;
481
415
  let nextIncrease = Math.round(this._physicalCount * 0.5);
482
416
 
@@ -508,8 +442,6 @@ export const ironList = {
508
442
  this._templateCost = (window.performance.now() - ts) / delta;
509
443
  nextIncrease = Math.round(this._physicalCount * 0.5);
510
444
  }
511
- // The upper bounds is not fixed when dealing with a grid that doesn't
512
- // fill it's last row with the exact number of items per row.
513
445
  if (this._virtualEnd >= this._virtualCount - 1 || nextIncrease === 0) {
514
446
  // Do nothing.
515
447
  } else if (!this._isClientFull()) {
@@ -547,17 +479,6 @@ export const ironList = {
547
479
  }
548
480
  },
549
481
 
550
- _gridChanged(newGrid, oldGrid) {
551
- if (typeof oldGrid === 'undefined') {
552
- return;
553
- }
554
- this.notifyResize();
555
- flush();
556
- if (newGrid) {
557
- this._updateGridMetrics();
558
- }
559
- },
560
-
561
482
  /**
562
483
  * Called when the items have changed. That is, reassignments
563
484
  * to `items`, splices or updates to a single item.
@@ -577,32 +498,7 @@ export const ironList = {
577
498
  if (this._scrollTop > this._scrollOffset) {
578
499
  this._resetScrollPosition(0);
579
500
  }
580
- this._removeFocusedItem();
581
501
  this._debounce('_render', this._render, animationFrame);
582
- } else if (change.path === 'items.splices') {
583
- this._adjustVirtualIndex(change.value.indexSplices);
584
- this._virtualCount = this.items ? this.items.length : 0;
585
- // Only blur if at least one item is added or removed.
586
- const itemAddedOrRemoved = change.value.indexSplices.some((splice) => {
587
- return splice.addedCount > 0 || splice.removed.length > 0;
588
- });
589
- if (itemAddedOrRemoved) {
590
- // Only blur activeElement if it is a descendant of the list (#505,
591
- // #507).
592
- const activeElement = this._getActiveElement();
593
- if (this.contains(activeElement)) {
594
- activeElement.blur();
595
- }
596
- }
597
- // Render only if the affected index is rendered.
598
- const affectedIndexRendered = change.value.indexSplices.some((splice) => {
599
- return splice.index + splice.addedCount >= this._virtualStart && splice.index <= this._virtualEnd;
600
- });
601
- if (!this._isClientFull() || affectedIndexRendered) {
602
- this._debounce('_render', this._render, animationFrame);
603
- }
604
- } else if (change.path !== 'items.length') {
605
- this._forwardItemPath(change.path, change.value);
606
502
  }
607
503
  },
608
504
 
@@ -677,17 +573,8 @@ export const ironList = {
677
573
  this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
678
574
  }, itemSet);
679
575
 
680
- if (this.grid) {
681
- this._updateGridMetrics();
682
- this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
683
- } else {
684
- oldPhysicalSize =
685
- this._itemsPerRow === 1
686
- ? oldPhysicalSize
687
- : Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
688
- this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
689
- this._itemsPerRow = 1;
690
- }
576
+ this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
577
+
691
578
  // Update the average if it measured something.
692
579
  if (this._physicalAverageCount !== prevAvgCount) {
693
580
  this._physicalAverage = Math.round(
@@ -696,12 +583,6 @@ export const ironList = {
696
583
  }
697
584
  },
698
585
 
699
- _updateGridMetrics() {
700
- this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : 200;
701
- this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : 200;
702
- this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
703
- },
704
-
705
586
  /**
706
587
  * Updates the position of the physical items.
707
588
  */
@@ -710,59 +591,14 @@ export const ironList = {
710
591
 
711
592
  let y = this._physicalTop;
712
593
 
713
- if (this.grid) {
714
- const totalItemWidth = this._itemsPerRow * this._itemWidth;
715
- const rowOffset = (this._viewportWidth - totalItemWidth) / 2;
716
-
717
- this._iterateItems((pidx, vidx) => {
718
- const modulus = vidx % this._itemsPerRow;
719
- let x = Math.floor(modulus * this._itemWidth + rowOffset);
720
- if (this._isRTL) {
721
- x *= -1;
722
- }
723
- this.translate3d(`${x}px`, `${y}px`, 0, this._physicalItems[pidx]);
724
- if (this._shouldRenderNextRow(vidx)) {
725
- y += this._rowHeight;
726
- }
727
- });
728
- } else {
729
- const order = [];
730
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
731
- this._iterateItems((pidx, vidx) => {
732
- const item = this._physicalItems[pidx];
733
- this.translate3d(0, `${y}px`, 0, item);
734
- y += this._physicalSizes[pidx];
735
- const itemId = item.id;
736
- if (itemId) {
737
- order.push(itemId);
738
- }
739
- });
740
- if (order.length) {
741
- this.setAttribute('aria-owns', order.join(' '));
742
- }
743
- }
594
+ this._iterateItems((pidx) => {
595
+ this.translate3d(0, `${y}px`, 0, this._physicalItems[pidx]);
596
+ y += this._physicalSizes[pidx];
597
+ });
744
598
  },
745
599
 
746
600
  _getPhysicalSizeIncrement(pidx) {
747
- if (!this.grid) {
748
- return this._physicalSizes[pidx];
749
- }
750
- if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1) {
751
- return 0;
752
- }
753
- return this._rowHeight;
754
- },
755
-
756
- /**
757
- * Returns, based on the current index,
758
- * whether or not the next index will need
759
- * to be rendered on a new row.
760
- *
761
- * @param {number} vidx Virtual index
762
- * @return {boolean}
763
- */
764
- _shouldRenderNextRow(vidx) {
765
- return vidx % this._itemsPerRow === this._itemsPerRow - 1;
601
+ return this._physicalSizes[pidx];
766
602
  },
767
603
 
768
604
  /**
@@ -799,16 +635,12 @@ export const ironList = {
799
635
  * @param {boolean=} forceUpdate If true, updates the height no matter what.
800
636
  */
801
637
  _updateScrollerSize(forceUpdate) {
802
- if (this.grid) {
803
- this._estScrollHeight = this._virtualRowCount * this._rowHeight;
804
- } else {
805
- this._estScrollHeight =
806
- this._physicalBottom +
807
- Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
808
- }
638
+ this._estScrollHeight =
639
+ this._physicalBottom +
640
+ Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
641
+
809
642
  forceUpdate = forceUpdate || this._scrollHeight === 0;
810
643
  forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
811
- forceUpdate = forceUpdate || (this.grid && this.$.items.style.height < this._estScrollHeight);
812
644
  // Amortize height adjustment, so it won't trigger large repaints too often.
813
645
  if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._viewportHeight) {
814
646
  this.$.items.style.height = `${this._estScrollHeight}px`;
@@ -835,13 +667,12 @@ export const ironList = {
835
667
  idx = this._clamp(idx, 0, this._virtualCount - 1);
836
668
  // Update the virtual start only when needed.
837
669
  if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
838
- this._virtualStart = this.grid ? idx - this._itemsPerRow * 2 : idx - 1;
670
+ this._virtualStart = idx - 1;
839
671
  }
840
- this._manageFocus();
841
672
  this._assignModels();
842
673
  this._updateMetrics();
843
674
  // Estimate new physical offset.
844
- this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
675
+ this._physicalTop = this._virtualStart * this._physicalAverage;
845
676
 
846
677
  let currentTopItem = this._physicalStart;
847
678
  let currentVirtualItem = this._virtualStart;
@@ -896,49 +727,10 @@ export const ironList = {
896
727
  );
897
728
  },
898
729
 
899
- /**
900
- * Updates the size of a given list item.
901
- *
902
- * @method updateSizeForItem
903
- * @param {Object} item The item instance.
904
- */
905
- updateSizeForItem(item) {
906
- return this.updateSizeForIndex(this.items.indexOf(item));
907
- },
908
-
909
- /**
910
- * Updates the size of the item at the given index in the items array.
911
- *
912
- * @method updateSizeForIndex
913
- * @param {number} index The index of the item in the items array.
914
- */
915
- updateSizeForIndex(index) {
916
- if (!this._isIndexRendered(index)) {
917
- return null;
918
- }
919
- this._updateMetrics([this._getPhysicalIndex(index)]);
920
- this._positionItems();
921
- return null;
922
- },
923
-
924
- /**
925
- * Converts a random index to the index of the item that completes it's row.
926
- * Allows for better order and fill computation when grid == true.
927
- */
928
- _convertIndexToCompleteRow(idx) {
929
- // When grid == false _itemPerRow can be unset.
930
- this._itemsPerRow = this._itemsPerRow || 1;
931
- return this.grid ? Math.ceil(idx / this._itemsPerRow) * this._itemsPerRow : idx;
932
- },
933
-
934
730
  _isIndexRendered(idx) {
935
731
  return idx >= this._virtualStart && idx <= this._virtualEnd;
936
732
  },
937
733
 
938
- _isIndexVisible(idx) {
939
- return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
940
- },
941
-
942
734
  _getPhysicalIndex(vidx) {
943
735
  return (this._physicalStart + (vidx - this._virtualStart)) % this._physicalCount;
944
736
  },
@@ -9,15 +9,6 @@ import { ReactiveController } from 'lit';
9
9
  * A controller for listening on media query changes.
10
10
  */
11
11
  export class MediaQueryController implements ReactiveController {
12
- /**
13
- * @param {HTMLElement} host
14
- */
15
- constructor(query: string, callback: (matches: boolean) => void);
16
-
17
- hostConnected(): void;
18
-
19
- hostDisconnected(): void;
20
-
21
12
  /**
22
13
  * The CSS media query to evaluate.
23
14
  */
@@ -27,4 +18,13 @@ export class MediaQueryController implements ReactiveController {
27
18
  * Function to call when media query changes.
28
19
  */
29
20
  protected callback: (matches: boolean) => void;
21
+
22
+ /**
23
+ * @param {HTMLElement} host
24
+ */
25
+ constructor(query: string, callback: (matches: boolean) => void);
26
+
27
+ hostConnected(): void;
28
+
29
+ hostDisconnected(): void;
30
30
  }
@@ -11,15 +11,15 @@ import { Constructor } from '@open-wc/dedupe-mixin';
11
11
  export declare function ResizeMixin<T extends Constructor<HTMLElement>>(base: T): T & Constructor<ResizeMixinClass>;
12
12
 
13
13
  export declare class ResizeMixinClass {
14
- /**
15
- * A handler invoked on host resize. By default, it does nothing.
16
- * Override the method to implement your own behavior.
17
- */
18
- protected _onResize(contentRect: DOMRect): void;
19
-
20
14
  /**
21
15
  * When true, the parent element resize will be also observed.
22
16
  * Override this getter and return `true` to enable this.
23
17
  */
24
18
  protected readonly _observeParent: boolean;
19
+
20
+ /**
21
+ * A handler invoked on host resize. By default, it does nothing.
22
+ * Override the method to implement your own behavior.
23
+ */
24
+ protected _onResize(contentRect: DOMRect): void;
25
25
  }
@@ -6,15 +6,6 @@
6
6
  import { ReactiveController } from 'lit';
7
7
 
8
8
  export class SlotController extends EventTarget implements ReactiveController {
9
- constructor(
10
- host: HTMLElement,
11
- slotName: string,
12
- slotFactory?: () => HTMLElement,
13
- slotInitializer?: (host: HTMLElement, node: HTMLElement) => void,
14
- );
15
-
16
- hostConnected(): void;
17
-
18
9
  /**
19
10
  * The controller host element.
20
11
  */
@@ -25,17 +16,26 @@ export class SlotController extends EventTarget implements ReactiveController {
25
16
  */
26
17
  node: HTMLElement;
27
18
 
28
- /**
29
- * Return a reference to the node managed by the controller.
30
- */
31
- getSlotChild(): Node;
32
-
33
19
  protected initialized: boolean;
34
20
 
35
21
  protected defaultNode: Node;
36
22
 
37
23
  protected defaultId: string;
38
24
 
25
+ constructor(
26
+ host: HTMLElement,
27
+ slotName: string,
28
+ slotFactory?: () => HTMLElement,
29
+ slotInitializer?: (host: HTMLElement, node: HTMLElement) => void,
30
+ );
31
+
32
+ hostConnected(): void;
33
+
34
+ /**
35
+ * Return a reference to the node managed by the controller.
36
+ */
37
+ getSlotChild(): Node;
38
+
39
39
  protected attachDefaultNode(): Node | undefined;
40
40
 
41
41
  protected initNode(node: Node): void;
@@ -10,16 +10,6 @@ import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nod
10
10
  * A controller for providing content to slot element and observing changes.
11
11
  */
12
12
  export class SlotController extends EventTarget {
13
- constructor(host, slotName, slotFactory, slotInitializer) {
14
- super();
15
-
16
- this.host = host;
17
- this.slotName = slotName;
18
- this.slotFactory = slotFactory;
19
- this.slotInitializer = slotInitializer;
20
- this.defaultId = SlotController.generateId(slotName, host);
21
- }
22
-
23
13
  /**
24
14
  * Ensure that every instance has unique ID.
25
15
  *
@@ -40,6 +30,16 @@ export class SlotController extends EventTarget {
40
30
  return `${prefix}-${host.localName}-${this[field]}`;
41
31
  }
42
32
 
33
+ constructor(host, slotName, slotFactory, slotInitializer) {
34
+ super();
35
+
36
+ this.host = host;
37
+ this.slotName = slotName;
38
+ this.slotFactory = slotFactory;
39
+ this.slotInitializer = slotInitializer;
40
+ this.defaultId = SlotController.generateId(slotName, host);
41
+ }
42
+
43
43
  hostConnected() {
44
44
  if (!this.initialized) {
45
45
  let node = this.getSlotChild();
@@ -26,6 +26,11 @@ export class IronListAdapter {
26
26
  // Iron-list uses this value to determine how many pages of elements to render
27
27
  this._maxPages = 1.3;
28
28
 
29
+ // Placeholder height (used for sizing elements that have intrinsic 0 height after update)
30
+ this.__placeholderHeight = 200;
31
+ // A queue of 10 previous element heights
32
+ this.__elementHeightQueue = Array(10);
33
+
29
34
  this.timeouts = {
30
35
  SCROLL_REORDER: 500,
31
36
  IGNORE_WHEEL: 500,
@@ -60,10 +65,6 @@ export class IronListAdapter {
60
65
  }
61
66
  }
62
67
 
63
- _manageFocus() {}
64
-
65
- _removeFocusedItem() {}
66
-
67
68
  get scrollOffset() {
68
69
  return 0;
69
70
  }
@@ -135,9 +136,9 @@ export class IronListAdapter {
135
136
  }
136
137
 
137
138
  __updateElement(el, index, forceSameIndexUpdates) {
138
- // Clean up temporary min height
139
- if (el.style.minHeight) {
140
- el.style.minHeight = '';
139
+ // Clean up temporary placeholder sizing
140
+ if (el.style.paddingTop) {
141
+ el.style.paddingTop = '';
141
142
  }
142
143
 
143
144
  if (!this.__preventElementUpdates && (el.__lastUpdatedIndex !== index || forceSameIndexUpdates)) {
@@ -145,12 +146,22 @@ export class IronListAdapter {
145
146
  el.__lastUpdatedIndex = index;
146
147
  }
147
148
 
148
- if (el.offsetHeight === 0) {
149
+ const elementHeight = el.offsetHeight;
150
+ if (elementHeight === 0) {
149
151
  // If the elements have 0 height after update (for example due to lazy rendering),
150
152
  // it results in iron-list requesting to create an unlimited count of elements.
151
- // Assign a temporary min height to elements that would otherwise end up having
153
+ // Assign a temporary placeholder sizing to elements that would otherwise end up having
152
154
  // no height.
153
- el.style.minHeight = '200px';
155
+ el.style.paddingTop = `${this.__placeholderHeight}px`;
156
+ } else {
157
+ // Add element height to the queue
158
+ this.__elementHeightQueue.push(elementHeight);
159
+ this.__elementHeightQueue.shift();
160
+
161
+ // Calcualte new placeholder height based on the average of the defined values in the
162
+ // element height queue
163
+ const filteredHeights = this.__elementHeightQueue.filter((h) => h !== undefined);
164
+ this.__placeholderHeight = Math.round(filteredHeights.reduce((a, b) => a + b, 0) / filteredHeights.length);
154
165
  }
155
166
  }
156
167
 
@@ -301,16 +312,28 @@ export class IronListAdapter {
301
312
 
302
313
  _scrollHandler() {
303
314
  this._adjustVirtualIndexOffset(this._scrollTop - (this.__previousScrollTop || 0));
315
+ const delta = this.scrollTarget.scrollTop - this._scrollPosition;
304
316
 
305
317
  super._scrollHandler();
306
318
 
307
319
  if (this._physicalCount !== 0) {
308
- // After running super._scrollHandler, fix _virtualStart to workaround an iron-list issue.
309
- // See https://github.com/vaadin/web-components/issues/1691
310
- const reusables = this._getReusables(true);
311
- this._physicalTop = reusables.physicalTop;
312
- this._virtualStart += reusables.indexes.length;
313
- this._physicalStart += reusables.indexes.length;
320
+ const isScrollingDown = delta >= 0;
321
+ const reusables = this._getReusables(!isScrollingDown);
322
+
323
+ if (reusables.indexes.length) {
324
+ // After running super._scrollHandler, fix internal properties to workaround an iron-list issue.
325
+ // See https://github.com/vaadin/web-components/issues/1691
326
+ this._physicalTop = reusables.physicalTop;
327
+
328
+ if (isScrollingDown) {
329
+ this._virtualStart -= reusables.indexes.length;
330
+ this._physicalStart -= reusables.indexes.length;
331
+ } else {
332
+ this._virtualStart += reusables.indexes.length;
333
+ this._physicalStart += reusables.indexes.length;
334
+ }
335
+ this._resizeHandler();
336
+ }
314
337
  }
315
338
 
316
339
  if (this.reorderElements) {