@vaadin/component-base 25.0.0-alpha2 → 25.0.0-alpha21

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": "25.0.0-alpha2",
3
+ "version": "25.0.0-alpha21",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,8 +23,7 @@
23
23
  "custom_typings",
24
24
  "index.d.ts",
25
25
  "index.js",
26
- "src",
27
- "!src/style-props.js"
26
+ "src"
28
27
  ],
29
28
  "keywords": [
30
29
  "Vaadin",
@@ -34,14 +33,15 @@
34
33
  "dependencies": {
35
34
  "@open-wc/dedupe-mixin": "^1.3.0",
36
35
  "@vaadin/vaadin-development-mode-detector": "^2.0.0",
36
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha21",
37
37
  "@vaadin/vaadin-usage-statistics": "^2.1.0",
38
38
  "lit": "^3.0.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@vaadin/chai-plugins": "25.0.0-alpha2",
42
- "@vaadin/test-runner-commands": "25.0.0-alpha2",
41
+ "@vaadin/chai-plugins": "25.0.0-alpha21",
42
+ "@vaadin/test-runner-commands": "25.0.0-alpha21",
43
43
  "@vaadin/testing-helpers": "^2.0.0",
44
- "sinon": "^18.0.0"
44
+ "sinon": "^21.0.0"
45
45
  },
46
- "gitHead": "67ffcd5355cf21ce1b5039c598525109fc4c164b"
46
+ "gitHead": "8fb9e9710c01449edf623a1aaac4655cdc11a933"
47
47
  }
@@ -33,6 +33,3 @@ export const isTouch = (() => {
33
33
  return false;
34
34
  }
35
35
  })();
36
-
37
- export const supportsAdoptingStyleSheets =
38
- window.ShadowRoot && 'adoptedStyleSheets' in Document.prototype && 'replace' in CSSStyleSheet.prototype;
@@ -58,14 +58,6 @@ export class Cache<TItem> {
58
58
  */
59
59
  get flatSize(): number;
60
60
 
61
- /**
62
- * The total number of items, including items from expanded sub-caches.
63
- *
64
- * @protected
65
- * @deprecated since 24.3 and will be removed in Vaadin 25.
66
- */
67
- get effectiveSize(): number;
68
-
69
61
  constructor(
70
62
  context: CacheContext<TItem>,
71
63
  pageSize: number,
@@ -113,34 +105,4 @@ export class Cache<TItem> {
113
105
  * of an item in the `items` array.
114
106
  */
115
107
  getFlatIndex(index: number): number;
116
-
117
- /**
118
- * @deprecated since 24.3 and will be removed in Vaadin 25.
119
- */
120
- getItemForIndex(index: number): TItem | undefined;
121
-
122
- /**
123
- * @deprecated since 24.3 and will be removed in Vaadin 25.
124
- */
125
- getCacheAndIndex(index: number): { cache: Cache<TItem>; scaledIndex: number };
126
-
127
- /**
128
- * @deprecated since 24.3 and will be removed in Vaadin 25.
129
- */
130
- updateSize(): void;
131
-
132
- /**
133
- * @deprecated since 24.3 and will be removed in Vaadin 25.
134
- */
135
- ensureSubCacheForScaledIndex(scaledIndex: number): void;
136
-
137
- /**
138
- * @deprecated since 24.3 and will be removed in Vaadin 25.
139
- */
140
- get grid(): HTMLElement;
141
-
142
- /**
143
- * @deprecated since 24.3 and will be removed in Vaadin 25.
144
- */
145
- get itemCaches(): object;
146
108
  }
@@ -3,7 +3,6 @@
3
3
  * Copyright (c) 2021 - 2025 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { getFlatIndexContext } from './helpers.js';
7
6
 
8
7
  /**
9
8
  * A class that stores items with their associated sub-caches.
@@ -49,7 +48,7 @@ export class Cache {
49
48
  * @type {Record<number, Cache>}
50
49
  * @private
51
50
  */
52
- __subCacheByIndex = {};
51
+ #subCacheByIndex = {};
53
52
 
54
53
  /**
55
54
  * The number of items.
@@ -57,7 +56,7 @@ export class Cache {
57
56
  * @type {number}
58
57
  * @private
59
58
  */
60
- __size = 0;
59
+ #size = 0;
61
60
 
62
61
  /**
63
62
  * The total number of items, including items from expanded sub-caches.
@@ -65,7 +64,7 @@ export class Cache {
65
64
  * @type {number}
66
65
  * @private
67
66
  */
68
- __flatSize = 0;
67
+ #flatSize = 0;
69
68
 
70
69
  /**
71
70
  * @param {Cache['context']} context
@@ -80,7 +79,7 @@ export class Cache {
80
79
  this.size = size;
81
80
  this.parentCache = parentCache;
82
81
  this.parentCacheIndex = parentCacheIndex;
83
- this.__flatSize = size || 0;
82
+ this.#flatSize = size || 0;
84
83
  }
85
84
 
86
85
  /**
@@ -99,7 +98,7 @@ export class Cache {
99
98
  * @return {Cache[]}
100
99
  */
101
100
  get subCaches() {
102
- return Object.values(this.__subCacheByIndex);
101
+ return Object.values(this.#subCacheByIndex);
103
102
  }
104
103
 
105
104
  /**
@@ -121,20 +120,7 @@ export class Cache {
121
120
  * @return {number}
122
121
  */
123
122
  get flatSize() {
124
- return this.__flatSize;
125
- }
126
-
127
- /**
128
- * The total number of items, including items from expanded sub-caches.
129
- *
130
- * @protected
131
- * @deprecated since 24.3 and will be removed in Vaadin 25.
132
- */
133
- get effectiveSize() {
134
- console.warn(
135
- '<vaadin-grid> The `effectiveSize` property of ItemCache is deprecated and will be removed in Vaadin 25.',
136
- );
137
- return this.flatSize;
123
+ return this.#flatSize;
138
124
  }
139
125
 
140
126
  /**
@@ -143,7 +129,7 @@ export class Cache {
143
129
  * @return {number}
144
130
  */
145
131
  get size() {
146
- return this.__size;
132
+ return this.#size;
147
133
  }
148
134
 
149
135
  /**
@@ -152,12 +138,12 @@ export class Cache {
152
138
  * @param {number} size
153
139
  */
154
140
  set size(size) {
155
- const oldSize = this.__size;
141
+ const oldSize = this.#size;
156
142
  if (oldSize === size) {
157
143
  return;
158
144
  }
159
145
 
160
- this.__size = size;
146
+ this.#size = size;
161
147
 
162
148
  if (this.context.placeholder !== undefined) {
163
149
  this.items.length = size || 0;
@@ -166,6 +152,10 @@ export class Cache {
166
152
  }
167
153
  }
168
154
 
155
+ if (this.items.length > size) {
156
+ this.items.length = size || 0;
157
+ }
158
+
169
159
  Object.keys(this.pendingRequests).forEach((page) => {
170
160
  const startIndex = parseInt(page) * this.pageSize;
171
161
  if (startIndex >= this.size || 0) {
@@ -178,7 +168,7 @@ export class Cache {
178
168
  * Recalculates the flattened size for the cache and its descendant caches recursively.
179
169
  */
180
170
  recalculateFlatSize() {
181
- this.__flatSize =
171
+ this.#flatSize =
182
172
  !this.parentItem || this.context.isExpanded(this.parentItem)
183
173
  ? this.size +
184
174
  this.subCaches.reduce((total, subCache) => {
@@ -213,7 +203,7 @@ export class Cache {
213
203
  * @return {Cache | undefined}
214
204
  */
215
205
  getSubCache(index) {
216
- return this.__subCacheByIndex[index];
206
+ return this.#subCacheByIndex[index];
217
207
  }
218
208
 
219
209
  /**
@@ -223,14 +213,14 @@ export class Cache {
223
213
  * @param {number} index
224
214
  */
225
215
  removeSubCache(index) {
226
- delete this.__subCacheByIndex[index];
216
+ delete this.#subCacheByIndex[index];
227
217
  }
228
218
 
229
219
  /**
230
220
  * Removes all sub-caches.
231
221
  */
232
222
  removeSubCaches() {
233
- this.__subCacheByIndex = {};
223
+ this.#subCacheByIndex = {};
234
224
  }
235
225
 
236
226
  /**
@@ -242,7 +232,7 @@ export class Cache {
242
232
  */
243
233
  createSubCache(index) {
244
234
  const subCache = new Cache(this.context, this.pageSize, 0, this, index);
245
- this.__subCacheByIndex[index] = subCache;
235
+ this.#subCacheByIndex[index] = subCache;
246
236
  return subCache;
247
237
  }
248
238
 
@@ -261,66 +251,4 @@ export class Cache {
261
251
  return clampedIndex > index ? prev + subCache.flatSize : prev;
262
252
  }, clampedIndex);
263
253
  }
264
-
265
- /**
266
- * @deprecated since 24.3 and will be removed in Vaadin 25.
267
- */
268
- getItemForIndex(index) {
269
- console.warn(
270
- '<vaadin-grid> The `getItemForIndex` method of ItemCache is deprecated and will be removed in Vaadin 25.',
271
- );
272
- const { item } = getFlatIndexContext(this, index);
273
- return item;
274
- }
275
-
276
- /**
277
- * @deprecated since 24.3 and will be removed in Vaadin 25.
278
- */
279
- getCacheAndIndex(index) {
280
- console.warn(
281
- '<vaadin-grid> The `getCacheAndIndex` method of ItemCache is deprecated and will be removed in Vaadin 25.',
282
- );
283
- const { cache, index: scaledIndex } = getFlatIndexContext(this, index);
284
- return { cache, scaledIndex };
285
- }
286
-
287
- /**
288
- * @deprecated since 24.3 and will be removed in Vaadin 25.
289
- */
290
- updateSize() {
291
- console.warn('<vaadin-grid> The `updateSize` method of ItemCache is deprecated and will be removed in Vaadin 25.');
292
- this.recalculateFlatSize();
293
- }
294
-
295
- /**
296
- * @deprecated since 24.3 and will be removed in Vaadin 25.
297
- */
298
- ensureSubCacheForScaledIndex(scaledIndex) {
299
- console.warn(
300
- '<vaadin-grid> The `ensureSubCacheForScaledIndex` method of ItemCache is deprecated and will be removed in Vaadin 25.',
301
- );
302
-
303
- if (!this.getSubCache(scaledIndex)) {
304
- const subCache = this.createSubCache(scaledIndex);
305
- this.context.__controller.__loadCachePage(subCache, 0);
306
- }
307
- }
308
-
309
- /**
310
- * @deprecated since 24.3 and will be removed in Vaadin 25.
311
- */
312
- get grid() {
313
- console.warn('<vaadin-grid> The `grid` property of ItemCache is deprecated and will be removed in Vaadin 25.');
314
- return this.context.__controller.host;
315
- }
316
-
317
- /**
318
- * @deprecated since 24.3 and will be removed in Vaadin 25.
319
- */
320
- get itemCaches() {
321
- console.warn(
322
- '<vaadin-grid> The `itemCaches` property of ItemCache is deprecated and will be removed in Vaadin 25.',
323
- );
324
- return this.__subCacheByIndex;
325
- }
326
254
  }
@@ -85,7 +85,7 @@ export class DataProviderController extends EventTarget {
85
85
  this.isPlaceholder = isPlaceholder;
86
86
  this.dataProvider = dataProvider;
87
87
  this.dataProviderParams = dataProviderParams;
88
- this.rootCache = this.__createRootCache(size);
88
+ this.rootCache = this.#createRootCache(size);
89
89
  }
90
90
 
91
91
  /**
@@ -96,12 +96,10 @@ export class DataProviderController extends EventTarget {
96
96
  }
97
97
 
98
98
  /** @private */
99
- get __cacheContext() {
99
+ get #cacheContext() {
100
100
  return {
101
101
  isExpanded: this.isExpanded,
102
102
  placeholder: this.placeholder,
103
- // The controller instance is needed to ensure deprecated cache methods work.
104
- __controller: this,
105
103
  };
106
104
  }
107
105
 
@@ -145,7 +143,7 @@ export class DataProviderController extends EventTarget {
145
143
  * Clears the cache.
146
144
  */
147
145
  clearCache() {
148
- this.rootCache = this.__createRootCache(this.rootCache.size);
146
+ this.rootCache = this.#createRootCache(this.rootCache.size);
149
147
  }
150
148
 
151
149
  /**
@@ -200,8 +198,8 @@ export class DataProviderController extends EventTarget {
200
198
  ensureFlatIndexLoaded(flatIndex) {
201
199
  const { cache, page, item } = this.getFlatIndexContext(flatIndex);
202
200
 
203
- if (!this.__isItemLoaded(item)) {
204
- this.__loadCachePage(cache, page);
201
+ if (!this.#isItemLoaded(item)) {
202
+ this.#loadCachePage(cache, page);
205
203
  }
206
204
  }
207
205
 
@@ -215,9 +213,9 @@ export class DataProviderController extends EventTarget {
215
213
  ensureFlatIndexHierarchy(flatIndex) {
216
214
  const { cache, item, index } = this.getFlatIndexContext(flatIndex);
217
215
 
218
- if (this.__isItemLoaded(item) && this.isExpanded(item) && !cache.getSubCache(index)) {
216
+ if (this.#isItemLoaded(item) && this.isExpanded(item) && !cache.getSubCache(index)) {
219
217
  const subCache = cache.createSubCache(index);
220
- this.__loadCachePage(subCache, 0);
218
+ this.#loadCachePage(subCache, 0);
221
219
  }
222
220
  }
223
221
 
@@ -225,17 +223,28 @@ export class DataProviderController extends EventTarget {
225
223
  * Loads the first page into the root cache.
226
224
  */
227
225
  loadFirstPage() {
228
- this.__loadCachePage(this.rootCache, 0);
226
+ this.#loadCachePage(this.rootCache, 0);
227
+ }
228
+
229
+ /**
230
+ * Override to prevent loading of the cache page under certain conditions.
231
+ *
232
+ * @param {Cache} cache
233
+ * @param {number} page
234
+ * @protected
235
+ */
236
+ _shouldLoadCachePage(_cache, _page) {
237
+ return true;
229
238
  }
230
239
 
231
240
  /** @private */
232
- __createRootCache(size) {
233
- return new Cache(this.__cacheContext, this.pageSize, size);
241
+ #createRootCache(size) {
242
+ return new Cache(this.#cacheContext, this.pageSize, size);
234
243
  }
235
244
 
236
245
  /** @private */
237
- __loadCachePage(cache, page) {
238
- if (!this.dataProvider || cache.pendingRequests[page]) {
246
+ #loadCachePage(cache, page) {
247
+ if (!this.dataProvider || cache.pendingRequests[page] || !this._shouldLoadCachePage(cache, page)) {
239
248
  return;
240
249
  }
241
250
 
@@ -279,7 +288,7 @@ export class DataProviderController extends EventTarget {
279
288
  }
280
289
 
281
290
  /** @private */
282
- __isItemLoaded(item) {
291
+ #isItemLoaded(item) {
283
292
  if (this.isPlaceholder) {
284
293
  return !this.isPlaceholder(item);
285
294
  } else if (this.placeholder) {
@@ -18,6 +18,7 @@
18
18
  *
19
19
  * @param {Cache} cache
20
20
  * @param {number} flatIndex
21
+ * @param {number} level
21
22
  */
22
23
  export function getFlatIndexContext(cache, flatIndex, level = 0) {
23
24
  let levelIndex = flatIndex;
@@ -53,7 +54,6 @@ export function getFlatIndexContext(cache, flatIndex, level = 0) {
53
54
  *
54
55
  * If the item isn't found, the method returns undefined.
55
56
  *
56
- * @param {Cache} cache
57
57
  * @param {{ getItemId: (item: unknown) => unknown}} context
58
58
  * @param {Cache} cache
59
59
  * @param {unknown} targetItem
package/src/define.js CHANGED
@@ -13,7 +13,7 @@ function dashToCamelCase(dash) {
13
13
 
14
14
  const experimentalMap = {};
15
15
 
16
- export function defineCustomElement(CustomElement, version = '25.0.0-alpha2') {
16
+ export function defineCustomElement(CustomElement, version = '25.0.0-alpha21') {
17
17
  Object.defineProperty(CustomElement, 'version', {
18
18
  get() {
19
19
  return version;
@@ -48,9 +48,10 @@ export const ElementMixin = (superClass) =>
48
48
  window.Vaadin.registrations.push(this);
49
49
  registered.add(is);
50
50
 
51
- if (window.Vaadin.developmentModeCallback) {
51
+ const callback = window.Vaadin.developmentModeCallback;
52
+ if (callback) {
52
53
  statsJob = Debouncer.debounce(statsJob, idlePeriod, () => {
53
- window.Vaadin.developmentModeCallback['vaadin-usage-statistics']();
54
+ callback['vaadin-usage-statistics']();
54
55
  });
55
56
  enqueueDebouncer(statsJob);
56
57
  }
package/src/gestures.js CHANGED
@@ -58,7 +58,6 @@ function isMouseEvent(name) {
58
58
  return MOUSE_EVENTS.indexOf(name) > -1;
59
59
  }
60
60
 
61
- /* eslint no-empty: ["error", { "allowEmptyCatch": true }] */
62
61
  // check for passive event listeners
63
62
  let supportsPassive = false;
64
63
  (function () {
@@ -347,7 +347,6 @@ export const ironList = {
347
347
  ith = this._physicalEnd;
348
348
  offsetContent = bottom - scrollBottom;
349
349
  }
350
- // eslint-disable-next-line no-constant-condition
351
350
  while (true) {
352
351
  physicalItemHeight = this._getPhysicalSizeIncrement(ith);
353
352
  offsetContent -= physicalItemHeight;
@@ -215,26 +215,10 @@ const PolylitMixinImplementation = (superclass) => {
215
215
  };
216
216
  }
217
217
 
218
- constructor() {
219
- super();
220
- this.__hasPolylitMixin = true;
221
- }
222
-
223
218
  /** @protected */
224
219
  connectedCallback() {
225
220
  super.connectedCallback();
226
221
 
227
- // Components like `vaadin-overlay` are teleported to the body element when opened.
228
- // If their opened state is set as an attribute, the teleportation happens immediately
229
- // after they are connected to the DOM. This means they will be outside the scope of
230
- // querySelectorAll in the parent component's `firstUpdated()`. To ensure their reference
231
- // is still registered in the $ map, we propagate the reference here.
232
- const parentHost = this.getRootNode().host;
233
- if (parentHost && parentHost.__hasPolylitMixin && this.id) {
234
- parentHost.$ ||= {};
235
- parentHost.$[this.id] = this;
236
- }
237
-
238
222
  const { polylitConfig } = this.constructor;
239
223
  if (!this.hasUpdated && !polylitConfig.asyncFirstRender) {
240
224
  this.performUpdate();
@@ -249,10 +233,8 @@ const PolylitMixinImplementation = (superclass) => {
249
233
  this.$ = {};
250
234
  }
251
235
 
252
- [...Object.values(this.$), this.renderRoot].forEach((node) => {
253
- node.querySelectorAll('[id]').forEach((node) => {
254
- this.$[node.id] = node;
255
- });
236
+ this.renderRoot.querySelectorAll('[id]').forEach((node) => {
237
+ this.$[node.id] = node;
256
238
  });
257
239
  }
258
240
 
@@ -15,7 +15,7 @@ export class SlotController extends EventTarget {
15
15
  * Ensure that every instance has unique ID.
16
16
  *
17
17
  * @param {HTMLElement} host
18
- * @param {string} slotName
18
+ * @param {string} prefix
19
19
  * @return {string}
20
20
  * @protected
21
21
  */
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2025 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import './style-props.js';
7
+ import { css } from 'lit';
8
+
9
+ export const loaderStyles = css`
10
+ @keyframes fade-in {
11
+ 0% {
12
+ opacity: 0;
13
+ }
14
+ }
15
+
16
+ @keyframes spin {
17
+ to {
18
+ rotate: 1turn;
19
+ }
20
+ }
21
+
22
+ [part='loader'] {
23
+ animation:
24
+ spin var(--vaadin-spinner-animation-duration, 1s) linear infinite,
25
+ fade-in 0.3s 0.3s both;
26
+ border: var(--vaadin-spinner-width, 2px) solid;
27
+ --_spinner-color: var(--vaadin-spinner-color, var(--vaadin-text-color));
28
+ --_spinner-color2: color-mix(in srgb, var(--_spinner-color) 20%, transparent);
29
+ border-color: var(--_spinner-color) var(--_spinner-color) var(--_spinner-color2) var(--_spinner-color2);
30
+ border-radius: 50%;
31
+ box-sizing: border-box;
32
+ height: var(--vaadin-spinner-size, 1lh);
33
+ pointer-events: none;
34
+ width: var(--vaadin-spinner-size, 1lh);
35
+ }
36
+
37
+ :host(:not([loading])) [part~='loader'] {
38
+ display: none;
39
+ }
40
+ `;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css } from 'lit';
7
+ import { addGlobalThemeStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
8
+
9
+ addGlobalThemeStyles(
10
+ 'vaadin-base',
11
+ css`
12
+ @layer vaadin.base {
13
+ :where(html) {
14
+ /* Background color */
15
+ --vaadin-background-color: light-dark(#fff, #222);
16
+
17
+ /* Container colors */
18
+ --vaadin-background-container: color-mix(in oklab, var(--vaadin-text-color) 5%, var(--vaadin-background-color));
19
+ --vaadin-background-container-strong: color-mix(
20
+ in oklab,
21
+ var(--vaadin-text-color) 10%,
22
+ var(--vaadin-background-color)
23
+ );
24
+
25
+ /* Border colors */
26
+ --vaadin-border-color-secondary: color-mix(in oklab, var(--vaadin-text-color) 24%, transparent);
27
+ --vaadin-border-color: color-mix(in oklab, var(--vaadin-text-color) 48%, transparent); /* Above 3:1 contrast */
28
+
29
+ /* Text colors */
30
+ --vaadin-text-color-disabled: color-mix(
31
+ in oklab,
32
+ var(--vaadin-text-color) 48%,
33
+ transparent
34
+ ); /* Above 3:1 contrast */
35
+ --vaadin-text-color-secondary: color-mix(
36
+ in oklab,
37
+ var(--vaadin-text-color) 68%,
38
+ transparent
39
+ ); /* Above 4.5:1 contrast */
40
+ --vaadin-text-color: light-dark(#1f1f1f, white); /* Above 7:1 contrast */
41
+
42
+ /* Padding */
43
+ --vaadin-padding-xs: 6px;
44
+ --vaadin-padding-s: 8px;
45
+ --vaadin-padding-m: 12px;
46
+ --vaadin-padding-l: 16px;
47
+ --vaadin-padding-xl: 24px;
48
+ --vaadin-padding-container: var(--vaadin-padding-xs) var(--vaadin-padding-s);
49
+
50
+ /* Gap/spacing */
51
+ --vaadin-gap-xs: 6px;
52
+ --vaadin-gap-s: 8px;
53
+ --vaadin-gap-m: 12px;
54
+ --vaadin-gap-l: 16px;
55
+ --vaadin-gap-xl: 24px;
56
+
57
+ /* Border radius */
58
+ --vaadin-radius-s: 3px;
59
+ --vaadin-radius-m: 6px;
60
+ --vaadin-radius-l: 12px;
61
+
62
+ /* Focus outline */
63
+ --vaadin-focus-ring-width: 2px;
64
+ --vaadin-focus-ring-color: var(--vaadin-text-color);
65
+
66
+ /* Icons, used as mask-image */
67
+ --_vaadin-icon-arrow-up: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18" /></svg>');
68
+ --_vaadin-icon-calendar: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5" /></svg>');
69
+ --_vaadin-icon-checkmark: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" /></svg>');
70
+ --_vaadin-icon-chevron-down: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /></svg>');
71
+ --_vaadin-icon-clock: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" /></svg>');
72
+ --_vaadin-icon-cross: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /></svg>');
73
+ --_vaadin-icon-drag: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path d="M11 7c0 .82843-.6716 1.5-1.5 1.5C8.67157 8.5 8 7.82843 8 7s.67157-1.5 1.5-1.5c.8284 0 1.5.67157 1.5 1.5Zm0 5c0 .8284-.6716 1.5-1.5 1.5-.82843 0-1.5-.6716-1.5-1.5s.67157-1.5 1.5-1.5c.8284 0 1.5.6716 1.5 1.5Zm0 5c0 .8284-.6716 1.5-1.5 1.5-.82843 0-1.5-.6716-1.5-1.5s.67157-1.5 1.5-1.5c.8284 0 1.5.6716 1.5 1.5Zm5-10c0 .82843-.6716 1.5-1.5 1.5S13 7.82843 13 7s.6716-1.5 1.5-1.5S16 6.17157 16 7Zm0 5c0 .8284-.6716 1.5-1.5 1.5S13 12.8284 13 12s.6716-1.5 1.5-1.5 1.5.6716 1.5 1.5Zm0 5c0 .8284-.6716 1.5-1.5 1.5S13 17.8284 13 17s.6716-1.5 1.5-1.5 1.5.6716 1.5 1.5Z" fill="currentColor"/></svg>');
74
+ --_vaadin-icon-eye: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>');
75
+ --_vaadin-icon-eye-slash: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg>');
76
+ --_vaadin-icon-fullscreen: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /></svg>');
77
+ --_vaadin-icon-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>');
78
+ --_vaadin-icon-link: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>');
79
+ --_vaadin-icon-menu: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /></svg>');
80
+ --_vaadin-icon-minus: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14" /></svg>');
81
+ --_vaadin-icon-paper-airplane: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" /></svg>');
82
+ --_vaadin-icon-pen: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></svg>');
83
+ --_vaadin-icon-play: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z" /></svg>');
84
+ --_vaadin-icon-plus: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /></svg>');
85
+ --_vaadin-icon-redo: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7"/></svg>');
86
+ --_vaadin-icon-refresh: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path d="M22 10C22 10 19.995 7.26822 18.3662 5.63824C16.7373 4.00827 14.4864 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.1031 21 19.5649 18.2543 20.6482 14.5M22 10V4M22 10H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
87
+ --_vaadin-icon-resize: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M18.5303 7.46967c.2929.29289.2929.76777 0 1.06066L8.53033 18.5304c-.29289.2929-.76777.2929-1.06066 0s-.29289-.7678 0-1.0607L17.4697 7.46967c.2929-.29289.7677-.29289 1.0606 0Zm0 4.50003c.2929.2929.2929.7678 0 1.0607l-5.5 5.5c-.2929.2928-.7677.2928-1.0606 0-.2929-.2929-.2929-.7678 0-1.0607l5.4999-5.5c.2929-.2929.7678-.2929 1.0607 0Zm0 4.5c.2929.2928.2929.7677 0 1.0606l-1 1.0001c-.2929.2928-.7677.2929-1.0606 0-.2929-.2929-.2929-.7678 0-1.0607l1-1c.2929-.2929.7677-.2929 1.0606 0Z" fill="currentColor"/></svg>');
88
+ --_vaadin-icon-sort: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="8" height="12" viewBox="0 0 8 12" fill="none"><path d="M7.49854 6.99951C7.92795 6.99951 8.15791 7.50528 7.87549 7.82861L4.37646 11.8296C4.17728 12.0571 3.82272 12.0571 3.62354 11.8296L0.125488 7.82861C-0.157248 7.50531 0.0719873 6.99956 0.501465 6.99951H7.49854ZM3.62354 0.17041C3.82275 -0.0573875 4.17725 -0.0573848 4.37646 0.17041L7.87549 4.17041C8.15825 4.49373 7.92806 5.00049 7.49854 5.00049L0.501465 4.99951C0.0719873 4.99946 -0.157248 4.49371 0.125488 4.17041L3.62354 0.17041Z" fill="black"/></svg>');
89
+ --_vaadin-icon-undo: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/></svg>');
90
+ --_vaadin-icon-upload: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5m-13.5-9L12 3m0 0 4.5 4.5M12 3v13.5" /></svg>');
91
+ --_vaadin-icon-user: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path d="M3 20C5.33579 17.5226 8.50702 16 12 16C15.493 16 18.6642 17.5226 21 20M16.5 7.5C16.5 9.98528 14.4853 12 12 12C9.51472 12 7.5 9.98528 7.5 7.5C7.5 5.01472 9.51472 3 12 3C14.4853 3 16.5 5.01472 16.5 7.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
92
+ --_vaadin-icon-warn: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /></svg>');
93
+
94
+ /* Cursors for interactive elements */
95
+ --vaadin-clickable-cursor: pointer;
96
+ --vaadin-disabled-cursor: not-allowed;
97
+ }
98
+
99
+ @media (forced-colors: active) {
100
+ html {
101
+ --vaadin-background-color: Canvas;
102
+ --vaadin-border-color: CanvasText;
103
+ --vaadin-border-color-secondary: CanvasText;
104
+ --vaadin-text-color-disabled: CanvasText;
105
+ --vaadin-text-color-secondary: CanvasText;
106
+ --vaadin-text-color: CanvasText;
107
+ --vaadin-icon-color: CanvasText;
108
+ --vaadin-focus-ring-color: Highlight;
109
+ }
110
+ }
111
+ }
112
+ `,
113
+ );
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css } from 'lit';
7
+ import { addGlobalThemeStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
8
+
9
+ addGlobalThemeStyles(
10
+ 'vaadin-base-user-colors',
11
+ css`
12
+ @layer vaadin.base {
13
+ :where(html) {
14
+ --_color-count: 10;
15
+ --_hue-step: calc(360 / var(--_color-count) - 1);
16
+ --vaadin-user-color-0: var(--vaadin-user-color, #4172d5);
17
+ --vaadin-user-color-1: oklch(
18
+ from var(--vaadin-user-color-0) max(0.2, l - 0.1) c calc(h - var(--_hue-step) * 1)
19
+ );
20
+ --vaadin-user-color-2: oklch(
21
+ from var(--vaadin-user-color-0) min(l + 0.1, 0.8) c calc(h - var(--_hue-step) * 2)
22
+ );
23
+ --vaadin-user-color-3: oklch(
24
+ from var(--vaadin-user-color-0) max(0.2, l - 0.1) c calc(h - var(--_hue-step) * 3)
25
+ );
26
+ --vaadin-user-color-4: oklch(
27
+ from var(--vaadin-user-color-0) min(l + 0.1, 0.8) c calc(h - var(--_hue-step) * 4)
28
+ );
29
+ --vaadin-user-color-5: oklch(
30
+ from var(--vaadin-user-color-0) max(0.2, l - 0.1) c calc(h - var(--_hue-step) * 5)
31
+ );
32
+ --vaadin-user-color-6: oklch(
33
+ from var(--vaadin-user-color-0) min(l + 0.1, 0.8) c calc(h - var(--_hue-step) * 6)
34
+ );
35
+ --vaadin-user-color-7: oklch(
36
+ from var(--vaadin-user-color-0) max(0.2, l - 0.1) c calc(h - var(--_hue-step) * 7)
37
+ );
38
+ --vaadin-user-color-8: oklch(
39
+ from var(--vaadin-user-color-0) min(l + 0.1, 0.8) c calc(h - var(--_hue-step) * 8)
40
+ );
41
+ --vaadin-user-color-9: oklch(
42
+ from var(--vaadin-user-color-0) max(0.2, l - 0.1) c calc(h - var(--_hue-step) * 9)
43
+ );
44
+ }
45
+ }
46
+ `,
47
+ );
@@ -14,6 +14,7 @@ export class TooltipController extends SlotController {
14
14
  super(host, 'tooltip');
15
15
 
16
16
  this.setTarget(host);
17
+ this.__onContentChange = this.__onContentChange.bind(this);
17
18
  }
18
19
 
19
20
  /**
@@ -50,7 +51,11 @@ export class TooltipController extends SlotController {
50
51
  tooltipNode.shouldShow = this.shouldShow;
51
52
  }
52
53
 
53
- this.__notifyChange();
54
+ if (!this.manual) {
55
+ this.host.setAttribute('has-tooltip', '');
56
+ }
57
+ this.__notifyChange(tooltipNode);
58
+ tooltipNode.addEventListener('content-changed', this.__onContentChange);
54
59
  }
55
60
 
56
61
  /**
@@ -60,8 +65,12 @@ export class TooltipController extends SlotController {
60
65
  * @protected
61
66
  * @override
62
67
  */
63
- teardownNode() {
64
- this.__notifyChange();
68
+ teardownNode(tooltipNode) {
69
+ if (!this.manual) {
70
+ this.host.removeAttribute('has-tooltip');
71
+ }
72
+ tooltipNode.removeEventListener('content-changed', this.__onContentChange);
73
+ this.__notifyChange(null);
65
74
  }
66
75
 
67
76
  /**
@@ -160,7 +169,12 @@ export class TooltipController extends SlotController {
160
169
  }
161
170
 
162
171
  /** @private */
163
- __notifyChange() {
164
- this.dispatchEvent(new CustomEvent('tooltip-changed', { detail: { node: this.node } }));
172
+ __onContentChange(event) {
173
+ this.__notifyChange(event.target);
174
+ }
175
+
176
+ /** @private */
177
+ __notifyChange(node) {
178
+ this.dispatchEvent(new CustomEvent('tooltip-changed', { detail: { node } }));
165
179
  }
166
180
  }
@@ -14,15 +14,29 @@ const MAX_VIRTUAL_COUNT = 100000;
14
14
  const OFFSET_ADJUST_MIN_THRESHOLD = 1000;
15
15
 
16
16
  export class IronListAdapter {
17
- constructor({ createElements, updateElement, scrollTarget, scrollContainer, elementsContainer, reorderElements }) {
17
+ constructor({
18
+ createElements,
19
+ updateElement,
20
+ scrollTarget,
21
+ scrollContainer,
22
+ reorderElements,
23
+ elementsContainer,
24
+ __disableHeightPlaceholder,
25
+ }) {
18
26
  this.isAttached = true;
19
27
  this._vidxOffset = 0;
20
28
  this.createElements = createElements;
21
29
  this.updateElement = updateElement;
22
30
  this.scrollTarget = scrollTarget;
23
31
  this.scrollContainer = scrollContainer;
24
- this.elementsContainer = elementsContainer || scrollContainer;
25
32
  this.reorderElements = reorderElements;
33
+ this.elementsContainer = elementsContainer || scrollContainer;
34
+
35
+ // Internal option that disables the heavy height placeholder calculation
36
+ // (see __afterElementsUpdated) for components that always render virtual
37
+ // elements with a non-zero height. Not for public use.
38
+ this.__disableHeightPlaceholder = __disableHeightPlaceholder ?? false;
39
+
26
40
  // Iron-list uses this value to determine how many pages of elements to render
27
41
  this._maxPages = 1.3;
28
42
 
@@ -33,7 +47,7 @@ export class IronListAdapter {
33
47
 
34
48
  this.timeouts = {
35
49
  SCROLL_REORDER: 500,
36
- IGNORE_WHEEL: 500,
50
+ PREVENT_OVERSCROLL: 500,
37
51
  FIX_INVALID_ITEM_POSITIONING: 100,
38
52
  };
39
53
 
@@ -65,7 +79,6 @@ export class IronListAdapter {
65
79
  attachObserver.observe(this.scrollTarget);
66
80
 
67
81
  this._scrollLineHeight = this._getScrollLineHeight();
68
- this.scrollTarget.addEventListener('wheel', (e) => this.__onWheel(e));
69
82
 
70
83
  this.scrollTarget.addEventListener('virtualizer-element-focused', (e) => this.__onElementFocused(e));
71
84
  this.elementsContainer.addEventListener('focusin', () => {
@@ -271,33 +284,35 @@ export class IronListAdapter {
271
284
  * @param {!Array<!HTMLElement>} updatedElements
272
285
  */
273
286
  __afterElementsUpdated(updatedElements) {
274
- updatedElements.forEach((el) => {
275
- const elementHeight = el.offsetHeight;
276
- if (elementHeight === 0) {
277
- // If the elements have 0 height after update (for example due to lazy rendering),
278
- // it results in iron-list requesting to create an unlimited count of elements.
279
- // Assign a temporary placeholder sizing to elements that would otherwise end up having
280
- // no height.
281
- el.style.paddingTop = `${this.__placeholderHeight}px`;
282
- el.style.opacity = '0';
283
- el.__virtualizerPlaceholder = true;
284
-
285
- // Manually schedule the resize handler to make sure the placeholder padding is
286
- // cleared in case the resize observer never triggers.
287
- this.__placeholderClearDebouncer = Debouncer.debounce(this.__placeholderClearDebouncer, animationFrame, () =>
288
- this._resizeHandler(),
289
- );
290
- } else {
291
- // Add element height to the queue
292
- this.__elementHeightQueue.push(elementHeight);
293
- this.__elementHeightQueue.shift();
294
-
295
- // Calculate new placeholder height based on the average of the defined values in the
296
- // element height queue
297
- const filteredHeights = this.__elementHeightQueue.filter((h) => h !== undefined);
298
- this.__placeholderHeight = Math.round(filteredHeights.reduce((a, b) => a + b, 0) / filteredHeights.length);
299
- }
300
- });
287
+ if (!this.__disableHeightPlaceholder) {
288
+ updatedElements.forEach((el) => {
289
+ const elementHeight = el.offsetHeight;
290
+ if (elementHeight === 0) {
291
+ // If the elements have 0 height after update (for example due to lazy rendering),
292
+ // it results in iron-list requesting to create an unlimited count of elements.
293
+ // Assign a temporary placeholder sizing to elements that would otherwise end up having
294
+ // no height.
295
+ el.style.paddingTop = `${this.__placeholderHeight}px`;
296
+ el.style.opacity = '0';
297
+ el.__virtualizerPlaceholder = true;
298
+
299
+ // Manually schedule the resize handler to make sure the placeholder padding is
300
+ // cleared in case the resize observer never triggers.
301
+ this.__placeholderClearDebouncer = Debouncer.debounce(this.__placeholderClearDebouncer, animationFrame, () =>
302
+ this._resizeHandler(),
303
+ );
304
+ } else {
305
+ // Add element height to the queue
306
+ this.__elementHeightQueue.push(elementHeight);
307
+ this.__elementHeightQueue.shift();
308
+
309
+ // Calculate new placeholder height based on the average of the defined values in the
310
+ // element height queue
311
+ const filteredHeights = this.__elementHeightQueue.filter((h) => h !== undefined);
312
+ this.__placeholderHeight = Math.round(filteredHeights.reduce((a, b) => a + b, 0) / filteredHeights.length);
313
+ }
314
+ });
315
+ }
301
316
 
302
317
  if (this.__pendingScrollToIndex !== undefined && !this.__hasPlaceholders()) {
303
318
  this.scrollToIndex(this.__pendingScrollToIndex);
@@ -548,8 +563,8 @@ export class IronListAdapter {
548
563
  return;
549
564
  }
550
565
 
551
- this._adjustVirtualIndexOffset(this._scrollTop - (this.__previousScrollTop || 0));
552
- const delta = this.scrollTarget.scrollTop - this._scrollPosition;
566
+ this._adjustVirtualIndexOffset(this._scrollTop - this._scrollPosition);
567
+ const delta = this._scrollTop - this._scrollPosition;
553
568
 
554
569
  super._scrollHandler();
555
570
 
@@ -580,6 +595,18 @@ export class IronListAdapter {
580
595
  timeOut.after(this.timeouts.FIX_INVALID_ITEM_POSITIONING),
581
596
  () => this.__fixInvalidItemPositioning(),
582
597
  );
598
+
599
+ if (!this.__overscrollDebouncer?.isActive()) {
600
+ this.scrollTarget.style.overscrollBehavior = 'none';
601
+ }
602
+
603
+ this.__overscrollDebouncer = Debouncer.debounce(
604
+ this.__overscrollDebouncer,
605
+ timeOut.after(this.timeouts.PREVENT_OVERSCROLL),
606
+ () => {
607
+ this.scrollTarget.style.overscrollBehavior = null;
608
+ },
609
+ );
583
610
  }
584
611
 
585
612
  if (this.reorderElements) {
@@ -590,15 +617,31 @@ export class IronListAdapter {
590
617
  );
591
618
  }
592
619
 
593
- this.__previousScrollTop = this._scrollTop;
594
-
595
620
  // If the first visible index is not 0 when scrolled to the top,
596
621
  // scroll to index 0 to fix the issue.
597
- if (this._scrollTop === 0 && this.firstVisibleIndex !== 0 && Math.abs(delta) > 0) {
622
+ if (this._scrollPosition === 0 && this.firstVisibleIndex !== 0 && Math.abs(delta) > 0) {
598
623
  this.scrollToIndex(0);
599
624
  }
600
625
  }
601
626
 
627
+ /** @override */
628
+ _resizeHandler() {
629
+ super._resizeHandler();
630
+
631
+ // Fixes an issue where the new items are not created on scroll target resize when the scroll position is around the end.
632
+ // See https://github.com/vaadin/flow-components/issues/7307
633
+ const lastIndexVisible = this.adjustedLastVisibleIndex === this.size - 1;
634
+ const emptySpace = this._physicalTop - this._scrollPosition;
635
+ if (lastIndexVisible && emptySpace > 0) {
636
+ const idxAdjustment = Math.ceil(emptySpace / this._physicalAverage);
637
+ this._virtualStart = Math.max(0, this._virtualStart - idxAdjustment);
638
+ this._physicalStart = Math.max(0, this._physicalStart - idxAdjustment);
639
+ // Scroll to end for smoother resize
640
+ super.scrollToIndex(this._virtualCount - 1);
641
+ this.scrollTarget.scrollTop = this.scrollTarget.scrollHeight - this.scrollTarget.clientHeight;
642
+ }
643
+ }
644
+
602
645
  /**
603
646
  * Work around an iron-list issue with invalid item positioning.
604
647
  * See https://github.com/vaadin/flow-components/issues/4306
@@ -636,96 +679,6 @@ export class IronListAdapter {
636
679
  }
637
680
  }
638
681
 
639
- /** @private */
640
- __onWheel(e) {
641
- if (e.ctrlKey || this._hasScrolledAncestor(e.target, e.deltaX, e.deltaY)) {
642
- return;
643
- }
644
-
645
- let deltaY = e.deltaY;
646
- if (e.deltaMode === WheelEvent.DOM_DELTA_LINE) {
647
- // Scrolling by "lines of text" instead of pixels
648
- deltaY *= this._scrollLineHeight;
649
- } else if (e.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
650
- // Scrolling by "pages" instead of pixels
651
- deltaY *= this._scrollPageHeight;
652
- }
653
-
654
- if (!this._deltaYAcc) {
655
- this._deltaYAcc = 0;
656
- }
657
-
658
- if (this._wheelAnimationFrame) {
659
- // Accumulate wheel delta while a frame is being processed
660
- this._deltaYAcc += deltaY;
661
- e.preventDefault();
662
- return;
663
- }
664
-
665
- deltaY += this._deltaYAcc;
666
- this._deltaYAcc = 0;
667
-
668
- this._wheelAnimationFrame = true;
669
- this.__debouncerWheelAnimationFrame = Debouncer.debounce(
670
- this.__debouncerWheelAnimationFrame,
671
- animationFrame,
672
- () => {
673
- this._wheelAnimationFrame = false;
674
- },
675
- );
676
-
677
- const momentum = Math.abs(e.deltaX) + Math.abs(deltaY);
678
-
679
- if (this._canScroll(this.scrollTarget, e.deltaX, deltaY)) {
680
- e.preventDefault();
681
- this.scrollTarget.scrollTop += deltaY;
682
- this.scrollTarget.scrollLeft += e.deltaX;
683
-
684
- this._hasResidualMomentum = true;
685
-
686
- this._ignoreNewWheel = true;
687
- this._debouncerIgnoreNewWheel = Debouncer.debounce(
688
- this._debouncerIgnoreNewWheel,
689
- timeOut.after(this.timeouts.IGNORE_WHEEL),
690
- () => {
691
- this._ignoreNewWheel = false;
692
- },
693
- );
694
- } else if ((this._hasResidualMomentum && momentum <= this._previousMomentum) || this._ignoreNewWheel) {
695
- e.preventDefault();
696
- } else if (momentum > this._previousMomentum) {
697
- this._hasResidualMomentum = false;
698
- }
699
- this._previousMomentum = momentum;
700
- }
701
-
702
- /**
703
- * Determines if the element has an ancestor that handles the scroll delta prior to this
704
- *
705
- * @private
706
- */
707
- _hasScrolledAncestor(el, deltaX, deltaY) {
708
- if (el === this.scrollTarget || el === this.scrollTarget.getRootNode().host) {
709
- return false;
710
- } else if (
711
- this._canScroll(el, deltaX, deltaY) &&
712
- ['auto', 'scroll'].indexOf(getComputedStyle(el).overflow) !== -1
713
- ) {
714
- return true;
715
- } else if (el !== this && el.parentElement) {
716
- return this._hasScrolledAncestor(el.parentElement, deltaX, deltaY);
717
- }
718
- }
719
-
720
- _canScroll(el, deltaX, deltaY) {
721
- return (
722
- (deltaY > 0 && el.scrollTop < el.scrollHeight - el.offsetHeight) ||
723
- (deltaY < 0 && el.scrollTop > 0) ||
724
- (deltaX > 0 && el.scrollLeft < el.scrollWidth - el.offsetWidth) ||
725
- (deltaX < 0 && el.scrollLeft > 0)
726
- );
727
- }
728
-
729
682
  /**
730
683
  * Increases the pool size.
731
684
  * @override
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
1
6
  import { IronListAdapter } from './virtualizer-iron-list-adapter.js';
2
7
 
3
8
  export class Virtualizer {
@@ -73,9 +78,7 @@ export class Virtualizer {
73
78
  /**
74
79
  * Flushes active asynchronous tasks so that the component and the DOM end up in a stable state
75
80
  *
76
- * @method update
77
- * @param {number | undefined} startIndex The start index of the range
78
- * @param {number | undefined} endIndex The end index of the range
81
+ * @method flush
79
82
  */
80
83
  flush() {
81
84
  this.__adapter.flush();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * Issues a warning in the browser console if it has not been issued before.
9
+ */
10
+ export declare function issueWarning(warning: string): void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ const issuedWarnings = new Set();
8
+
9
+ /**
10
+ * Issues a warning in the browser console if it has not been issued before.
11
+ * @param {string} warning
12
+ */
13
+ export function issueWarning(warning) {
14
+ if (issuedWarnings.has(warning)) {
15
+ return;
16
+ }
17
+
18
+ issuedWarnings.add(warning);
19
+ console.warn(warning);
20
+ }
21
+
22
+ /**
23
+ * Clears all issued warnings. Only intended for testing purposes.
24
+ */
25
+ export function clearWarnings() {
26
+ issuedWarnings.clear();
27
+ }