@vaadin/component-base 23.1.0-alpha1 → 23.1.0-alpha4

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-alpha1",
3
+ "version": "23.1.0-alpha4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -40,7 +40,7 @@
40
40
  "devDependencies": {
41
41
  "@esm-bundle/chai": "^4.3.4",
42
42
  "@vaadin/testing-helpers": "^0.3.2",
43
- "sinon": "^9.2.4"
43
+ "sinon": "^13.0.2"
44
44
  },
45
- "gitHead": "5d0cdee069f866037c507265fafb4d0476795333"
45
+ "gitHead": "aacdb7fe09811894751f0378ff7fb66071892c71"
46
46
  }
@@ -17,7 +17,7 @@ import { KeyboardMixinClass } from './keyboard-mixin.js';
17
17
  * by the pointer or by releasing the activation key.
18
18
  */
19
19
  export declare function ActiveMixin<T extends Constructor<HTMLElement>>(
20
- base: T
20
+ base: T,
21
21
  ): T & Constructor<ActiveMixinClass> & Constructor<DisabledMixinClass> & Constructor<KeyboardMixinClass>;
22
22
 
23
23
  export declare class ActiveMixinClass {
package/src/async.d.ts ADDED
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
4
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
+ * Code distributed by Google as part of the polymer project is also
8
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9
+ */
10
+
11
+ export interface AsyncInterface {
12
+ run: (fn: Function, delay?: number) => number;
13
+ cancel: (handle: number) => void;
14
+ }
15
+
16
+ /**
17
+ * Not defined in the TypeScript DOM library.
18
+ * See https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline
19
+ */
20
+ export interface IdleDeadline {
21
+ didTimeout: boolean;
22
+ timeRemaining(): number;
23
+ }
24
+
25
+ /**
26
+ * Async interface wrapper around `setTimeout`.
27
+ */
28
+ declare namespace timeOut {
29
+ /**
30
+ * Returns a sub-module with the async interface providing the provided
31
+ * delay.
32
+ *
33
+ * @returns An async timeout interface
34
+ */
35
+ function after(delay?: number): AsyncInterface;
36
+
37
+ /**
38
+ * Enqueues a function called in the next task.
39
+ *
40
+ * @returns Handle used for canceling task
41
+ */
42
+ function run(fn: Function, delay?: number): number;
43
+
44
+ /**
45
+ * Cancels a previously enqueued `timeOut` callback.
46
+ */
47
+ function cancel(handle: number): void;
48
+ }
49
+
50
+ export { timeOut };
51
+
52
+ /**
53
+ * Async interface wrapper around `requestAnimationFrame`.
54
+ */
55
+ declare namespace animationFrame {
56
+ /**
57
+ * Enqueues a function called at `requestAnimationFrame` timing.
58
+ *
59
+ * @returns Handle used for canceling task
60
+ */
61
+ function run(fn: (p0: number) => void): number;
62
+
63
+ /**
64
+ * Cancels a previously enqueued `animationFrame` callback.
65
+ */
66
+ function cancel(handle: number): void;
67
+ }
68
+
69
+ export { animationFrame };
70
+
71
+ /**
72
+ * Async interface wrapper around `requestIdleCallback`. Falls back to
73
+ * `setTimeout` on browsers that do not support `requestIdleCallback`.
74
+ */
75
+ declare namespace idlePeriod {
76
+ /**
77
+ * Enqueues a function called at `requestIdleCallback` timing.
78
+ *
79
+ * @returns Handle used for canceling task
80
+ */
81
+ function run(fn: (p0: IdleDeadline) => void): number;
82
+
83
+ /**
84
+ * Cancels a previously enqueued `idlePeriod` callback.
85
+ */
86
+ function cancel(handle: number): void;
87
+ }
88
+
89
+ export { idlePeriod };
90
+
91
+ /**
92
+ * Async interface for enqueuing callbacks that run at microtask timing.
93
+ *
94
+ * Note that microtask timing is achieved via a single `MutationObserver`,
95
+ * and thus callbacks enqueued with this API will all run in a single
96
+ * batch, and not interleaved with other microtasks such as promises.
97
+ * Promises are avoided as an implementation choice for the time being
98
+ * due to Safari bugs that cause Promises to lack microtask guarantees.
99
+ */
100
+ declare namespace microTask {
101
+ /**
102
+ * Enqueues a function called at microtask timing.
103
+ *
104
+ * @returns Handle used for canceling task
105
+ */
106
+ function run(callback?: Function): number;
107
+
108
+ /**
109
+ * Cancels a previously enqueued `microTask` callback.
110
+ */
111
+ function cancel(handle: number): void;
112
+ }
113
+
114
+ export { microTask };
package/src/async.js CHANGED
@@ -70,7 +70,7 @@ const timeOut = {
70
70
  },
71
71
  cancel(handle) {
72
72
  window.clearTimeout(handle);
73
- }
73
+ },
74
74
  };
75
75
  },
76
76
  /**
@@ -93,7 +93,7 @@ const timeOut = {
93
93
  */
94
94
  cancel(handle) {
95
95
  window.clearTimeout(handle);
96
- }
96
+ },
97
97
  };
98
98
  export { timeOut };
99
99
 
@@ -123,7 +123,7 @@ const animationFrame = {
123
123
  */
124
124
  cancel(handle) {
125
125
  window.cancelAnimationFrame(handle);
126
- }
126
+ },
127
127
  };
128
128
  export { animationFrame };
129
129
 
@@ -153,8 +153,12 @@ const idlePeriod = {
153
153
  * @return {void}
154
154
  */
155
155
  cancel(handle) {
156
- window.cancelIdleCallback ? window.cancelIdleCallback(handle) : window.clearTimeout(handle);
157
- }
156
+ if (window.cancelIdleCallback) {
157
+ window.cancelIdleCallback(handle);
158
+ } else {
159
+ window.clearTimeout(handle);
160
+ }
161
+ },
158
162
  };
159
163
  export { idlePeriod };
160
164
 
@@ -202,10 +206,10 @@ const microTask = {
202
206
  const idx = handle - microtaskLastHandle;
203
207
  if (idx >= 0) {
204
208
  if (!microtaskCallbacks[idx]) {
205
- throw new Error('invalid async handle: ' + handle);
209
+ throw new Error(`invalid async handle: ${handle}`);
206
210
  }
207
211
  microtaskCallbacks[idx] = null;
208
212
  }
209
- }
213
+ },
210
214
  };
211
215
  export { microTask };
@@ -10,7 +10,7 @@ import { ReactiveController, ReactiveControllerHost } from 'lit';
10
10
  * A mixin for connecting controllers to the element.
11
11
  */
12
12
  export declare function ControllerMixin<T extends Constructor<HTMLElement>>(
13
- superclass: T
13
+ superclass: T,
14
14
  ): T & Constructor<ControllerMixinClass>;
15
15
 
16
16
  export declare class ControllerMixinClass
@@ -27,7 +27,9 @@ export const ControllerMixin = dedupingMixin(
27
27
  super.connectedCallback();
28
28
 
29
29
  this.__controllers.forEach((c) => {
30
- c.hostConnected && c.hostConnected();
30
+ if (c.hostConnected) {
31
+ c.hostConnected();
32
+ }
31
33
  });
32
34
  }
33
35
 
@@ -36,7 +38,9 @@ export const ControllerMixin = dedupingMixin(
36
38
  super.disconnectedCallback();
37
39
 
38
40
  this.__controllers.forEach((c) => {
39
- c.hostDisconnected && c.hostDisconnected();
41
+ if (c.hostDisconnected) {
42
+ c.hostDisconnected();
43
+ }
40
44
  });
41
45
  }
42
46
 
@@ -63,5 +67,5 @@ export const ControllerMixin = dedupingMixin(
63
67
  removeController(controller) {
64
68
  this.__controllers.delete(controller);
65
69
  }
66
- }
70
+ },
67
71
  );
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
4
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
+ * Code distributed by Google as part of the polymer project is also
8
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9
+ */
10
+ import { AsyncInterface } from './async.js';
11
+
12
+ export declare class Debouncer {
13
+ constructor();
14
+
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 object.
45
+ * @param asyncModule Object with Async interface
46
+ * @param callback Callback to run.
47
+ * @returns Returns a debouncer object.
48
+ */
49
+ static debounce(debouncer: Debouncer | null, asyncModule: AsyncInterface, callback: () => any): Debouncer;
50
+
51
+ /**
52
+ * Sets the scheduler; that is, a module with the Async interface,
53
+ * a callback and optional arguments to be passed to the run function
54
+ * from the async module.
55
+ *
56
+ * @param asyncModule Object with Async interface.
57
+ * @param callback Callback to run.
58
+ */
59
+ setConfig(asyncModule: AsyncInterface, callback: () => any): void;
60
+
61
+ /**
62
+ * Cancels an active debouncer and returns a reference to itself.
63
+ */
64
+ cancel(): void;
65
+
66
+ /**
67
+ * Cancels a debouncer's async callback.
68
+ */
69
+ _cancelAsync(): void;
70
+
71
+ /**
72
+ * Flushes an active debouncer and returns a reference to itself.
73
+ */
74
+ flush(): void;
75
+
76
+ /**
77
+ * Returns true if the debouncer is active.
78
+ *
79
+ * @returns True if active.
80
+ */
81
+ isActive(): boolean;
82
+ }
83
+
84
+ /**
85
+ * Adds a `Debouncer` to a list of globally flushable tasks.
86
+ */
87
+ export declare function enqueueDebouncer(debouncer: Debouncer): void;
88
+
89
+ /**
90
+ * Flushes any enqueued debouncers.
91
+ *
92
+ * @returns Returns whether any debouncers were flushed
93
+ */
94
+ export declare function flushDebouncers(): boolean;
95
+
96
+ /**
97
+ * Forces debouncers added via `enqueueDebouncer` to flush.
98
+ *
99
+ * @return {void}
100
+ */
101
+ export declare function flush(): void;
@@ -35,7 +35,7 @@ declare class DirHelper {
35
35
  scrollType: string,
36
36
  direction: string,
37
37
  element: Element | null,
38
- scrollLeft: number
38
+ scrollLeft: number,
39
39
  ): void;
40
40
  }
41
41
 
package/src/dir-mixin.js CHANGED
@@ -48,8 +48,16 @@ export const DirMixin = (superClass) =>
48
48
  dir: {
49
49
  type: String,
50
50
  value: '',
51
- reflectToAttribute: true
52
- }
51
+ reflectToAttribute: true,
52
+ converter: {
53
+ fromAttribute: (attr) => {
54
+ return !attr ? '' : attr;
55
+ },
56
+ toAttribute: (prop) => {
57
+ return prop === '' ? null : prop;
58
+ },
59
+ },
60
+ },
53
61
  };
54
62
  }
55
63
 
@@ -127,9 +135,11 @@ export const DirMixin = (superClass) =>
127
135
  /** @private */
128
136
  __subscribe(push = true) {
129
137
  if (push) {
130
- directionSubscribers.indexOf(this) === -1 && directionSubscribers.push(this);
131
- } else {
132
- directionSubscribers.indexOf(this) > -1 && directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
138
+ if (!directionSubscribers.includes(this)) {
139
+ directionSubscribers.push(this);
140
+ }
141
+ } else if (directionSubscribers.includes(this)) {
142
+ directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
133
143
  }
134
144
  }
135
145
 
@@ -22,8 +22,8 @@ export const DisabledMixin = dedupingMixin(
22
22
  type: Boolean,
23
23
  value: false,
24
24
  observer: '_disabledChanged',
25
- reflectToAttribute: true
26
- }
25
+ reflectToAttribute: true,
26
+ },
27
27
  };
28
28
  }
29
29
 
@@ -58,5 +58,5 @@ export const DisabledMixin = dedupingMixin(
58
58
  super.click();
59
59
  }
60
60
  }
61
- }
61
+ },
62
62
  );
@@ -12,7 +12,7 @@ import { DirMixinClass } from './dir-mixin.js';
12
12
  * A mixin providing common logic for Vaadin components.
13
13
  */
14
14
  export declare function ElementMixin<T extends Constructor<HTMLElement>>(
15
- superclass: T
15
+ superclass: T,
16
16
  ): T & Constructor<DirMixinClass> & Constructor<ElementMixinClass>;
17
17
 
18
18
  export declare class ElementMixinClass {
@@ -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-alpha1';
42
+ return '23.1.0-alpha4';
43
43
  }
44
44
 
45
45
  /** @protected */
@@ -67,7 +67,7 @@ export const ElementMixin = (superClass) =>
67
67
 
68
68
  if (document.doctype === null) {
69
69
  console.warn(
70
- 'Vaadin components require the "standards mode" declaration. Please add <!DOCTYPE html> to the HTML document.'
70
+ 'Vaadin components require the "standards mode" declaration. Please add <!DOCTYPE html> to the HTML document.',
71
71
  );
72
72
  }
73
73
  }
@@ -16,7 +16,7 @@ window.addEventListener(
16
16
  () => {
17
17
  keyboardActive = true;
18
18
  },
19
- { capture: true }
19
+ { capture: true },
20
20
  );
21
21
 
22
22
  window.addEventListener(
@@ -24,7 +24,7 @@ window.addEventListener(
24
24
  () => {
25
25
  keyboardActive = false;
26
26
  },
27
- { capture: true }
27
+ { capture: true },
28
28
  );
29
29
 
30
30
  /**
@@ -110,5 +110,5 @@ export const FocusMixin = dedupingMixin(
110
110
  _shouldRemoveFocus(_event) {
111
111
  return true;
112
112
  }
113
- }
113
+ },
114
114
  );
package/src/gestures.js CHANGED
@@ -65,7 +65,7 @@ let supportsPassive = false;
65
65
  // eslint-disable-next-line getter-return
66
66
  get() {
67
67
  supportsPassive = true;
68
- }
68
+ },
69
69
  });
70
70
  window.addEventListener('test', null, opts);
71
71
  window.removeEventListener('test', null, opts);
@@ -103,7 +103,7 @@ const canBeDisabled = {
103
103
  optgroup: true,
104
104
  option: true,
105
105
  select: true,
106
- textarea: true
106
+ textarea: true,
107
107
  };
108
108
 
109
109
  /**
@@ -161,14 +161,14 @@ function isSyntheticClick(ev) {
161
161
  const POINTERSTATE = {
162
162
  mouse: {
163
163
  target: null,
164
- mouseIgnoreJob: null
164
+ mouseIgnoreJob: null,
165
165
  },
166
166
  touch: {
167
167
  x: 0,
168
168
  y: 0,
169
169
  id: -1,
170
- scrollDecided: false
171
- }
170
+ scrollDecided: false,
171
+ },
172
172
  };
173
173
 
174
174
  function firstTouchAction(ev) {
@@ -555,13 +555,13 @@ register({
555
555
  deps: ['mousedown', 'touchstart', 'touchend'],
556
556
  flow: {
557
557
  start: ['mousedown', 'touchstart'],
558
- end: ['mouseup', 'touchend']
558
+ end: ['mouseup', 'touchend'],
559
559
  },
560
560
  emits: ['down', 'up'],
561
561
 
562
562
  info: {
563
563
  movefn: null,
564
- upfn: null
564
+ upfn: null,
565
565
  },
566
566
 
567
567
  /**
@@ -616,7 +616,7 @@ register({
616
616
  */
617
617
  touchend: function (e) {
618
618
  downupFire('up', _findOriginalTarget(e), e.changedTouches[0], e);
619
- }
619
+ },
620
620
  });
621
621
 
622
622
  /**
@@ -637,7 +637,7 @@ function downupFire(type, target, event, preventer) {
637
637
  preventer: preventer,
638
638
  prevent: function (e) {
639
639
  return prevent(e);
640
- }
640
+ },
641
641
  });
642
642
  }
643
643
 
@@ -647,7 +647,7 @@ register({
647
647
  deps: ['mousedown', 'touchstart', 'touchmove', 'touchend'],
648
648
  flow: {
649
649
  start: ['mousedown', 'touchstart'],
650
- end: ['mouseup', 'touchend']
650
+ end: ['mouseup', 'touchend'],
651
651
  },
652
652
  emits: ['track'],
653
653
 
@@ -666,7 +666,7 @@ register({
666
666
  },
667
667
  movefn: null,
668
668
  upfn: null,
669
- prevent: false
669
+ prevent: false,
670
670
  },
671
671
 
672
672
  /**
@@ -779,7 +779,7 @@ register({
779
779
  this.info.addMove({ x: ct.clientX, y: ct.clientY });
780
780
  trackFire(this.info, t, ct);
781
781
  }
782
- }
782
+ },
783
783
  });
784
784
 
785
785
  /**
@@ -831,7 +831,7 @@ function trackFire(info, target, touch) {
831
831
  sourceEvent: touch,
832
832
  hover: function () {
833
833
  return deepTargetFind(touch.clientX, touch.clientY);
834
- }
834
+ },
835
835
  });
836
836
  }
837
837
 
@@ -840,13 +840,13 @@ register({
840
840
  deps: ['mousedown', 'click', 'touchstart', 'touchend'],
841
841
  flow: {
842
842
  start: ['mousedown', 'touchstart'],
843
- end: ['click', 'touchend']
843
+ end: ['click', 'touchend'],
844
844
  },
845
845
  emits: ['tap'],
846
846
  info: {
847
847
  x: NaN,
848
848
  y: NaN,
849
- prevent: false
849
+ prevent: false,
850
850
  },
851
851
 
852
852
  /**
@@ -900,7 +900,7 @@ register({
900
900
  */
901
901
  touchend: function (e) {
902
902
  trackForward(this.info, e.changedTouches[0], e);
903
- }
903
+ },
904
904
  });
905
905
 
906
906
  /**
@@ -925,7 +925,7 @@ function trackForward(info, e, preventer) {
925
925
  x: e.clientX,
926
926
  y: e.clientY,
927
927
  sourceEvent: e,
928
- preventer: preventer
928
+ preventer: preventer,
929
929
  });
930
930
  }
931
931
  }
@@ -346,7 +346,7 @@ export const ironList = {
346
346
  // _increasePoolIfNeeded to run away creating items to try to fill it.
347
347
  this._physicalTop = Math.min(
348
348
  Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage,
349
- this._scrollPosition
349
+ this._scrollPosition,
350
350
  );
351
351
  this._update();
352
352
  } else if (this._physicalCount > 0) {
@@ -454,7 +454,7 @@ export const ironList = {
454
454
 
455
455
  _isClientFull: function () {
456
456
  return (
457
- this._scrollBottom != 0 &&
457
+ this._scrollBottom !== 0 &&
458
458
  this._physicalBottom - 1 >= this._scrollBottom &&
459
459
  this._physicalTop <= this._scrollPosition
460
460
  );
@@ -467,7 +467,7 @@ export const ironList = {
467
467
  var nextPhysicalCount = this._clamp(
468
468
  this._physicalCount + count,
469
469
  DEFAULT_PHYSICAL_COUNT,
470
- this._virtualCount - this._virtualStart
470
+ this._virtualCount - this._virtualStart,
471
471
  );
472
472
  nextPhysicalCount = this._convertIndexToCompleteRow(nextPhysicalCount);
473
473
  if (this.grid) {
@@ -520,7 +520,7 @@ export const ironList = {
520
520
  this._debounce(
521
521
  '_increasePoolIfNeeded',
522
522
  this._increasePoolIfNeeded.bind(this, this._clamp(Math.round(50 / this._templateCost), 1, nextIncrease)),
523
- idlePeriod
523
+ idlePeriod,
524
524
  );
525
525
  }
526
526
  },
@@ -553,7 +553,9 @@ export const ironList = {
553
553
  }
554
554
  this.notifyResize();
555
555
  flush();
556
- newGrid && this._updateGridMetrics();
556
+ if (newGrid) {
557
+ this._updateGridMetrics();
558
+ }
557
559
  },
558
560
 
559
561
  /**
@@ -581,7 +583,7 @@ export const ironList = {
581
583
  this._adjustVirtualIndex(change.value.indexSplices);
582
584
  this._virtualCount = this.items ? this.items.length : 0;
583
585
  // Only blur if at least one item is added or removed.
584
- var itemAddedOrRemoved = change.value.indexSplices.some(function (splice) {
586
+ var itemAddedOrRemoved = change.value.indexSplices.some((splice) => {
585
587
  return splice.addedCount > 0 || splice.removed.length > 0;
586
588
  });
587
589
  if (itemAddedOrRemoved) {
@@ -593,9 +595,9 @@ export const ironList = {
593
595
  }
594
596
  }
595
597
  // Render only if the affected index is rendered.
596
- var affectedIndexRendered = change.value.indexSplices.some(function (splice) {
598
+ var affectedIndexRendered = change.value.indexSplices.some((splice) => {
597
599
  return splice.index + splice.addedCount >= this._virtualStart && splice.index <= this._virtualEnd;
598
- }, this);
600
+ });
599
601
  if (!this._isClientFull() || affectedIndexRendered) {
600
602
  this._debounce('_render', this._render, animationFrame);
601
603
  }
@@ -689,7 +691,7 @@ export const ironList = {
689
691
  // Update the average if it measured something.
690
692
  if (this._physicalAverageCount !== prevAvgCount) {
691
693
  this._physicalAverage = Math.round(
692
- (prevPhysicalAvg * prevAvgCount + newPhysicalSize) / this._physicalAverageCount
694
+ (prevPhysicalAvg * prevAvgCount + newPhysicalSize) / this._physicalAverageCount,
693
695
  );
694
696
  }
695
697
  },
@@ -718,7 +720,7 @@ export const ironList = {
718
720
  if (this._isRTL) {
719
721
  x *= -1;
720
722
  }
721
- this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]);
723
+ this.translate3d(`${x}px`, `${y}px`, 0, this._physicalItems[pidx]);
722
724
  if (this._shouldRenderNextRow(vidx)) {
723
725
  y += this._rowHeight;
724
726
  }
@@ -728,7 +730,7 @@ export const ironList = {
728
730
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
729
731
  this._iterateItems((pidx, vidx) => {
730
732
  const item = this._physicalItems[pidx];
731
- this.translate3d(0, y + 'px', 0, item);
733
+ this.translate3d(0, `${y}px`, 0, item);
732
734
  y += this._physicalSizes[pidx];
733
735
  const itemId = item.id;
734
736
  if (itemId) {
@@ -809,7 +811,7 @@ export const ironList = {
809
811
  forceUpdate = forceUpdate || (this.grid && this.$.items.style.height < this._estScrollHeight);
810
812
  // Amortize height adjustment, so it won't trigger large repaints too often.
811
813
  if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._viewportHeight) {
812
- this.$.items.style.height = this._estScrollHeight + 'px';
814
+ this.$.items.style.height = `${this._estScrollHeight}px`;
813
815
  this._scrollHeight = this._estScrollHeight;
814
816
  }
815
817
  },
@@ -890,7 +892,7 @@ export const ironList = {
890
892
  this.toggleScrollListener(false);
891
893
  }
892
894
  },
893
- animationFrame
895
+ animationFrame,
894
896
  );
895
897
  },
896
898
 
@@ -949,5 +951,5 @@ export const ironList = {
949
951
  this._debouncers = this._debouncers || {};
950
952
  this._debouncers[name] = Debouncer.debounce(this._debouncers[name], asyncModule, cb.bind(this));
951
953
  enqueueDebouncer(this._debouncers[name]);
952
- }
954
+ },
953
955
  };
@@ -49,5 +49,5 @@ export const KeyboardMixin = dedupingMixin(
49
49
  _onKeyUp(_event) {
50
50
  // To be implemented.
51
51
  }
52
- }
52
+ },
53
53
  );
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { Constructor } from '@open-wc/dedupe-mixin';
7
+ import { LitElement } from 'lit';
8
+
9
+ export declare function PolylitMixin<T extends Constructor<LitElement>>(base: T): T & Constructor<PolylitMixinClass>;
10
+
11
+ export declare class PolylitMixinClass {
12
+ ready(): void;
13
+
14
+ /**
15
+ * Reads a value from a path.
16
+ */
17
+ protected _get(root: Object, path: String): any;
18
+
19
+ /**
20
+ * Sets a value to a path.
21
+ */
22
+ protected _set(root: Object, path: String, value: any): void;
23
+ }
@@ -0,0 +1,266 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
7
+
8
+ const caseMap = {};
9
+
10
+ const CAMEL_TO_DASH = /([A-Z])/g;
11
+
12
+ function camelToDash(camel) {
13
+ return caseMap[camel] || (caseMap[camel] = camel.replace(CAMEL_TO_DASH, '-$1').toLowerCase());
14
+ }
15
+
16
+ function upper(name) {
17
+ return name[0].toUpperCase() + name.substring(1);
18
+ }
19
+
20
+ function parseObserver(observerString) {
21
+ const [method, rest] = observerString.split('(');
22
+ const observerProps = rest
23
+ .replace(')', '')
24
+ .split(',')
25
+ .map((prop) => prop.trim());
26
+
27
+ return {
28
+ method,
29
+ observerProps,
30
+ };
31
+ }
32
+
33
+ function getOrCreateMap(obj, name) {
34
+ if (!Object.prototype.hasOwnProperty.call(obj, name)) {
35
+ // clone any existing entries (superclasses)
36
+ obj[name] = new Map(obj[name]);
37
+ }
38
+ return obj[name];
39
+ }
40
+
41
+ const PolylitMixinImplementation = (superclass) => {
42
+ class PolylitMixinClass extends superclass {
43
+ static createProperty(name, options) {
44
+ if ([String, Boolean, Number, Array].includes(options)) {
45
+ options = {
46
+ type: options,
47
+ };
48
+ }
49
+
50
+ if (options.reflectToAttribute) {
51
+ options.reflect = true;
52
+ }
53
+
54
+ super.createProperty(name, options);
55
+ }
56
+
57
+ static getOrCreateMap(name) {
58
+ return getOrCreateMap(this, name);
59
+ }
60
+
61
+ /**
62
+ * @protected
63
+ * @override
64
+ */
65
+ static finalize() {
66
+ super.finalize();
67
+
68
+ if (Array.isArray(this.observers)) {
69
+ const complexObservers = this.getOrCreateMap('__complexObservers');
70
+
71
+ this.observers.forEach((observer) => {
72
+ const { method, observerProps } = parseObserver(observer);
73
+ complexObservers.set(method, observerProps);
74
+ });
75
+ }
76
+ }
77
+
78
+ static addCheckedInitializer(initializer) {
79
+ super.addInitializer((instance) => {
80
+ // Prevent initializer from affecting superclass
81
+ if (instance instanceof this) {
82
+ initializer(instance);
83
+ }
84
+ });
85
+ }
86
+
87
+ static getPropertyDescriptor(name, key, options) {
88
+ const defaultDescriptor = super.getPropertyDescriptor(name, key, options);
89
+
90
+ let result = defaultDescriptor;
91
+
92
+ if ('value' in options) {
93
+ // Set the default value
94
+ this.addCheckedInitializer((instance) => {
95
+ if (typeof options.value === 'function') {
96
+ instance[name] = options.value.call(instance);
97
+ } else {
98
+ instance[name] = options.value;
99
+ }
100
+ });
101
+ }
102
+
103
+ if (options.readOnly) {
104
+ const setter = defaultDescriptor.set;
105
+
106
+ this.addCheckedInitializer((instance) => {
107
+ // This is run during construction of the element
108
+ instance[`_set${upper(name)}`] = function (value) {
109
+ setter.call(instance, value);
110
+ };
111
+ });
112
+
113
+ result = {
114
+ get: defaultDescriptor.get,
115
+ set() {
116
+ // Do nothing, property is read-only.
117
+ },
118
+ configurable: true,
119
+ enumerable: true,
120
+ };
121
+ }
122
+
123
+ if (options.observer) {
124
+ const method = options.observer;
125
+
126
+ // set this method
127
+ this.getOrCreateMap('__observers').set(name, method);
128
+
129
+ this.addCheckedInitializer((instance) => {
130
+ if (!instance[method]) {
131
+ console.warn(`observer method ${method} not defined`);
132
+ }
133
+ });
134
+ }
135
+
136
+ if (options.notify) {
137
+ if (!this.__notifyProps) {
138
+ this.__notifyProps = new Set();
139
+ // eslint-disable-next-line no-prototype-builtins
140
+ } else if (!this.hasOwnProperty('__notifyProps')) {
141
+ // clone any existing observers (superclasses)
142
+ const notifyProps = this.__notifyProps;
143
+ this.__notifyProps = new Set(notifyProps);
144
+ }
145
+
146
+ // set this method
147
+ this.__notifyProps.add(name);
148
+ }
149
+
150
+ if (options.computed) {
151
+ const assignComputedMethod = `__assignComputed${name}`;
152
+ const observer = parseObserver(options.computed);
153
+ this.prototype[assignComputedMethod] = function (...props) {
154
+ this[name] = this[observer.method](...props);
155
+ };
156
+
157
+ this.getOrCreateMap('__complexObservers').set(assignComputedMethod, observer.observerProps);
158
+ }
159
+
160
+ if (!options.attribute) {
161
+ options.attribute = camelToDash(name);
162
+ }
163
+
164
+ return result;
165
+ }
166
+
167
+ /** @protected */
168
+ ready() {
169
+ if (super.ready) {
170
+ super.ready();
171
+ }
172
+ this.$ = this.$ || {};
173
+ this.shadowRoot.querySelectorAll('[id]').forEach((node) => {
174
+ this.$[node.id] = node;
175
+ });
176
+ }
177
+
178
+ /** @protected */
179
+ firstUpdated() {
180
+ super.firstUpdated();
181
+
182
+ this.ready();
183
+ }
184
+
185
+ /** @protected */
186
+ updated(props) {
187
+ if (this.constructor.__observers) {
188
+ this.__runObservers(props, this.constructor.__observers);
189
+ }
190
+
191
+ if (this.constructor.__complexObservers) {
192
+ this.__runComplexObservers(props, this.constructor.__complexObservers);
193
+ }
194
+
195
+ if (this.__dynamicObservers) {
196
+ this.__runComplexObservers(props, this.__dynamicObservers);
197
+ }
198
+
199
+ if (this.constructor.__notifyProps) {
200
+ this.__runNotifyProps(props, this.constructor.__notifyProps);
201
+ }
202
+ }
203
+
204
+ /** @protected */
205
+ _createMethodObserver(observer) {
206
+ const dynamicObservers = getOrCreateMap(this, '__dynamicObservers');
207
+ const { method, observerProps } = parseObserver(observer);
208
+ dynamicObservers.set(method, observerProps);
209
+ }
210
+
211
+ /** @private */
212
+ __runComplexObservers(props, observers) {
213
+ observers.forEach((observerProps, method) => {
214
+ if (observerProps.some((prop) => props.has(prop))) {
215
+ if (!this[method]) {
216
+ console.warn(`observer method ${method} not defined`);
217
+ } else {
218
+ this[method](...observerProps.map((prop) => this[prop]));
219
+ }
220
+ }
221
+ });
222
+ }
223
+
224
+ /** @private */
225
+ __runObservers(props, observers) {
226
+ props.forEach((v, k) => {
227
+ const observer = observers.get(k);
228
+ if (observer !== undefined && this[observer]) {
229
+ this[observer](this[k], v);
230
+ }
231
+ });
232
+ }
233
+
234
+ /** @private */
235
+ __runNotifyProps(props, notifyProps) {
236
+ props.forEach((_, k) => {
237
+ if (notifyProps.has(k)) {
238
+ this.dispatchEvent(
239
+ new CustomEvent(`${camelToDash(k)}-changed`, {
240
+ detail: {
241
+ value: this[k],
242
+ },
243
+ }),
244
+ );
245
+ }
246
+ });
247
+ }
248
+
249
+ /** @protected */
250
+ _get(path, object) {
251
+ return path.split('.').reduce((obj, property) => (obj ? obj[property] : undefined), object);
252
+ }
253
+
254
+ /** @protected */
255
+ _set(path, value, object) {
256
+ const pathParts = path.split('.');
257
+ const lastPart = pathParts.pop();
258
+ const target = pathParts.reduce((target, part) => target[part], object);
259
+ target[lastPart] = value;
260
+ }
261
+ }
262
+
263
+ return PolylitMixinClass;
264
+ };
265
+
266
+ export const PolylitMixin = dedupeMixin(PolylitMixinImplementation);
@@ -49,8 +49,8 @@ export const ResizeMixin = dedupingMixin(
49
49
  */
50
50
  notifyResize() {
51
51
  console.warn(
52
- `WARNING: Since Vaadin 23, notifyResize() is deprecated. The component uses a ResizeObserver internally and doesn't need to be explicitly notified of resizes.`
52
+ `WARNING: Since Vaadin 23, notifyResize() is deprecated. The component uses a ResizeObserver internally and doesn't need to be explicitly notified of resizes.`,
53
53
  );
54
54
  }
55
- }
55
+ },
56
56
  );
@@ -10,7 +10,7 @@ export class SlotController extends EventTarget implements ReactiveController {
10
10
  host: HTMLElement,
11
11
  slotName: string,
12
12
  slotFactory?: () => HTMLElement,
13
- slotInitializer?: (host: HTMLElement, node: HTMLElement) => void
13
+ slotInitializer?: (host: HTMLElement, node: HTMLElement) => void,
14
14
  );
15
15
 
16
16
  hostConnected(): void;
package/src/slot-mixin.js CHANGED
@@ -56,5 +56,5 @@ export const SlotMixin = dedupingMixin(
56
56
  );
57
57
  });
58
58
  }
59
- }
59
+ },
60
60
  );
@@ -9,13 +9,11 @@ import { DisabledMixinClass } from './disabled-mixin.js';
9
9
  /**
10
10
  * A mixin to toggle the `tabindex` attribute.
11
11
  *
12
- * By default, the attribute is set to 0 that makes the element focusable.
13
- *
14
12
  * The attribute is set to -1 whenever the user disables the element
15
13
  * and restored with the last known value once the element is enabled.
16
14
  */
17
15
  export declare function TabindexMixin<T extends Constructor<HTMLElement>>(
18
- base: T
16
+ base: T,
19
17
  ): T & Constructor<DisabledMixinClass> & Constructor<TabindexMixinClass>;
20
18
 
21
19
  export declare class TabindexMixinClass {
@@ -24,6 +22,11 @@ export declare class TabindexMixinClass {
24
22
  */
25
23
  tabindex: number | undefined | null;
26
24
 
25
+ /**
26
+ * Stores the last known tabindex since the element has been disabled.
27
+ */
28
+ protected _lastTabIndex: number | undefined | null;
29
+
27
30
  /**
28
31
  * When the user has changed tabindex while the element is disabled,
29
32
  * the observer reverts tabindex to -1 and rather saves the new tabindex value to apply it later.
@@ -8,8 +8,6 @@ import { DisabledMixin } from './disabled-mixin.js';
8
8
  /**
9
9
  * A mixin to toggle the `tabindex` attribute.
10
10
  *
11
- * By default, the attribute is set to 0 that makes the element focusable.
12
- *
13
11
  * The attribute is set to -1 whenever the user disables the element
14
12
  * and restored with the last known value once the element is enabled.
15
13
  *
@@ -22,24 +20,23 @@ export const TabindexMixin = (superclass) =>
22
20
  return {
23
21
  /**
24
22
  * Indicates whether the element can be focused and where it participates in sequential keyboard navigation.
23
+ *
25
24
  * @protected
26
25
  */
27
26
  tabindex: {
28
27
  type: Number,
29
- value: 0,
30
28
  reflectToAttribute: true,
31
- observer: '_tabindexChanged'
29
+ observer: '_tabindexChanged',
32
30
  },
33
31
 
34
32
  /**
35
33
  * Stores the last known tabindex since the element has been disabled.
36
34
  *
37
- * @private
35
+ * @protected
38
36
  */
39
- __lastTabIndex: {
37
+ _lastTabIndex: {
40
38
  type: Number,
41
- value: 0
42
- }
39
+ },
43
40
  };
44
41
  }
45
42
 
@@ -57,11 +54,11 @@ export const TabindexMixin = (superclass) =>
57
54
 
58
55
  if (disabled) {
59
56
  if (this.tabindex !== undefined) {
60
- this.__lastTabIndex = this.tabindex;
57
+ this._lastTabIndex = this.tabindex;
61
58
  }
62
59
  this.tabindex = -1;
63
60
  } else if (oldDisabled) {
64
- this.tabindex = this.__lastTabIndex;
61
+ this.tabindex = this._lastTabIndex;
65
62
  }
66
63
  }
67
64
 
@@ -74,7 +71,7 @@ export const TabindexMixin = (superclass) =>
74
71
  */
75
72
  _tabindexChanged(tabindex) {
76
73
  if (this.disabled && tabindex !== -1) {
77
- this.__lastTabIndex = tabindex;
74
+ this._lastTabIndex = tabindex;
78
75
  this.tabindex = -1;
79
76
  }
80
77
  }
package/src/templates.js CHANGED
@@ -18,7 +18,7 @@ export function processTemplates(component) {
18
18
 
19
19
  if (component.querySelector('template')) {
20
20
  console.warn(
21
- `WARNING: <template> inside <${component.localName}> is no longer supported. Import @vaadin/polymer-legacy-adapter/template-renderer.js to enable compatibility.`
21
+ `WARNING: <template> inside <${component.localName}> is no longer supported. Import @vaadin/polymer-legacy-adapter/template-renderer.js to enable compatibility.`,
22
22
  );
23
23
  }
24
24
  }
@@ -28,7 +28,7 @@ export class IronListAdapter {
28
28
 
29
29
  this.timeouts = {
30
30
  SCROLL_REORDER: 500,
31
- IGNORE_WHEEL: 500
31
+ IGNORE_WHEEL: 500,
32
32
  };
33
33
 
34
34
  this.__resizeObserver = new ResizeObserver(() => this._resizeHandler());
@@ -118,8 +118,12 @@ export class IronListAdapter {
118
118
  this._resizeHandler();
119
119
  flush();
120
120
  this._scrollHandler();
121
- this.__scrollReorderDebouncer && this.__scrollReorderDebouncer.flush();
122
- this.__debouncerWheelAnimationFrame && this.__debouncerWheelAnimationFrame.flush();
121
+ if (this.__scrollReorderDebouncer) {
122
+ this.__scrollReorderDebouncer.flush();
123
+ }
124
+ if (this.__debouncerWheelAnimationFrame) {
125
+ this.__debouncerWheelAnimationFrame.flush();
126
+ }
123
127
  }
124
128
 
125
129
  update(startIndex = 0, endIndex = this.size - 1) {
@@ -183,7 +187,7 @@ export class IronListAdapter {
183
187
  flush();
184
188
 
185
189
  this._itemsChanged({
186
- path: 'items'
190
+ path: 'items',
187
191
  });
188
192
  flush();
189
193
 
@@ -221,7 +225,7 @@ export class IronListAdapter {
221
225
  /** @private */
222
226
  get items() {
223
227
  return {
224
- length: Math.min(this.size, MAX_VIRTUAL_COUNT)
228
+ length: Math.min(this.size, MAX_VIRTUAL_COUNT),
225
229
  };
226
230
  }
227
231
 
@@ -233,7 +237,7 @@ export class IronListAdapter {
233
237
  /** @private */
234
238
  get $() {
235
239
  return {
236
- items: this.scrollContainer
240
+ items: this.scrollContainer,
237
241
  };
238
242
  }
239
243
 
@@ -245,7 +249,9 @@ export class IronListAdapter {
245
249
  this._viewportWidth = this.elementsContainer.offsetWidth;
246
250
  this._viewportHeight = this.scrollTarget.offsetHeight;
247
251
  this._scrollPageHeight = this._viewportHeight - this._scrollLineHeight;
248
- this.grid && this._updateGridMetrics();
252
+ if (this.grid) {
253
+ this._updateGridMetrics();
254
+ }
249
255
  }
250
256
 
251
257
  /** @private */
@@ -302,7 +308,7 @@ export class IronListAdapter {
302
308
  this.__scrollReorderDebouncer = Debouncer.debounce(
303
309
  this.__scrollReorderDebouncer,
304
310
  timeOut.after(this.timeouts.SCROLL_REORDER),
305
- () => this.__reorderElements()
311
+ () => this.__reorderElements(),
306
312
  );
307
313
  }
308
314
 
@@ -340,7 +346,7 @@ export class IronListAdapter {
340
346
  this.__debouncerWheelAnimationFrame = Debouncer.debounce(
341
347
  this.__debouncerWheelAnimationFrame,
342
348
  animationFrame,
343
- () => (this._wheelAnimationFrame = false)
349
+ () => (this._wheelAnimationFrame = false),
344
350
  );
345
351
 
346
352
  const momentum = Math.abs(e.deltaX) + Math.abs(deltaY);
@@ -356,7 +362,7 @@ export class IronListAdapter {
356
362
  this._debouncerIgnoreNewWheel = Debouncer.debounce(
357
363
  this._debouncerIgnoreNewWheel,
358
364
  timeOut.after(this.timeouts.IGNORE_WHEEL),
359
- () => (this._ignoreNewWheel = false)
365
+ () => (this._ignoreNewWheel = false),
360
366
  );
361
367
  } else if ((this._hasResidualMomentum && momentum <= this._previousMomentum) || this._ignoreNewWheel) {
362
368
  e.preventDefault();
@@ -427,7 +433,7 @@ export class IronListAdapter {
427
433
  const elementWithFocus = visibleElements.find(
428
434
  (element) =>
429
435
  element.contains(this.elementsContainer.getRootNode().activeElement) ||
430
- element.contains(this.scrollTarget.getRootNode().activeElement)
436
+ element.contains(this.scrollTarget.getRootNode().activeElement),
431
437
  );
432
438
  const targetElement = elementWithFocus || visibleElements[0];
433
439
  if (!targetElement) {