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

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.
@@ -1,11 +1,11 @@
1
1
  interface Vaadin {
2
2
  developmentModeCallback?: {
3
- 'usage-statistics'?: () => void;
4
- 'vaadin-license-checker'?: () => void;
3
+ 'usage-statistics'?(): void;
4
+ 'vaadin-license-checker'?(): void;
5
5
  };
6
6
  registrations?: Array<{ is: string; version: string }>;
7
7
  usageStatsChecker?: {
8
- maybeGatherAndSend: () => void;
8
+ maybeGatherAndSend(): void;
9
9
  };
10
10
  }
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/component-base",
3
- "version": "23.1.0-beta1",
3
+ "version": "23.1.0-beta2",
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": "8be43cf83102a6b9ccf309687446e590ce0164e8"
45
+ "gitHead": "f11f9245a0b5e6bf912725a501c27c24b74e7c8d"
46
46
  }
package/src/async.d.ts CHANGED
@@ -9,8 +9,8 @@
9
9
  */
10
10
 
11
11
  export interface AsyncInterface {
12
- run: (fn: Function, delay?: number) => number;
13
- cancel: (handle: number) => void;
12
+ run(fn: Function, delay?: number): number;
13
+ cancel(handle: number): void;
14
14
  }
15
15
 
16
16
  /**
@@ -16,7 +16,7 @@ export const isChrome = testUserAgent(/Chrome/) && testVendor(/Google Inc/);
16
16
 
17
17
  export const isFirefox = testUserAgent(/Firefox/);
18
18
 
19
- // iPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
19
+ // IPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
20
20
  export const isIPad = testPlatform(/^iPad/) || (testPlatform(/^Mac/) && navigator.maxTouchPoints > 1);
21
21
 
22
22
  export const isIPhone = testPlatform(/^iPhone/);
@@ -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-beta1';
42
+ return '23.1.0-beta2';
43
43
  }
44
44
 
45
45
  /** @protected */
@@ -68,7 +68,7 @@ export const FocusMixin = dedupingMixin(
68
68
  disconnectedCallback() {
69
69
  super.disconnectedCallback();
70
70
 
71
- // in non-Chrome browsers, blur does not fire on the element when it is disconnected.
71
+ // In non-Chrome browsers, blur does not fire on the element when it is disconnected.
72
72
  // reproducible in `<vaadin-date-picker>` when closing on `Cancel` or `Today` click.
73
73
  if (this.hasAttribute('focused')) {
74
74
  this._setFocused(false);
@@ -84,7 +84,7 @@ export const FocusMixin = dedupingMixin(
84
84
  _setFocused(focused) {
85
85
  this.toggleAttribute('focused', focused);
86
86
 
87
- // focus-ring is true when the element was focused from the keyboard.
87
+ // Focus-ring is true when the element was focused from the keyboard.
88
88
  // Focus Ring [A11ycasts]: https://youtu.be/ilj2P5-5CjI
89
89
  this.toggleAttribute('focus-ring', focused && this._keyboardActive);
90
90
  }
package/src/gestures.d.ts CHANGED
@@ -65,12 +65,12 @@ export { prevent };
65
65
  declare function prevent(evName: string): void;
66
66
 
67
67
  export interface GestureRecognizer {
68
- reset: () => void;
69
- mousedown?: (e: MouseEvent) => void;
70
- mousemove?: (e: MouseEvent) => void;
71
- mouseup?: (e: MouseEvent) => void;
72
- touchstart?: (e: TouchEvent) => void;
73
- touchmove?: (e: TouchEvent) => void;
74
- touchend?: (e: TouchEvent) => void;
75
- click?: (e: MouseEvent) => void;
68
+ reset(): void;
69
+ mousedown?(e: MouseEvent): void;
70
+ mousemove?(e: MouseEvent): void;
71
+ mouseup?(e: MouseEvent): void;
72
+ touchstart?(e: TouchEvent): void;
73
+ touchmove?(e: TouchEvent): void;
74
+ touchend?(e: TouchEvent): void;
75
+ click?(e: MouseEvent): void;
76
76
  }
package/src/gestures.js CHANGED
@@ -26,19 +26,19 @@ import { microTask } from './async.js';
26
26
  const passiveTouchGestures = false;
27
27
  const wrap = (node) => node;
28
28
 
29
- // detect native touch action support
29
+ // Detect native touch action support
30
30
  const HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
31
31
  const GESTURE_KEY = '__polymerGestures';
32
32
  const HANDLED_OBJ = '__polymerGesturesHandled';
33
33
  const TOUCH_ACTION = '__polymerGesturesTouchAction';
34
- // radius for tap and track
34
+ // Radius for tap and track
35
35
  const TAP_DISTANCE = 25;
36
36
  const TRACK_DISTANCE = 5;
37
- // number of last N track positions to keep
37
+ // Number of last N track positions to keep
38
38
  const TRACK_LENGTH = 2;
39
39
 
40
40
  const MOUSE_EVENTS = ['mousedown', 'mousemove', 'mouseup', 'click'];
41
- // an array of bitmask values for mapping MouseEvent.which to MouseEvent.buttons
41
+ // An array of bitmask values for mapping MouseEvent.which to MouseEvent.buttons
42
42
  const MOUSE_WHICH_TO_BUTTONS = [0, 1, 4, 2];
43
43
  const MOUSE_HAS_BUTTONS = (function () {
44
44
  try {
@@ -112,47 +112,47 @@ const canBeDisabled = {
112
112
  */
113
113
  function hasLeftMouseButton(ev) {
114
114
  const type = ev.type;
115
- // exit early if the event is not a mouse event
115
+ // Exit early if the event is not a mouse event
116
116
  if (!isMouseEvent(type)) {
117
117
  return false;
118
118
  }
119
- // ev.button is not reliable for mousemove (0 is overloaded as both left button and no buttons)
119
+ // Ev.button is not reliable for mousemove (0 is overloaded as both left button and no buttons)
120
120
  // instead we use ev.buttons (bitmask of buttons) or fall back to ev.which (deprecated, 0 for no buttons, 1 for left button)
121
121
  if (type === 'mousemove') {
122
- // allow undefined for testing events
122
+ // Allow undefined for testing events
123
123
  let buttons = ev.buttons === undefined ? 1 : ev.buttons;
124
124
  if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
125
125
  buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
126
126
  }
127
- // buttons is a bitmask, check that the left button bit is set (1)
127
+ // Buttons is a bitmask, check that the left button bit is set (1)
128
128
  return Boolean(buttons & 1);
129
129
  }
130
- // allow undefined for testing events
130
+ // Allow undefined for testing events
131
131
  const button = ev.button === undefined ? 0 : ev.button;
132
- // ev.button is 0 in mousedown/mouseup/click for left button activation
132
+ // Ev.button is 0 in mousedown/mouseup/click for left button activation
133
133
  return button === 0;
134
134
  }
135
135
 
136
136
  function isSyntheticClick(ev) {
137
137
  if (ev.type === 'click') {
138
- // ev.detail is 0 for HTMLElement.click in most browsers
138
+ // Ev.detail is 0 for HTMLElement.click in most browsers
139
139
  if (ev.detail === 0) {
140
140
  return true;
141
141
  }
142
- // in the worst case, check that the x/y position of the click is within
142
+ // In the worst case, check that the x/y position of the click is within
143
143
  // the bounding box of the target of the event
144
144
  // Thanks IE 10 >:(
145
145
  const t = _findOriginalTarget(ev);
146
- // make sure the target of the event is an element so we can use getBoundingClientRect,
146
+ // Make sure the target of the event is an element so we can use getBoundingClientRect,
147
147
  // if not, just assume it is a synthetic click
148
148
  if (!t.nodeType || /** @type {Element} */ (t).nodeType !== Node.ELEMENT_NODE) {
149
149
  return true;
150
150
  }
151
151
  const bcr = /** @type {Element} */ (t).getBoundingClientRect();
152
- // use page x/y to account for scrolling
152
+ // Use page x/y to account for scrolling
153
153
  const x = ev.pageX,
154
154
  y = ev.pageY;
155
- // ev is a synthetic click if the position is outside the bounding box of the target
155
+ // Ev is a synthetic click if the position is outside the bounding box of the target
156
156
  return !(x >= bcr.left && x <= bcr.right && y >= bcr.top && y <= bcr.bottom);
157
157
  }
158
158
  return false;
@@ -228,14 +228,14 @@ export const recognizers = [];
228
228
  export function deepTargetFind(x, y) {
229
229
  let node = document.elementFromPoint(x, y);
230
230
  let next = node;
231
- // this code path is only taken when native ShadowDOM is used
231
+ // This code path is only taken when native ShadowDOM is used
232
232
  // if there is a shadowroot, it may have a node at x/y
233
233
  // if there is not a shadowroot, exit the loop
234
234
  while (next && next.shadowRoot && !window.ShadyDOM) {
235
- // if there is a node at x/y in the shadowroot, look deeper
235
+ // If there is a node at x/y in the shadowroot, look deeper
236
236
  const oldNext = next;
237
237
  next = next.shadowRoot.elementFromPoint(x, y);
238
- // on Safari, elementFromPoint may return the shadowRoot host
238
+ // On Safari, elementFromPoint may return the shadowRoot host
239
239
  if (oldNext === next) {
240
240
  break;
241
241
  }
@@ -247,7 +247,7 @@ export function deepTargetFind(x, y) {
247
247
  }
248
248
 
249
249
  /**
250
- * a cheaper check than ev.composedPath()[0];
250
+ * A cheaper check than ev.composedPath()[0];
251
251
  *
252
252
  * @private
253
253
  * @param {Event|Touch} ev Event.
@@ -278,10 +278,9 @@ function _handleNative(ev) {
278
278
  if (!ev[HANDLED_OBJ]) {
279
279
  ev[HANDLED_OBJ] = {};
280
280
  if (type.slice(0, 5) === 'touch') {
281
- // ev = /** @type {TouchEvent} */ (ev); // eslint-disable-line no-self-assign
282
281
  const t = ev.changedTouches[0];
283
282
  if (type === 'touchstart') {
284
- // only handle the first finger
283
+ // Only handle the first finger
285
284
  if (ev.touches.length === 1) {
286
285
  POINTERSTATE.touch.id = t.identifier;
287
286
  }
@@ -297,11 +296,11 @@ function _handleNative(ev) {
297
296
  }
298
297
  }
299
298
  const handled = ev[HANDLED_OBJ];
300
- // used to ignore synthetic mouse events
299
+ // Used to ignore synthetic mouse events
301
300
  if (handled.skip) {
302
301
  return;
303
302
  }
304
- // reset recognizer state
303
+ // Reset recognizer state
305
304
  for (let i = 0, r; i < recognizers.length; i++) {
306
305
  r = recognizers[i];
307
306
  if (gs[r.name] && !handled[r.name]) {
@@ -310,7 +309,7 @@ function _handleNative(ev) {
310
309
  }
311
310
  }
312
311
  }
313
- // enforce gesture recognizer order
312
+ // Enforce gesture recognizer order
314
313
  for (let i = 0, r; i < recognizers.length; i++) {
315
314
  r = recognizers[i];
316
315
  if (gs[r.name] && !handled[r.name]) {
@@ -342,7 +341,7 @@ function _handleTouchAction(ev) {
342
341
  const dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
343
342
  const dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
344
343
  if (!ev.cancelable) {
345
- // scrolling is happening
344
+ // Scrolling is happening
346
345
  } else if (ta === 'none') {
347
346
  shouldPrevent = true;
348
347
  } else if (ta === 'pan-x') {
@@ -392,7 +391,7 @@ export function removeListener(node, evType, handler) {
392
391
  }
393
392
 
394
393
  /**
395
- * automate the event listeners for the native events
394
+ * Automate the event listeners for the native events
396
395
  *
397
396
  * @private
398
397
  * @param {!EventTarget} node Node on which to add the event.
@@ -410,7 +409,7 @@ function _add(node, evType, handler) {
410
409
  }
411
410
  for (let i = 0, dep, gd; i < deps.length; i++) {
412
411
  dep = deps[i];
413
- // don't add mouse handlers on iOS because they cause gray selection overlays
412
+ // Don't add mouse handlers on iOS because they cause gray selection overlays
414
413
  if (IS_TOUCH_ONLY && isMouseEvent(dep) && dep !== 'click') {
415
414
  continue;
416
415
  }
@@ -431,7 +430,7 @@ function _add(node, evType, handler) {
431
430
  }
432
431
 
433
432
  /**
434
- * automate event listener removal for native events
433
+ * Automate event listener removal for native events
435
434
  *
436
435
  * @private
437
436
  * @param {!EventTarget} node Node on which to remove the event.
@@ -528,7 +527,7 @@ function _fire(target, type, detail) {
528
527
  const ev = new Event(type, { bubbles: true, cancelable: true, composed: true });
529
528
  ev.detail = detail;
530
529
  wrap(/** @type {!Node} */ (target)).dispatchEvent(ev);
531
- // forward `preventDefault` in a clean way
530
+ // Forward `preventDefault` in a clean way
532
531
  if (ev.defaultPrevented) {
533
532
  const preventer = detail.preventer || detail.sourceEvent;
534
533
  if (preventer && preventer.preventDefault) {
@@ -568,7 +567,7 @@ register({
568
567
  * @this {GestureRecognizer}
569
568
  * @return {void}
570
569
  */
571
- reset: function () {
570
+ reset() {
572
571
  untrackDocument(this.info);
573
572
  },
574
573
 
@@ -577,7 +576,7 @@ register({
577
576
  * @param {MouseEvent} e
578
577
  * @return {void}
579
578
  */
580
- mousedown: function (e) {
579
+ mousedown(e) {
581
580
  if (!hasLeftMouseButton(e)) {
582
581
  return;
583
582
  }
@@ -605,7 +604,7 @@ register({
605
604
  * @param {TouchEvent} e
606
605
  * @return {void}
607
606
  */
608
- touchstart: function (e) {
607
+ touchstart(e) {
609
608
  downupFire('down', _findOriginalTarget(e), e.changedTouches[0], e);
610
609
  },
611
610
 
@@ -614,7 +613,7 @@ register({
614
613
  * @param {TouchEvent} e
615
614
  * @return {void}
616
615
  */
617
- touchend: function (e) {
616
+ touchend(e) {
618
617
  downupFire('up', _findOriginalTarget(e), e.changedTouches[0], e);
619
618
  },
620
619
  });
@@ -634,8 +633,8 @@ function downupFire(type, target, event, preventer) {
634
633
  x: event.clientX,
635
634
  y: event.clientY,
636
635
  sourceEvent: event,
637
- preventer: preventer,
638
- prevent: function (e) {
636
+ preventer,
637
+ prevent(e) {
639
638
  return prevent(e);
640
639
  },
641
640
  });
@@ -658,7 +657,7 @@ register({
658
657
  started: false,
659
658
  moves: [],
660
659
  /** @this {GestureInfo} */
661
- addMove: function (move) {
660
+ addMove(move) {
662
661
  if (this.moves.length > TRACK_LENGTH) {
663
662
  this.moves.shift();
664
663
  }
@@ -673,7 +672,7 @@ register({
673
672
  * @this {GestureRecognizer}
674
673
  * @return {void}
675
674
  */
676
- reset: function () {
675
+ reset() {
677
676
  this.info.state = 'start';
678
677
  this.info.started = false;
679
678
  this.info.moves = [];
@@ -688,7 +687,7 @@ register({
688
687
  * @param {MouseEvent} e
689
688
  * @return {void}
690
689
  */
691
- mousedown: function (e) {
690
+ mousedown(e) {
692
691
  if (!hasLeftMouseButton(e)) {
693
692
  return;
694
693
  }
@@ -699,15 +698,15 @@ register({
699
698
  const x = e.clientX,
700
699
  y = e.clientY;
701
700
  if (trackHasMovedEnough(self.info, x, y)) {
702
- // first move is 'start', subsequent moves are 'move', mouseup is 'end'
701
+ // First move is 'start', subsequent moves are 'move', mouseup is 'end'
703
702
  self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start';
704
703
  if (self.info.state === 'start') {
705
- // if and only if tracking, always prevent tap
704
+ // If and only if tracking, always prevent tap
706
705
  prevent('tap');
707
706
  }
708
- self.info.addMove({ x: x, y: y });
707
+ self.info.addMove({ x, y });
709
708
  if (!hasLeftMouseButton(e)) {
710
- // always fire "end"
709
+ // Always fire "end"
711
710
  self.info.state = 'end';
712
711
  untrackDocument(self.info);
713
712
  }
@@ -722,10 +721,10 @@ register({
722
721
  movefn(e);
723
722
  }
724
723
 
725
- // remove the temporary listeners
724
+ // Remove the temporary listeners
726
725
  untrackDocument(self.info);
727
726
  };
728
- // add temporary document listeners as mouse retargets
727
+ // Add temporary document listeners as mouse retargets
729
728
  trackDocument(this.info, movefn, upfn);
730
729
  this.info.x = e.clientX;
731
730
  this.info.y = e.clientY;
@@ -736,7 +735,7 @@ register({
736
735
  * @param {TouchEvent} e
737
736
  * @return {void}
738
737
  */
739
- touchstart: function (e) {
738
+ touchstart(e) {
740
739
  const ct = e.changedTouches[0];
741
740
  this.info.x = ct.clientX;
742
741
  this.info.y = ct.clientY;
@@ -747,17 +746,17 @@ register({
747
746
  * @param {TouchEvent} e
748
747
  * @return {void}
749
748
  */
750
- touchmove: function (e) {
749
+ touchmove(e) {
751
750
  const t = _findOriginalTarget(e);
752
751
  const ct = e.changedTouches[0];
753
752
  const x = ct.clientX,
754
753
  y = ct.clientY;
755
754
  if (trackHasMovedEnough(this.info, x, y)) {
756
755
  if (this.info.state === 'start') {
757
- // if and only if tracking, always prevent tap
756
+ // If and only if tracking, always prevent tap
758
757
  prevent('tap');
759
758
  }
760
- this.info.addMove({ x: x, y: y });
759
+ this.info.addMove({ x, y });
761
760
  trackFire(this.info, t, ct);
762
761
  this.info.state = 'track';
763
762
  this.info.started = true;
@@ -769,12 +768,12 @@ register({
769
768
  * @param {TouchEvent} e
770
769
  * @return {void}
771
770
  */
772
- touchend: function (e) {
771
+ touchend(e) {
773
772
  const t = _findOriginalTarget(e);
774
773
  const ct = e.changedTouches[0];
775
- // only trackend if track was started and not aborted
774
+ // Only trackend if track was started and not aborted
776
775
  if (this.info.started) {
777
- // reset started state on up
776
+ // Reset started state on up
778
777
  this.info.state = 'end';
779
778
  this.info.addMove({ x: ct.clientX, y: ct.clientY });
780
779
  trackFire(this.info, t, ct);
@@ -824,12 +823,12 @@ function trackFire(info, target, touch) {
824
823
  state: info.state,
825
824
  x: touch.clientX,
826
825
  y: touch.clientY,
827
- dx: dx,
828
- dy: dy,
829
- ddx: ddx,
830
- ddy: ddy,
826
+ dx,
827
+ dy,
828
+ ddx,
829
+ ddy,
831
830
  sourceEvent: touch,
832
- hover: function () {
831
+ hover() {
833
832
  return deepTargetFind(touch.clientX, touch.clientY);
834
833
  },
835
834
  });
@@ -853,7 +852,7 @@ register({
853
852
  * @this {GestureRecognizer}
854
853
  * @return {void}
855
854
  */
856
- reset: function () {
855
+ reset() {
857
856
  this.info.x = NaN;
858
857
  this.info.y = NaN;
859
858
  this.info.prevent = false;
@@ -864,7 +863,7 @@ register({
864
863
  * @param {MouseEvent} e
865
864
  * @return {void}
866
865
  */
867
- mousedown: function (e) {
866
+ mousedown(e) {
868
867
  if (hasLeftMouseButton(e)) {
869
868
  this.info.x = e.clientX;
870
869
  this.info.y = e.clientY;
@@ -876,7 +875,7 @@ register({
876
875
  * @param {MouseEvent} e
877
876
  * @return {void}
878
877
  */
879
- click: function (e) {
878
+ click(e) {
880
879
  if (hasLeftMouseButton(e)) {
881
880
  trackForward(this.info, e);
882
881
  }
@@ -887,7 +886,7 @@ register({
887
886
  * @param {TouchEvent} e
888
887
  * @return {void}
889
888
  */
890
- touchstart: function (e) {
889
+ touchstart(e) {
891
890
  const touch = e.changedTouches[0];
892
891
  this.info.x = touch.clientX;
893
892
  this.info.y = touch.clientY;
@@ -898,7 +897,7 @@ register({
898
897
  * @param {TouchEvent} e
899
898
  * @return {void}
900
899
  */
901
- touchend: function (e) {
900
+ touchend(e) {
902
901
  trackForward(this.info, e.changedTouches[0], e);
903
902
  },
904
903
  });
@@ -912,20 +911,20 @@ register({
912
911
  function trackForward(info, e, preventer) {
913
912
  const dx = Math.abs(e.clientX - info.x);
914
913
  const dy = Math.abs(e.clientY - info.y);
915
- // find original target from `preventer` for TouchEvents, or `e` for MouseEvents
914
+ // Find original target from `preventer` for TouchEvents, or `e` for MouseEvents
916
915
  const t = _findOriginalTarget(preventer || e);
917
916
  if (!t || (canBeDisabled[/** @type {!HTMLElement} */ (t).localName] && t.hasAttribute('disabled'))) {
918
917
  return;
919
918
  }
920
- // dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`
919
+ // Dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`
921
920
  if (isNaN(dx) || isNaN(dy) || (dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) || isSyntheticClick(e)) {
922
- // prevent taps from being generated if an event has canceled them
921
+ // Prevent taps from being generated if an event has canceled them
923
922
  if (!info.prevent) {
924
923
  _fire(t, 'tap', {
925
924
  x: e.clientX,
926
925
  y: e.clientY,
927
926
  sourceEvent: e,
928
- preventer: preventer,
927
+ preventer,
929
928
  });
930
929
  }
931
930
  }
@@ -166,7 +166,7 @@ export const ironList = {
166
166
  * The height of the physical content that isn't on the screen.
167
167
  */
168
168
  get _hiddenContentSize() {
169
- var size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
169
+ const size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
170
170
  return size - this._viewportHeight;
171
171
  },
172
172
 
@@ -182,7 +182,7 @@ export const ironList = {
182
182
  * `_physicalStart`.
183
183
  */
184
184
  get _maxVirtualStart() {
185
- var virtualCount = this._convertIndexToCompleteRow(this._virtualCount);
185
+ const virtualCount = this._convertIndexToCompleteRow(this._virtualCount);
186
186
  return Math.max(0, virtualCount - this._physicalCount);
187
187
  },
188
188
 
@@ -255,9 +255,9 @@ export const ironList = {
255
255
  * @type {number}
256
256
  */
257
257
  get firstVisibleIndex() {
258
- var idx = this._firstVisibleIndexVal;
258
+ let idx = this._firstVisibleIndexVal;
259
259
  if (idx == null) {
260
- var physicalOffset = this._physicalTop + this._scrollOffset;
260
+ let physicalOffset = this._physicalTop + this._scrollOffset;
261
261
 
262
262
  idx =
263
263
  this._iterateItems((pidx, vidx) => {
@@ -282,12 +282,12 @@ export const ironList = {
282
282
  * @type {number}
283
283
  */
284
284
  get lastVisibleIndex() {
285
- var idx = this._lastVisibleIndexVal;
285
+ let idx = this._lastVisibleIndexVal;
286
286
  if (idx == null) {
287
287
  if (this.grid) {
288
288
  idx = Math.min(this._virtualCount, this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1);
289
289
  } else {
290
- var physicalOffset = this._physicalTop + this._scrollOffset;
290
+ let physicalOffset = this._physicalTop + this._scrollOffset;
291
291
  this._iterateItems((pidx, vidx) => {
292
292
  if (physicalOffset < this._scrollBottom) {
293
293
  idx = vidx;
@@ -323,10 +323,10 @@ export const ironList = {
323
323
  /**
324
324
  * Recycles the physical items when needed.
325
325
  */
326
- _scrollHandler: function () {
327
- var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
328
- var delta = scrollTop - this._scrollPosition;
329
- var isScrollingDown = delta >= 0;
326
+ _scrollHandler() {
327
+ const scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
328
+ let delta = scrollTop - this._scrollPosition;
329
+ const isScrollingDown = delta >= 0;
330
330
  // Track the current scroll position.
331
331
  this._scrollPosition = scrollTop;
332
332
  // Clear indexes for first and last visible indexes.
@@ -335,7 +335,7 @@ export const ironList = {
335
335
  // Random access.
336
336
  if (Math.abs(delta) > this._physicalSize && this._physicalSize > 0) {
337
337
  delta -= this._scrollOffset;
338
- var idxAdjustment = Math.round(delta / this._physicalAverage) * this._itemsPerRow;
338
+ const idxAdjustment = Math.round(delta / this._physicalAverage) * this._itemsPerRow;
339
339
  this._virtualStart += idxAdjustment;
340
340
  this._physicalStart += idxAdjustment;
341
341
  // Estimate new physical offset based on the virtual start index.
@@ -350,7 +350,7 @@ export const ironList = {
350
350
  );
351
351
  this._update();
352
352
  } else if (this._physicalCount > 0) {
353
- var reusables = this._getReusables(isScrollingDown);
353
+ const reusables = this._getReusables(isScrollingDown);
354
354
  if (isScrollingDown) {
355
355
  this._physicalTop = reusables.physicalTop;
356
356
  this._virtualStart += reusables.indexes.length;
@@ -370,18 +370,18 @@ export const ironList = {
370
370
  *
371
371
  * @param {boolean} fromTop If the potential reusable items are above the scrolling region.
372
372
  */
373
- _getReusables: function (fromTop) {
374
- var ith, lastIth, offsetContent, physicalItemHeight;
375
- var idxs = [];
376
- var protectedOffsetContent = this._hiddenContentSize * this._ratio;
377
- var virtualStart = this._virtualStart;
378
- var virtualEnd = this._virtualEnd;
379
- var physicalCount = this._physicalCount;
380
- var top = this._physicalTop + this._scrollOffset;
381
- var bottom = this._physicalBottom + this._scrollOffset;
373
+ _getReusables(fromTop) {
374
+ let ith, lastIth, offsetContent, physicalItemHeight;
375
+ const idxs = [];
376
+ const protectedOffsetContent = this._hiddenContentSize * this._ratio;
377
+ const virtualStart = this._virtualStart;
378
+ const virtualEnd = this._virtualEnd;
379
+ const physicalCount = this._physicalCount;
380
+ let top = this._physicalTop + this._scrollOffset;
381
+ const bottom = this._physicalBottom + this._scrollOffset;
382
382
  // This may be called outside of a scrollHandler, so use last cached position
383
- var scrollTop = this._scrollPosition;
384
- var scrollBottom = this._scrollBottom;
383
+ const scrollTop = this._scrollPosition;
384
+ const scrollBottom = this._scrollBottom;
385
385
 
386
386
  if (fromTop) {
387
387
  ith = this._physicalStart;
@@ -434,7 +434,7 @@ export const ironList = {
434
434
  * @param {!Array<number>=} itemSet
435
435
  * @param {!Array<number>=} movingUp
436
436
  */
437
- _update: function (itemSet, movingUp) {
437
+ _update(itemSet, movingUp) {
438
438
  if ((itemSet && itemSet.length === 0) || this._physicalCount === 0) {
439
439
  return;
440
440
  }
@@ -444,7 +444,7 @@ export const ironList = {
444
444
  // Adjust offset after measuring.
445
445
  if (movingUp) {
446
446
  while (movingUp.length) {
447
- var idx = movingUp.pop();
447
+ const idx = movingUp.pop();
448
448
  this._physicalTop -= this._getPhysicalSizeIncrement(idx);
449
449
  }
450
450
  }
@@ -452,7 +452,7 @@ export const ironList = {
452
452
  this._updateScrollerSize();
453
453
  },
454
454
 
455
- _isClientFull: function () {
455
+ _isClientFull() {
456
456
  return (
457
457
  this._scrollBottom !== 0 &&
458
458
  this._physicalBottom - 1 >= this._scrollBottom &&
@@ -463,33 +463,33 @@ export const ironList = {
463
463
  /**
464
464
  * Increases the pool size.
465
465
  */
466
- _increasePoolIfNeeded: function (count) {
467
- var nextPhysicalCount = this._clamp(
466
+ _increasePoolIfNeeded(count) {
467
+ let nextPhysicalCount = this._clamp(
468
468
  this._physicalCount + count,
469
469
  DEFAULT_PHYSICAL_COUNT,
470
470
  this._virtualCount - this._virtualStart,
471
471
  );
472
472
  nextPhysicalCount = this._convertIndexToCompleteRow(nextPhysicalCount);
473
473
  if (this.grid) {
474
- var correction = nextPhysicalCount % this._itemsPerRow;
474
+ const correction = nextPhysicalCount % this._itemsPerRow;
475
475
  if (correction && nextPhysicalCount - correction <= this._physicalCount) {
476
476
  nextPhysicalCount += this._itemsPerRow;
477
477
  }
478
478
  nextPhysicalCount -= correction;
479
479
  }
480
- var delta = nextPhysicalCount - this._physicalCount;
481
- var nextIncrease = Math.round(this._physicalCount * 0.5);
480
+ const delta = nextPhysicalCount - this._physicalCount;
481
+ let nextIncrease = Math.round(this._physicalCount * 0.5);
482
482
 
483
483
  if (delta < 0) {
484
484
  return;
485
485
  }
486
486
  if (delta > 0) {
487
- var ts = window.performance.now();
487
+ const ts = window.performance.now();
488
488
  // Concat arrays in place.
489
489
  [].push.apply(this._physicalItems, this._createPool(delta));
490
490
  // Push 0s into physicalSizes. Can't use Array.fill because IE11 doesn't
491
491
  // support it.
492
- for (var i = 0; i < delta; i++) {
492
+ for (let i = 0; i < delta; i++) {
493
493
  this._physicalSizes.push(0);
494
494
  }
495
495
  this._physicalCount += delta;
@@ -528,12 +528,12 @@ export const ironList = {
528
528
  /**
529
529
  * Renders the a new list.
530
530
  */
531
- _render: function () {
531
+ _render() {
532
532
  if (!this.isAttached || !this._isVisible) {
533
533
  return;
534
534
  }
535
535
  if (this._physicalCount !== 0) {
536
- var reusables = this._getReusables(true);
536
+ const reusables = this._getReusables(true);
537
537
  this._physicalTop = reusables.physicalTop;
538
538
  this._virtualStart += reusables.indexes.length;
539
539
  this._physicalStart += reusables.indexes.length;
@@ -547,7 +547,7 @@ export const ironList = {
547
547
  }
548
548
  },
549
549
 
550
- _gridChanged: function (newGrid, oldGrid) {
550
+ _gridChanged(newGrid, oldGrid) {
551
551
  if (typeof oldGrid === 'undefined') {
552
552
  return;
553
553
  }
@@ -562,7 +562,7 @@ export const ironList = {
562
562
  * Called when the items have changed. That is, reassignments
563
563
  * to `items`, splices or updates to a single item.
564
564
  */
565
- _itemsChanged: function (change) {
565
+ _itemsChanged(change) {
566
566
  if (change.path === 'items') {
567
567
  this._virtualStart = 0;
568
568
  this._physicalTop = 0;
@@ -583,19 +583,19 @@ export const ironList = {
583
583
  this._adjustVirtualIndex(change.value.indexSplices);
584
584
  this._virtualCount = this.items ? this.items.length : 0;
585
585
  // Only blur if at least one item is added or removed.
586
- var itemAddedOrRemoved = change.value.indexSplices.some((splice) => {
586
+ const itemAddedOrRemoved = change.value.indexSplices.some((splice) => {
587
587
  return splice.addedCount > 0 || splice.removed.length > 0;
588
588
  });
589
589
  if (itemAddedOrRemoved) {
590
590
  // Only blur activeElement if it is a descendant of the list (#505,
591
591
  // #507).
592
- var activeElement = this._getActiveElement();
592
+ const activeElement = this._getActiveElement();
593
593
  if (this.contains(activeElement)) {
594
594
  activeElement.blur();
595
595
  }
596
596
  }
597
597
  // Render only if the affected index is rendered.
598
- var affectedIndexRendered = change.value.indexSplices.some((splice) => {
598
+ const affectedIndexRendered = change.value.indexSplices.some((splice) => {
599
599
  return splice.index + splice.addedCount >= this._virtualStart && splice.index <= this._virtualEnd;
600
600
  });
601
601
  if (!this._isClientFull() || affectedIndexRendered) {
@@ -614,8 +614,8 @@ export const ironList = {
614
614
  * @param {!function(number, number)} fn
615
615
  * @param {!Array<number>=} itemSet
616
616
  */
617
- _iterateItems: function (fn, itemSet) {
618
- var pidx, vidx, rtn, i;
617
+ _iterateItems(fn, itemSet) {
618
+ let pidx, vidx, rtn, i;
619
619
 
620
620
  if (arguments.length === 2 && itemSet) {
621
621
  for (i = 0; i < itemSet.length; i++) {
@@ -647,7 +647,7 @@ export const ironList = {
647
647
  * @param {number} pidx Physical index
648
648
  * @return {number}
649
649
  */
650
- _computeVidx: function (pidx) {
650
+ _computeVidx(pidx) {
651
651
  if (pidx >= this._physicalStart) {
652
652
  return this._virtualStart + (pidx - this._physicalStart);
653
653
  }
@@ -659,15 +659,15 @@ export const ironList = {
659
659
  *
660
660
  * @param {!Array<number>=} itemSet
661
661
  */
662
- _updateMetrics: function (itemSet) {
662
+ _updateMetrics(itemSet) {
663
663
  // Make sure we distributed all the physical items
664
664
  // so we can measure them.
665
665
  flush();
666
666
 
667
- var newPhysicalSize = 0;
668
- var oldPhysicalSize = 0;
669
- var prevAvgCount = this._physicalAverageCount;
670
- var prevPhysicalAvg = this._physicalAverage;
667
+ let newPhysicalSize = 0;
668
+ let oldPhysicalSize = 0;
669
+ const prevAvgCount = this._physicalAverageCount;
670
+ const prevPhysicalAvg = this._physicalAverage;
671
671
 
672
672
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
673
673
  this._iterateItems((pidx, vidx) => {
@@ -696,7 +696,7 @@ export const ironList = {
696
696
  }
697
697
  },
698
698
 
699
- _updateGridMetrics: function () {
699
+ _updateGridMetrics() {
700
700
  this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : 200;
701
701
  this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : 200;
702
702
  this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
@@ -705,18 +705,18 @@ export const ironList = {
705
705
  /**
706
706
  * Updates the position of the physical items.
707
707
  */
708
- _positionItems: function () {
708
+ _positionItems() {
709
709
  this._adjustScrollPosition();
710
710
 
711
- var y = this._physicalTop;
711
+ let y = this._physicalTop;
712
712
 
713
713
  if (this.grid) {
714
- var totalItemWidth = this._itemsPerRow * this._itemWidth;
715
- var rowOffset = (this._viewportWidth - totalItemWidth) / 2;
714
+ const totalItemWidth = this._itemsPerRow * this._itemWidth;
715
+ const rowOffset = (this._viewportWidth - totalItemWidth) / 2;
716
716
 
717
717
  this._iterateItems((pidx, vidx) => {
718
- var modulus = vidx % this._itemsPerRow;
719
- var x = Math.floor(modulus * this._itemWidth + rowOffset);
718
+ const modulus = vidx % this._itemsPerRow;
719
+ let x = Math.floor(modulus * this._itemWidth + rowOffset);
720
720
  if (this._isRTL) {
721
721
  x *= -1;
722
722
  }
@@ -743,7 +743,7 @@ export const ironList = {
743
743
  }
744
744
  },
745
745
 
746
- _getPhysicalSizeIncrement: function (pidx) {
746
+ _getPhysicalSizeIncrement(pidx) {
747
747
  if (!this.grid) {
748
748
  return this._physicalSizes[pidx];
749
749
  }
@@ -761,22 +761,22 @@ export const ironList = {
761
761
  * @param {number} vidx Virtual index
762
762
  * @return {boolean}
763
763
  */
764
- _shouldRenderNextRow: function (vidx) {
764
+ _shouldRenderNextRow(vidx) {
765
765
  return vidx % this._itemsPerRow === this._itemsPerRow - 1;
766
766
  },
767
767
 
768
768
  /**
769
769
  * Adjusts the scroll position when it was overestimated.
770
770
  */
771
- _adjustScrollPosition: function () {
772
- var deltaHeight =
771
+ _adjustScrollPosition() {
772
+ const deltaHeight =
773
773
  this._virtualStart === 0 ? this._physicalTop : Math.min(this._scrollPosition + this._physicalTop, 0);
774
774
  // Note: the delta can be positive or negative.
775
775
  if (deltaHeight !== 0) {
776
776
  this._physicalTop -= deltaHeight;
777
777
  // This may be called outside of a scrollHandler, so use last cached position
778
- var scrollTop = this._scrollPosition;
779
- // juking scroll position during interial scrolling on iOS is no bueno
778
+ const scrollTop = this._scrollPosition;
779
+ // Juking scroll position during interial scrolling on iOS is no bueno
780
780
  if (!IOS_TOUCH_SCROLLING && scrollTop > 0) {
781
781
  this._resetScrollPosition(scrollTop - deltaHeight);
782
782
  }
@@ -786,7 +786,7 @@ export const ironList = {
786
786
  /**
787
787
  * Sets the position of the scroll.
788
788
  */
789
- _resetScrollPosition: function (pos) {
789
+ _resetScrollPosition(pos) {
790
790
  if (this.scrollTarget && pos >= 0) {
791
791
  this._scrollTop = pos;
792
792
  this._scrollPosition = this._scrollTop;
@@ -798,7 +798,7 @@ export const ironList = {
798
798
  *
799
799
  * @param {boolean=} forceUpdate If true, updates the height no matter what.
800
800
  */
801
- _updateScrollerSize: function (forceUpdate) {
801
+ _updateScrollerSize(forceUpdate) {
802
802
  if (this.grid) {
803
803
  this._estScrollHeight = this._virtualRowCount * this._rowHeight;
804
804
  } else {
@@ -823,7 +823,7 @@ export const ironList = {
823
823
  * @method scrollToIndex
824
824
  * @param {number} idx The index of the item
825
825
  */
826
- scrollToIndex: function (idx) {
826
+ scrollToIndex(idx) {
827
827
  if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
828
828
  return;
829
829
  }
@@ -843,11 +843,11 @@ export const ironList = {
843
843
  // Estimate new physical offset.
844
844
  this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
845
845
 
846
- var currentTopItem = this._physicalStart;
847
- var currentVirtualItem = this._virtualStart;
848
- var targetOffsetTop = 0;
849
- var hiddenContentSize = this._hiddenContentSize;
850
- // scroll to the item as much as we can.
846
+ let currentTopItem = this._physicalStart;
847
+ let currentVirtualItem = this._virtualStart;
848
+ let targetOffsetTop = 0;
849
+ const hiddenContentSize = this._hiddenContentSize;
850
+ // Scroll to the item as much as we can.
851
851
  while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
852
852
  targetOffsetTop += this._getPhysicalSizeIncrement(currentTopItem);
853
853
  currentTopItem = (currentTopItem + 1) % this._physicalCount;
@@ -857,7 +857,7 @@ export const ironList = {
857
857
  this._positionItems();
858
858
  this._resetScrollPosition(this._physicalTop + this._scrollOffset + targetOffsetTop);
859
859
  this._increasePoolIfNeeded(0);
860
- // clear cached visible index.
860
+ // Clear cached visible index.
861
861
  this._firstVisibleIndexVal = null;
862
862
  this._lastVisibleIndexVal = null;
863
863
  },
@@ -865,7 +865,7 @@ export const ironList = {
865
865
  /**
866
866
  * Reset the physical average and the average count.
867
867
  */
868
- _resetAverage: function () {
868
+ _resetAverage() {
869
869
  this._physicalAverage = 0;
870
870
  this._physicalAverageCount = 0;
871
871
  },
@@ -874,11 +874,11 @@ export const ironList = {
874
874
  * A handler for the `iron-resize` event triggered by `IronResizableBehavior`
875
875
  * when the element is resized.
876
876
  */
877
- _resizeHandler: function () {
877
+ _resizeHandler() {
878
878
  this._debounce(
879
879
  '_render',
880
880
  () => {
881
- // clear cached visible index.
881
+ // Clear cached visible index.
882
882
  this._firstVisibleIndexVal = null;
883
883
  this._lastVisibleIndexVal = null;
884
884
  if (this._isVisible) {
@@ -902,7 +902,7 @@ export const ironList = {
902
902
  * @method updateSizeForItem
903
903
  * @param {Object} item The item instance.
904
904
  */
905
- updateSizeForItem: function (item) {
905
+ updateSizeForItem(item) {
906
906
  return this.updateSizeForIndex(this.items.indexOf(item));
907
907
  },
908
908
 
@@ -912,7 +912,7 @@ export const ironList = {
912
912
  * @method updateSizeForIndex
913
913
  * @param {number} index The index of the item in the items array.
914
914
  */
915
- updateSizeForIndex: function (index) {
915
+ updateSizeForIndex(index) {
916
916
  if (!this._isIndexRendered(index)) {
917
917
  return null;
918
918
  }
@@ -925,29 +925,29 @@ export const ironList = {
925
925
  * Converts a random index to the index of the item that completes it's row.
926
926
  * Allows for better order and fill computation when grid == true.
927
927
  */
928
- _convertIndexToCompleteRow: function (idx) {
929
- // when grid == false _itemPerRow can be unset.
928
+ _convertIndexToCompleteRow(idx) {
929
+ // When grid == false _itemPerRow can be unset.
930
930
  this._itemsPerRow = this._itemsPerRow || 1;
931
931
  return this.grid ? Math.ceil(idx / this._itemsPerRow) * this._itemsPerRow : idx;
932
932
  },
933
933
 
934
- _isIndexRendered: function (idx) {
934
+ _isIndexRendered(idx) {
935
935
  return idx >= this._virtualStart && idx <= this._virtualEnd;
936
936
  },
937
937
 
938
- _isIndexVisible: function (idx) {
938
+ _isIndexVisible(idx) {
939
939
  return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
940
940
  },
941
941
 
942
- _getPhysicalIndex: function (vidx) {
942
+ _getPhysicalIndex(vidx) {
943
943
  return (this._physicalStart + (vidx - this._virtualStart)) % this._physicalCount;
944
944
  },
945
945
 
946
- _clamp: function (v, min, max) {
946
+ _clamp(v, min, max) {
947
947
  return Math.min(max, Math.max(min, v));
948
948
  },
949
949
 
950
- _debounce: function (name, cb, asyncModule) {
950
+ _debounce(name, cb, asyncModule) {
951
951
  this._debouncers = this._debouncers || {};
952
952
  this._debouncers[name] = Debouncer.debounce(this._debouncers[name], asyncModule, cb.bind(this));
953
953
  enqueueDebouncer(this._debouncers[name]);
@@ -32,7 +32,7 @@ function parseObserver(observerString) {
32
32
 
33
33
  function getOrCreateMap(obj, name) {
34
34
  if (!Object.prototype.hasOwnProperty.call(obj, name)) {
35
- // clone any existing entries (superclasses)
35
+ // Clone any existing entries (superclasses)
36
36
  obj[name] = new Map(obj[name]);
37
37
  }
38
38
  return obj[name];
@@ -123,7 +123,7 @@ const PolylitMixinImplementation = (superclass) => {
123
123
  if (options.observer) {
124
124
  const method = options.observer;
125
125
 
126
- // set this method
126
+ // Set this method
127
127
  this.getOrCreateMap('__observers').set(name, method);
128
128
 
129
129
  this.addCheckedInitializer((instance) => {
@@ -138,12 +138,12 @@ const PolylitMixinImplementation = (superclass) => {
138
138
  this.__notifyProps = new Set();
139
139
  // eslint-disable-next-line no-prototype-builtins
140
140
  } else if (!this.hasOwnProperty('__notifyProps')) {
141
- // clone any existing observers (superclasses)
141
+ // Clone any existing observers (superclasses)
142
142
  const notifyProps = this.__notifyProps;
143
143
  this.__notifyProps = new Set(notifyProps);
144
144
  }
145
145
 
146
- // set this method
146
+ // Set this method
147
147
  this.__notifyProps.add(name);
148
148
  }
149
149
 
@@ -16,4 +16,10 @@ export declare class ResizeMixinClass {
16
16
  * Override the method to implement your own behavior.
17
17
  */
18
18
  protected _onResize(contentRect: DOMRect): void;
19
+
20
+ /**
21
+ * When true, the parent element resize will be also observed.
22
+ * Override this getter and return `true` to enable this.
23
+ */
24
+ protected readonly _observeParent: boolean;
19
25
  }
@@ -8,7 +8,14 @@ import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
8
8
  const observer = new ResizeObserver((entries) => {
9
9
  setTimeout(() => {
10
10
  entries.forEach((entry) => {
11
- entry.target._onResize(entry.contentRect);
11
+ // Notify child resizables, if any
12
+ if (entry.target.resizables) {
13
+ entry.target.resizables.forEach((resizable) => {
14
+ resizable._onResize(entry.contentRect);
15
+ });
16
+ } else {
17
+ entry.target._onResize(entry.contentRect);
18
+ }
12
19
  });
13
20
  });
14
21
  });
@@ -25,12 +32,49 @@ export const ResizeMixin = dedupingMixin(
25
32
  connectedCallback() {
26
33
  super.connectedCallback();
27
34
  observer.observe(this);
35
+
36
+ if (this._observeParent) {
37
+ const parent = this.parentNode instanceof ShadowRoot ? this.parentNode.host : this.parentNode;
38
+
39
+ if (!parent.resizables) {
40
+ parent.resizables = new Set();
41
+ observer.observe(parent);
42
+ }
43
+
44
+ parent.resizables.add(this);
45
+ this.__parent = parent;
46
+ }
28
47
  }
29
48
 
30
49
  /** @protected */
31
50
  disconnectedCallback() {
32
51
  super.disconnectedCallback();
33
52
  observer.unobserve(this);
53
+
54
+ const parent = this.__parent;
55
+ if (this._observeParent && parent) {
56
+ const resizables = parent.resizables;
57
+
58
+ if (resizables) {
59
+ resizables.delete(this);
60
+
61
+ if (resizables.size === 0) {
62
+ observer.unobserve(parent);
63
+ }
64
+ }
65
+
66
+ this.__parent = null;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * When true, the parent element resize will be also observed.
72
+ * Override this getter and return `true` to enable this.
73
+ *
74
+ * @protected
75
+ */
76
+ get _observeParent() {
77
+ return false;
34
78
  }
35
79
 
36
80
  /**
@@ -8,7 +8,7 @@ import { isSafari } from './browser-utils.js';
8
8
  import { Debouncer, flush } from './debounce.js';
9
9
  import { ironList } from './iron-list-core.js';
10
10
 
11
- // iron-list can by default handle sizes up to around 100000.
11
+ // Iron-list can by default handle sizes up to around 100000.
12
12
  // When the size is larger than MAX_VIRTUAL_COUNT _vidxOffset is used
13
13
  const MAX_VIRTUAL_COUNT = 100000;
14
14
  const OFFSET_ADJUST_MIN_THRESHOLD = 1000;
@@ -172,8 +172,8 @@ export class IronListAdapter {
172
172
  this.__preventElementUpdates = true;
173
173
 
174
174
  // Record the scroll position before changing the size
175
- let fvi; // first visible index
176
- let fviOffsetBefore; // scroll offset of the first visible index
175
+ let fvi; // First visible index
176
+ let fviOffsetBefore; // Scroll offset of the first visible index
177
177
  if (size > 0) {
178
178
  fvi = this.adjustedFirstVisibleIndex;
179
179
  fviOffsetBefore = this.__getIndexScrollOffset(fvi);
@@ -304,6 +304,15 @@ export class IronListAdapter {
304
304
 
305
305
  super._scrollHandler();
306
306
 
307
+ 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;
314
+ }
315
+
307
316
  if (this.reorderElements) {
308
317
  this.__scrollReorderDebouncer = Debouncer.debounce(
309
318
  this.__scrollReorderDebouncer,