@vaadin/component-base
Advanced tools
| /** | ||
| * @license | ||
| * Copyright (c) 2026 - 2026 Vaadin Ltd. | ||
| * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ | ||
| */ | ||
| /** | ||
| * Recursively copies own properties of `source` into `target` and returns | ||
| * `target`. Plain objects are merged, other values are assigned as they are. | ||
| * An object is plain when it inherits from `Object.prototype` or from nothing, | ||
| * so values such as a `Date` or a class instance are assigned, not merged. | ||
| * | ||
| * Merges a single source. Use `deepMergePartials()` to merge several objects, | ||
| * or to merge objects that only provide some of the properties. | ||
| * | ||
| * Both arguments are expected to be plain objects. When either of them is not, | ||
| * `target` is returned without changes. A property of the target that is not a | ||
| * plain object is replaced with the merged object, unlike the arguments. | ||
| * | ||
| * Keys that would modify `Object.prototype`, such as `__proto__`, are ignored. | ||
| */ | ||
| export function deepMerge<T extends object>(target: T, source: object): T; | ||
| /** | ||
| * Recursively merges partial objects into `target` in order and returns | ||
| * `target`, so that a later source overrides an earlier one. | ||
| * | ||
| * Values that are `null` or `undefined` are skipped, so a source that only | ||
| * provides some of the properties does not remove the others. For the same | ||
| * reason, a property that the target already has is not replaced with an | ||
| * object when the source has one for the same key. Arrays are copied one level | ||
| * deep, so that the result does not share an array with any of the sources. | ||
| * | ||
| * Sources that are not plain objects are ignored. When `target` is not a plain | ||
| * object, it is returned without changes. | ||
| * | ||
| * Keys that would modify `Object.prototype`, such as `__proto__`, are ignored. | ||
| */ | ||
| export function deepMergePartials<T extends object>(target: T, ...sources: object[]): T; |
| /** | ||
| * @license | ||
| * Copyright (c) 2026 - 2026 Vaadin Ltd. | ||
| * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ | ||
| */ | ||
| /** | ||
| * Keys that are not copied while merging, as assigning them would modify | ||
| * `Object.prototype` instead of the merge target, and so affect every | ||
| * object in the application. | ||
| */ | ||
| const IGNORED_KEYS = ['__proto__', 'constructor', 'prototype']; | ||
| const isPlainObject = (value) => { | ||
| if (!value || typeof value !== 'object') { | ||
| return false; | ||
| } | ||
| const prototype = Object.getPrototypeOf(value); | ||
| return prototype === Object.prototype || prototype === null; | ||
| }; | ||
| /** | ||
| * Merges `source` into `target`. With `partial`, the source is treated as an | ||
| * object that may provide only some of the properties: nullish values are | ||
| * skipped and arrays are copied instead of shared. | ||
| */ | ||
| function merge(target, source, partial) { | ||
| if (!isPlainObject(target) || !isPlainObject(source)) { | ||
| return target; | ||
| } | ||
| Object.keys(source).forEach((key) => { | ||
| if (IGNORED_KEYS.includes(key)) { | ||
| return; | ||
| } | ||
| const value = source[key]; | ||
| if (isPlainObject(value)) { | ||
| // Only merge into an own plain object, so that the merge can never | ||
| // continue into an object inherited from the prototype chain. | ||
| if (!Object.hasOwn(target, key) || !isPlainObject(target[key])) { | ||
| // With `partial`, a value that the target already has is kept, so that | ||
| // a source property of an unexpected type does not remove a default. | ||
| if (partial && Object.hasOwn(target, key) && target[key]) { | ||
| return; | ||
| } | ||
| target[key] = {}; | ||
| } | ||
| merge(target[key], value, partial); | ||
| } else if (partial && Array.isArray(value)) { | ||
| target[key] = [...value]; | ||
| } else if (!partial || (value !== undefined && value !== null)) { | ||
| target[key] = value; | ||
| } | ||
| }); | ||
| return target; | ||
| } | ||
| /** | ||
| * Recursively copies own properties of `source` into `target` and returns | ||
| * `target`. Plain objects are merged, other values are assigned as they are. | ||
| * An object is plain when it inherits from `Object.prototype` or from nothing, | ||
| * so values such as a `Date` or a class instance are assigned, not merged. | ||
| * | ||
| * Merges a single source. Use `deepMergePartials()` to merge several objects, | ||
| * or to merge objects that only provide some of the properties. | ||
| * | ||
| * Both arguments are expected to be plain objects. When either of them is not, | ||
| * `target` is returned without changes. A property of the target that is not a | ||
| * plain object is replaced with the merged object, unlike the arguments. | ||
| * | ||
| * Keys that would modify `Object.prototype`, such as `__proto__`, are ignored. | ||
| * | ||
| * @param {object} target the object to merge into, modified in place | ||
| * @param {object} source the object to copy the properties from | ||
| * @return {object} the `target` object | ||
| */ | ||
| export function deepMerge(target, source) { | ||
| return merge(target, source, false); | ||
| } | ||
| /** | ||
| * Recursively merges partial objects into `target` in order and returns | ||
| * `target`, so that a later source overrides an earlier one. | ||
| * | ||
| * Values that are `null` or `undefined` are skipped, so a source that only | ||
| * provides some of the properties does not remove the others. For the same | ||
| * reason, a property that the target already has is not replaced with an | ||
| * object when the source has one for the same key. Arrays are copied one level | ||
| * deep, so that the result does not share an array with any of the sources. | ||
| * | ||
| * Sources that are not plain objects are ignored. When `target` is not a plain | ||
| * object, it is returned without changes. | ||
| * | ||
| * Keys that would modify `Object.prototype`, such as `__proto__`, are ignored. | ||
| * | ||
| * @param {object} target the object to merge into, modified in place | ||
| * @param {...object} sources the objects to copy the properties from | ||
| * @return {object} the `target` object | ||
| */ | ||
| export function deepMergePartials(target, ...sources) { | ||
| sources.forEach((source) => merge(target, source, true)); | ||
| return target; | ||
| } |
+4
-4
| { | ||
| "name": "@vaadin/component-base", | ||
| "version": "24.10.4", | ||
| "version": "24.10.5", | ||
| "publishConfig": { | ||
@@ -41,8 +41,8 @@ "access": "public" | ||
| "devDependencies": { | ||
| "@vaadin/chai-plugins": "~24.10.4", | ||
| "@vaadin/test-runner-commands": "~24.10.4", | ||
| "@vaadin/chai-plugins": "~24.10.5", | ||
| "@vaadin/test-runner-commands": "~24.10.5", | ||
| "@vaadin/testing-helpers": "^1.1.0", | ||
| "sinon": "^18.0.0" | ||
| }, | ||
| "gitHead": "db2b55d7760803aacfff86694c3124a563d782c3" | ||
| "gitHead": "58e7810171be7423aab5c5caefbf67f62074c796" | ||
| } |
+1
-1
@@ -16,3 +16,3 @@ /** | ||
| export function defineCustomElement(CustomElement, version = '24.10.4') { | ||
| export function defineCustomElement(CustomElement, version = '24.10.5') { | ||
| Object.defineProperty(CustomElement, 'version', { | ||
@@ -19,0 +19,0 @@ get() { |
+3
-30
@@ -6,31 +6,4 @@ /** | ||
| */ | ||
| import { deepMergePartials } from './object-utils.js'; | ||
| function deepMerge(target, ...sources) { | ||
| const isArray = (item) => Array.isArray(item); | ||
| const isObject = (item) => item && typeof item === 'object' && !isArray(item); | ||
| const merge = (target, source) => { | ||
| if (isObject(source) && isObject(target)) { | ||
| Object.keys(source).forEach((key) => { | ||
| const sourceValue = source[key]; | ||
| if (isObject(sourceValue)) { | ||
| if (!target[key]) { | ||
| target[key] = {}; | ||
| } | ||
| merge(target[key], sourceValue); | ||
| } else if (isArray(sourceValue)) { | ||
| target[key] = [...sourceValue]; | ||
| } else if (sourceValue !== undefined && sourceValue !== null) { | ||
| target[key] = sourceValue; | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| sources.forEach((source) => { | ||
| merge(target, source); | ||
| }); | ||
| return target; | ||
| } | ||
| /** | ||
@@ -66,3 +39,3 @@ * A mixin that allows to set partial I18N properties. | ||
| this.i18n = deepMerge({}, defaultI18n); | ||
| this.i18n = deepMergePartials({}, defaultI18n); | ||
| } | ||
@@ -99,4 +72,4 @@ | ||
| this.__customI18n = value; | ||
| this.__effectiveI18n = deepMerge({}, defaultI18n, this.__customI18n); | ||
| this.__effectiveI18n = deepMergePartials({}, defaultI18n, this.__customI18n); | ||
| } | ||
| }; |
@@ -80,3 +80,8 @@ /** | ||
| // Need to defer reordering until the user lets go of the scroll bar handle. | ||
| this.scrollTarget.addEventListener('mousedown', () => { | ||
| this.scrollTarget.addEventListener('mousedown', (event) => { | ||
| // Only handle clicks on the scroll target itself | ||
| if (event.target !== this.scrollTarget) { | ||
| return; | ||
| } | ||
| this.__mouseDown = true; | ||
@@ -83,0 +88,0 @@ }); |
236182
2.28%70
2.94%6894
1.68%