gridstack 12.3.3 → 12.4.1

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.
Files changed (124) hide show
  1. package/dist/angular/esm2020/lib/base-widget.mjs +2 -2
  2. package/dist/angular/esm2020/lib/gridstack-item.component.mjs +2 -2
  3. package/dist/angular/esm2020/lib/gridstack.component.mjs +4 -2
  4. package/dist/angular/esm2020/lib/gridstack.module.mjs +2 -2
  5. package/dist/angular/esm2020/lib/types.mjs +2 -2
  6. package/dist/angular/fesm2015/gridstack-angular.mjs +6 -4
  7. package/dist/angular/fesm2015/gridstack-angular.mjs.map +1 -1
  8. package/dist/angular/fesm2020/gridstack-angular.mjs +7 -5
  9. package/dist/angular/fesm2020/gridstack-angular.mjs.map +1 -1
  10. package/dist/angular/lib/gridstack-item.component.d.ts +1 -1
  11. package/dist/angular/lib/gridstack.component.d.ts +4 -4
  12. package/dist/angular/lib/types.d.ts +1 -1
  13. package/dist/angular/package.json +1 -1
  14. package/dist/angular/src/base-widget.ts +13 -13
  15. package/dist/angular/src/gridstack-item.component.ts +5 -5
  16. package/dist/angular/src/gridstack.component.ts +34 -32
  17. package/dist/angular/src/gridstack.module.ts +4 -4
  18. package/dist/angular/src/types.ts +3 -2
  19. package/dist/dd-base-impl.d.ts +1 -1
  20. package/dist/dd-base-impl.js +1 -1
  21. package/dist/dd-base-impl.js.map +1 -1
  22. package/dist/dd-draggable.d.ts +1 -1
  23. package/dist/dd-draggable.js +1 -1
  24. package/dist/dd-draggable.js.map +1 -1
  25. package/dist/dd-droppable.d.ts +1 -1
  26. package/dist/dd-droppable.js +7 -1
  27. package/dist/dd-droppable.js.map +1 -1
  28. package/dist/dd-element.d.ts +1 -1
  29. package/dist/dd-element.js +1 -1
  30. package/dist/dd-element.js.map +1 -1
  31. package/dist/dd-gridstack.d.ts +1 -1
  32. package/dist/dd-gridstack.js +1 -1
  33. package/dist/dd-gridstack.js.map +1 -1
  34. package/dist/dd-manager.d.ts +1 -1
  35. package/dist/dd-manager.js +1 -1
  36. package/dist/dd-manager.js.map +1 -1
  37. package/dist/dd-resizable-handle.d.ts +5 -4
  38. package/dist/dd-resizable-handle.js +23 -8
  39. package/dist/dd-resizable-handle.js.map +1 -1
  40. package/dist/dd-resizable.d.ts +3 -5
  41. package/dist/dd-resizable.js +5 -10
  42. package/dist/dd-resizable.js.map +1 -1
  43. package/dist/dd-touch.d.ts +1 -1
  44. package/dist/dd-touch.js +1 -1
  45. package/dist/dd-touch.js.map +1 -1
  46. package/dist/gridstack-all.js +1 -1
  47. package/dist/gridstack-all.js.LICENSE.txt +1 -1
  48. package/dist/gridstack-all.js.map +1 -1
  49. package/dist/gridstack-engine.d.ts +1 -1
  50. package/dist/gridstack-engine.js +7 -1
  51. package/dist/gridstack-engine.js.map +1 -1
  52. package/dist/gridstack.css +1 -1
  53. package/dist/gridstack.d.ts +1 -2
  54. package/dist/gridstack.js +9 -18
  55. package/dist/gridstack.js.map +1 -1
  56. package/dist/types.d.ts +11 -6
  57. package/dist/types.js +1 -1
  58. package/dist/types.js.map +1 -1
  59. package/dist/utils.d.ts +1 -1
  60. package/dist/utils.js +78 -69
  61. package/dist/utils.js.map +1 -1
  62. package/doc/API.md +166 -165
  63. package/package.json +5 -5
  64. package/dist/spec/gridstack-engine-spec.d.ts +0 -1
  65. package/dist/spec/gridstack-engine-spec.js +0 -358
  66. package/dist/spec/gridstack-engine-spec.js.map +0 -1
  67. package/dist/spec/gridstack-spec.d.ts +0 -1
  68. package/dist/spec/gridstack-spec.js +0 -1780
  69. package/dist/spec/gridstack-spec.js.map +0 -1
  70. package/dist/spec/integration/gridstack-integration.spec.d.ts +0 -1
  71. package/dist/spec/integration/gridstack-integration.spec.js +0 -171
  72. package/dist/spec/integration/gridstack-integration.spec.js.map +0 -1
  73. package/dist/spec/regression-spec.d.ts +0 -1
  74. package/dist/spec/regression-spec.js +0 -100
  75. package/dist/spec/regression-spec.js.map +0 -1
  76. package/dist/spec/utils-spec.d.ts +0 -1
  77. package/dist/spec/utils-spec.js +0 -243
  78. package/dist/spec/utils-spec.js.map +0 -1
  79. package/dist/src/dd-base-impl.d.ts +0 -69
  80. package/dist/src/dd-base-impl.js +0 -70
  81. package/dist/src/dd-base-impl.js.map +0 -1
  82. package/dist/src/dd-draggable.d.ts +0 -20
  83. package/dist/src/dd-draggable.js +0 -364
  84. package/dist/src/dd-draggable.js.map +0 -1
  85. package/dist/src/dd-droppable.d.ts +0 -26
  86. package/dist/src/dd-droppable.js +0 -149
  87. package/dist/src/dd-droppable.js.map +0 -1
  88. package/dist/src/dd-element.d.ts +0 -27
  89. package/dist/src/dd-element.js +0 -91
  90. package/dist/src/dd-element.js.map +0 -1
  91. package/dist/src/dd-gridstack.d.ts +0 -82
  92. package/dist/src/dd-gridstack.js +0 -165
  93. package/dist/src/dd-gridstack.js.map +0 -1
  94. package/dist/src/dd-manager.d.ts +0 -43
  95. package/dist/src/dd-manager.js +0 -14
  96. package/dist/src/dd-manager.js.map +0 -1
  97. package/dist/src/dd-resizable-handle.d.ts +0 -18
  98. package/dist/src/dd-resizable-handle.js +0 -113
  99. package/dist/src/dd-resizable-handle.js.map +0 -1
  100. package/dist/src/dd-resizable.d.ts +0 -30
  101. package/dist/src/dd-resizable.js +0 -304
  102. package/dist/src/dd-resizable.js.map +0 -1
  103. package/dist/src/dd-touch.d.ts +0 -33
  104. package/dist/src/dd-touch.js +0 -145
  105. package/dist/src/dd-touch.js.map +0 -1
  106. package/dist/src/gridstack-engine.d.ts +0 -321
  107. package/dist/src/gridstack-engine.js +0 -1272
  108. package/dist/src/gridstack-engine.js.map +0 -1
  109. package/dist/src/gridstack.d.ts +0 -802
  110. package/dist/src/gridstack.js +0 -2872
  111. package/dist/src/gridstack.js.map +0 -1
  112. package/dist/src/gridstack.scss +0 -157
  113. package/dist/src/types.d.ts +0 -427
  114. package/dist/src/types.js +0 -38
  115. package/dist/src/types.js.map +0 -1
  116. package/dist/src/utils.d.ts +0 -283
  117. package/dist/src/utils.js +0 -790
  118. package/dist/src/utils.js.map +0 -1
  119. package/dist/vitest.config.d.ts +0 -2
  120. package/dist/vitest.config.js +0 -74
  121. package/dist/vitest.config.js.map +0 -1
  122. package/dist/vitest.setup.d.ts +0 -1
  123. package/dist/vitest.setup.js +0 -90
  124. package/dist/vitest.setup.js.map +0 -1
package/dist/src/utils.js DELETED
@@ -1,790 +0,0 @@
1
- /**
2
- * utils.ts 12.3.3
3
- * Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
4
- */
5
- /**
6
- * @internal Checks for obsolete method names and provides deprecation warnings.
7
- * Creates a wrapper function that logs a deprecation warning when called.
8
- *
9
- * @param self the object context to apply the function to
10
- * @param f the new function to call
11
- * @param oldName the deprecated method name
12
- * @param newName the new method name to use instead
13
- * @param rev the version when the deprecation was introduced
14
- * @returns a wrapper function that warns about deprecation
15
- */
16
- // eslint-disable-next-line
17
- export function obsolete(self, f, oldName, newName, rev) {
18
- const wrapper = (...args) => {
19
- console.warn('gridstack.js: Function `' + oldName + '` is deprecated in ' + rev + ' and has been replaced ' +
20
- 'with `' + newName + '`. It will be **removed** in a future release');
21
- return f.apply(self, args);
22
- };
23
- wrapper.prototype = f.prototype;
24
- return wrapper;
25
- }
26
- /**
27
- * @internal Checks for obsolete grid options and migrates them to new names.
28
- * Automatically copies old option values to new option names and shows deprecation warnings.
29
- *
30
- * @param opts the options object to check and migrate
31
- * @param oldName the deprecated option name
32
- * @param newName the new option name to use instead
33
- * @param rev the version when the deprecation was introduced
34
- */
35
- export function obsoleteOpts(opts, oldName, newName, rev) {
36
- if (opts[oldName] !== undefined) {
37
- opts[newName] = opts[oldName];
38
- console.warn('gridstack.js: Option `' + oldName + '` is deprecated in ' + rev + ' and has been replaced with `' +
39
- newName + '`. It will be **removed** in a future release');
40
- }
41
- }
42
- /**
43
- * @internal Checks for obsolete grid options that have been completely removed.
44
- * Shows deprecation warnings for options that are no longer supported.
45
- *
46
- * @param opts the options object to check
47
- * @param oldName the removed option name
48
- * @param rev the version when the option was removed
49
- * @param info additional information about the removal
50
- */
51
- export function obsoleteOptsDel(opts, oldName, rev, info) {
52
- if (opts[oldName] !== undefined) {
53
- console.warn('gridstack.js: Option `' + oldName + '` is deprecated in ' + rev + info);
54
- }
55
- }
56
- /**
57
- * @internal Checks for obsolete HTML element attributes and migrates them.
58
- * Automatically copies old attribute values to new attribute names and shows deprecation warnings.
59
- *
60
- * @param el the HTML element to check and migrate
61
- * @param oldName the deprecated attribute name
62
- * @param newName the new attribute name to use instead
63
- * @param rev the version when the deprecation was introduced
64
- */
65
- export function obsoleteAttr(el, oldName, newName, rev) {
66
- const oldAttr = el.getAttribute(oldName);
67
- if (oldAttr !== null) {
68
- el.setAttribute(newName, oldAttr);
69
- console.warn('gridstack.js: attribute `' + oldName + '`=' + oldAttr + ' is deprecated on this object in ' + rev + ' and has been replaced with `' +
70
- newName + '`. It will be **removed** in a future release');
71
- }
72
- }
73
- /**
74
- * Collection of utility methods used throughout GridStack.
75
- * These are general-purpose helper functions for DOM manipulation,
76
- * positioning calculations, object operations, and more.
77
- */
78
- export class Utils {
79
- /**
80
- * Convert a potential selector into an actual list of HTML elements.
81
- * Supports CSS selectors, element references, and special ID handling.
82
- *
83
- * @param els selector string, HTMLElement, or array of elements
84
- * @param root optional root element to search within (defaults to document, useful for shadow DOM)
85
- * @returns array of HTML elements matching the selector
86
- *
87
- * @example
88
- * const elements = Utils.getElements('.grid-item');
89
- * const byId = Utils.getElements('#myWidget');
90
- * const fromShadow = Utils.getElements('.item', shadowRoot);
91
- */
92
- static getElements(els, root = document) {
93
- if (typeof els === 'string') {
94
- const doc = ('getElementById' in root) ? root : undefined;
95
- // Note: very common for people use to id='1,2,3' which is only legal as HTML5 id, but not CSS selectors
96
- // so if we start with a number, assume it's an id and just return that one item...
97
- // see https://github.com/gridstack/gridstack.js/issues/2234#issuecomment-1523796562
98
- if (doc && !isNaN(+els[0])) { // start with digit
99
- const el = doc.getElementById(els);
100
- return el ? [el] : [];
101
- }
102
- let list = root.querySelectorAll(els);
103
- if (!list.length && els[0] !== '.' && els[0] !== '#') {
104
- list = root.querySelectorAll('.' + els);
105
- if (!list.length) {
106
- list = root.querySelectorAll('#' + els);
107
- }
108
- }
109
- return Array.from(list);
110
- }
111
- return [els];
112
- }
113
- /**
114
- * Convert a potential selector into a single HTML element.
115
- * Similar to getElements() but returns only the first match.
116
- *
117
- * @param els selector string or HTMLElement
118
- * @param root optional root element to search within (defaults to document)
119
- * @returns the first HTML element matching the selector, or null if not found
120
- *
121
- * @example
122
- * const element = Utils.getElement('#myWidget');
123
- * const first = Utils.getElement('.grid-item');
124
- */
125
- static getElement(els, root = document) {
126
- if (typeof els === 'string') {
127
- const doc = ('getElementById' in root) ? root : undefined;
128
- if (!els.length)
129
- return null;
130
- if (doc && els[0] === '#') {
131
- return doc.getElementById(els.substring(1));
132
- }
133
- if (els[0] === '#' || els[0] === '.' || els[0] === '[') {
134
- return root.querySelector(els);
135
- }
136
- // if we start with a digit, assume it's an id (error calling querySelector('#1')) as class are not valid CSS
137
- if (doc && !isNaN(+els[0])) { // start with digit
138
- return doc.getElementById(els);
139
- }
140
- // finally try string, then id, then class
141
- let el = root.querySelector(els);
142
- if (doc && !el) {
143
- el = doc.getElementById(els);
144
- }
145
- if (!el) {
146
- el = root.querySelector('.' + els);
147
- }
148
- return el;
149
- }
150
- return els;
151
- }
152
- /**
153
- * Check if a widget should be lazy loaded based on node or grid settings.
154
- *
155
- * @param n the grid node to check
156
- * @returns true if the item should be lazy loaded
157
- *
158
- * @example
159
- * if (Utils.lazyLoad(node)) {
160
- * // Set up intersection observer for lazy loading
161
- * }
162
- */
163
- static lazyLoad(n) {
164
- return n.lazyLoad || n.grid?.opts?.lazyLoad && n.lazyLoad !== false;
165
- }
166
- /**
167
- * Create a div element with the specified CSS classes.
168
- *
169
- * @param classes array of CSS class names to add
170
- * @param parent optional parent element to append the div to
171
- * @returns the created div element
172
- *
173
- * @example
174
- * const div = Utils.createDiv(['grid-item', 'draggable']);
175
- * const nested = Utils.createDiv(['content'], parentDiv);
176
- */
177
- static createDiv(classes, parent) {
178
- const el = document.createElement('div');
179
- classes.forEach(c => { if (c)
180
- el.classList.add(c); });
181
- parent?.appendChild(el);
182
- return el;
183
- }
184
- /**
185
- * Check if a widget should resize to fit its content.
186
- *
187
- * @param n the grid node to check (can be undefined)
188
- * @param strict if true, only returns true for explicit sizeToContent:true (not numbers)
189
- * @returns true if the widget should resize to content
190
- *
191
- * @example
192
- * if (Utils.shouldSizeToContent(node)) {
193
- * // Trigger content-based resizing
194
- * }
195
- */
196
- static shouldSizeToContent(n, strict = false) {
197
- return n?.grid && (strict ?
198
- (n.sizeToContent === true || (n.grid.opts.sizeToContent === true && n.sizeToContent === undefined)) :
199
- (!!n.sizeToContent || (n.grid.opts.sizeToContent && n.sizeToContent !== false)));
200
- }
201
- /**
202
- * Check if two grid positions overlap/intersect.
203
- *
204
- * @param a first position with x, y, w, h properties
205
- * @param b second position with x, y, w, h properties
206
- * @returns true if the positions overlap
207
- *
208
- * @example
209
- * const overlaps = Utils.isIntercepted(
210
- * {x: 0, y: 0, w: 2, h: 1},
211
- * {x: 1, y: 0, w: 2, h: 1}
212
- * ); // true - they overlap
213
- */
214
- static isIntercepted(a, b) {
215
- return !(a.y >= b.y + b.h || a.y + a.h <= b.y || a.x + a.w <= b.x || a.x >= b.x + b.w);
216
- }
217
- /**
218
- * Check if two grid positions are touching (edges or corners).
219
- *
220
- * @param a first position
221
- * @param b second position
222
- * @returns true if the positions are touching
223
- *
224
- * @example
225
- * const touching = Utils.isTouching(
226
- * {x: 0, y: 0, w: 2, h: 1},
227
- * {x: 2, y: 0, w: 1, h: 1}
228
- * ); // true - they share an edge
229
- */
230
- static isTouching(a, b) {
231
- return Utils.isIntercepted(a, { x: b.x - 0.5, y: b.y - 0.5, w: b.w + 1, h: b.h + 1 });
232
- }
233
- /**
234
- * Calculate the overlapping area between two grid positions.
235
- *
236
- * @param a first position
237
- * @param b second position
238
- * @returns the area of overlap (0 if no overlap)
239
- *
240
- * @example
241
- * const overlap = Utils.areaIntercept(
242
- * {x: 0, y: 0, w: 3, h: 2},
243
- * {x: 1, y: 0, w: 3, h: 2}
244
- * ); // returns 4 (2x2 overlap)
245
- */
246
- static areaIntercept(a, b) {
247
- const x0 = (a.x > b.x) ? a.x : b.x;
248
- const x1 = (a.x + a.w < b.x + b.w) ? a.x + a.w : b.x + b.w;
249
- if (x1 <= x0)
250
- return 0; // no overlap
251
- const y0 = (a.y > b.y) ? a.y : b.y;
252
- const y1 = (a.y + a.h < b.y + b.h) ? a.y + a.h : b.y + b.h;
253
- if (y1 <= y0)
254
- return 0; // no overlap
255
- return (x1 - x0) * (y1 - y0);
256
- }
257
- /**
258
- * Calculate the total area of a grid position.
259
- *
260
- * @param a position with width and height
261
- * @returns the total area (width * height)
262
- *
263
- * @example
264
- * const area = Utils.area({x: 0, y: 0, w: 3, h: 2}); // returns 6
265
- */
266
- static area(a) {
267
- return a.w * a.h;
268
- }
269
- /**
270
- * Sort an array of grid nodes by position (y first, then x).
271
- *
272
- * @param nodes array of nodes to sort
273
- * @param dir sort direction: 1 for ascending (top-left first), -1 for descending
274
- * @returns the sorted array (modifies original)
275
- *
276
- * @example
277
- * const sorted = Utils.sort(nodes); // Sort top-left to bottom-right
278
- * const reverse = Utils.sort(nodes, -1); // Sort bottom-right to top-left
279
- */
280
- static sort(nodes, dir = 1) {
281
- const und = 10000;
282
- return nodes.sort((a, b) => {
283
- const diffY = dir * ((a.y ?? und) - (b.y ?? und));
284
- if (diffY === 0)
285
- return dir * ((a.x ?? und) - (b.x ?? und));
286
- return diffY;
287
- });
288
- }
289
- /**
290
- * Find a grid node by its ID.
291
- *
292
- * @param nodes array of nodes to search
293
- * @param id the ID to search for
294
- * @returns the node with matching ID, or undefined if not found
295
- *
296
- * @example
297
- * const node = Utils.find(nodes, 'widget-1');
298
- * if (node) console.log('Found node at:', node.x, node.y);
299
- */
300
- static find(nodes, id) {
301
- return id ? nodes.find(n => n.id === id) : undefined;
302
- }
303
- /**
304
- * Convert various value types to boolean.
305
- * Handles strings like 'false', 'no', '0' as false.
306
- *
307
- * @param v value to convert
308
- * @returns boolean representation
309
- *
310
- * @example
311
- * Utils.toBool('true'); // true
312
- * Utils.toBool('false'); // false
313
- * Utils.toBool('no'); // false
314
- * Utils.toBool('1'); // true
315
- */
316
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
317
- static toBool(v) {
318
- if (typeof v === 'boolean') {
319
- return v;
320
- }
321
- if (typeof v === 'string') {
322
- v = v.toLowerCase();
323
- return !(v === '' || v === 'no' || v === 'false' || v === '0');
324
- }
325
- return Boolean(v);
326
- }
327
- /**
328
- * Convert a string value to a number, handling null and empty strings.
329
- *
330
- * @param value string or null value to convert
331
- * @returns number value, or undefined for null/empty strings
332
- *
333
- * @example
334
- * Utils.toNumber('42'); // 42
335
- * Utils.toNumber(''); // undefined
336
- * Utils.toNumber(null); // undefined
337
- */
338
- static toNumber(value) {
339
- return (value === null || value.length === 0) ? undefined : Number(value);
340
- }
341
- /**
342
- * Parse a height value with units into numeric value and unit string.
343
- * Supports px, em, rem, vh, vw, %, cm, mm units.
344
- *
345
- * @param val height value as number or string with units
346
- * @returns object with h (height) and unit properties
347
- *
348
- * @example
349
- * Utils.parseHeight('100px'); // {h: 100, unit: 'px'}
350
- * Utils.parseHeight('2rem'); // {h: 2, unit: 'rem'}
351
- * Utils.parseHeight(50); // {h: 50, unit: 'px'}
352
- */
353
- static parseHeight(val) {
354
- let h;
355
- let unit = 'px';
356
- if (typeof val === 'string') {
357
- if (val === 'auto' || val === '')
358
- h = 0;
359
- else {
360
- const match = val.match(/^(-[0-9]+\.[0-9]+|[0-9]*\.[0-9]+|-[0-9]+|[0-9]+)(px|em|rem|vh|vw|%|cm|mm)?$/);
361
- if (!match) {
362
- throw new Error(`Invalid height val = ${val}`);
363
- }
364
- unit = match[2] || 'px';
365
- h = parseFloat(match[1]);
366
- }
367
- }
368
- else {
369
- h = val;
370
- }
371
- return { h, unit };
372
- }
373
- /**
374
- * Copy unset fields from source objects to target object (shallow merge with defaults).
375
- * Similar to Object.assign but only sets undefined/null fields.
376
- *
377
- * @param target the object to copy defaults into
378
- * @param sources one or more source objects to copy defaults from
379
- * @returns the modified target object
380
- *
381
- * @example
382
- * const config = { width: 100 };
383
- * Utils.defaults(config, { width: 200, height: 50 });
384
- * // config is now { width: 100, height: 50 }
385
- */
386
- // eslint-disable-next-line
387
- static defaults(target, ...sources) {
388
- sources.forEach(source => {
389
- for (const key in source) {
390
- if (!source.hasOwnProperty(key))
391
- return;
392
- if (target[key] === null || target[key] === undefined) {
393
- target[key] = source[key];
394
- }
395
- else if (typeof source[key] === 'object' && typeof target[key] === 'object') {
396
- // property is an object, recursively add it's field over... #1373
397
- Utils.defaults(target[key], source[key]);
398
- }
399
- }
400
- });
401
- return target;
402
- }
403
- /**
404
- * Compare two objects for equality (shallow comparison).
405
- * Checks if objects have the same fields and values at one level deep.
406
- *
407
- * @param a first object to compare
408
- * @param b second object to compare
409
- * @returns true if objects have the same values
410
- *
411
- * @example
412
- * Utils.same({x: 1, y: 2}, {x: 1, y: 2}); // true
413
- * Utils.same({x: 1}, {x: 1, y: 2}); // false
414
- */
415
- static same(a, b) {
416
- if (typeof a !== 'object')
417
- return a == b;
418
- if (typeof a !== typeof b)
419
- return false;
420
- // else we have object, check just 1 level deep for being same things...
421
- if (Object.keys(a).length !== Object.keys(b).length)
422
- return false;
423
- for (const key in a) {
424
- if (a[key] !== b[key])
425
- return false;
426
- }
427
- return true;
428
- }
429
- /**
430
- * Copy position and size properties from one widget to another.
431
- * Copies x, y, w, h and optionally min/max constraints.
432
- *
433
- * @param a target widget to copy to
434
- * @param b source widget to copy from
435
- * @param doMinMax if true, also copy min/max width/height constraints
436
- * @returns the target widget (a)
437
- *
438
- * @example
439
- * Utils.copyPos(widget1, widget2); // Copy position/size
440
- * Utils.copyPos(widget1, widget2, true); // Also copy constraints
441
- */
442
- static copyPos(a, b, doMinMax = false) {
443
- if (b.x !== undefined)
444
- a.x = b.x;
445
- if (b.y !== undefined)
446
- a.y = b.y;
447
- if (b.w !== undefined)
448
- a.w = b.w;
449
- if (b.h !== undefined)
450
- a.h = b.h;
451
- if (doMinMax) {
452
- if (b.minW)
453
- a.minW = b.minW;
454
- if (b.minH)
455
- a.minH = b.minH;
456
- if (b.maxW)
457
- a.maxW = b.maxW;
458
- if (b.maxH)
459
- a.maxH = b.maxH;
460
- }
461
- return a;
462
- }
463
- /** true if a and b has same size & position */
464
- static samePos(a, b) {
465
- return a && b && a.x === b.x && a.y === b.y && (a.w || 1) === (b.w || 1) && (a.h || 1) === (b.h || 1);
466
- }
467
- /** given a node, makes sure it's min/max are valid */
468
- static sanitizeMinMax(node) {
469
- // remove 0, undefine, null
470
- if (!node.minW) {
471
- delete node.minW;
472
- }
473
- if (!node.minH) {
474
- delete node.minH;
475
- }
476
- if (!node.maxW) {
477
- delete node.maxW;
478
- }
479
- if (!node.maxH) {
480
- delete node.maxH;
481
- }
482
- }
483
- /** removes field from the first object if same as the second objects (like diffing) and internal '_' for saving */
484
- static removeInternalAndSame(a, b) {
485
- if (typeof a !== 'object' || typeof b !== 'object')
486
- return;
487
- // skip arrays as we don't know how to hydrate them (unlike object spread operator)
488
- if (Array.isArray(a) || Array.isArray(b))
489
- return;
490
- for (let key in a) {
491
- const aVal = a[key];
492
- const bVal = b[key];
493
- if (key[0] === '_' || aVal === bVal) {
494
- delete a[key];
495
- }
496
- else if (aVal && typeof aVal === 'object' && bVal !== undefined) {
497
- Utils.removeInternalAndSame(aVal, bVal);
498
- if (!Object.keys(aVal).length) {
499
- delete a[key];
500
- }
501
- }
502
- }
503
- }
504
- /** removes internal fields '_' and default values for saving */
505
- static removeInternalForSave(n, removeEl = true) {
506
- for (let key in n) {
507
- if (key[0] === '_' || n[key] === null || n[key] === undefined)
508
- delete n[key];
509
- }
510
- delete n.grid;
511
- if (removeEl)
512
- delete n.el;
513
- // delete default values (will be re-created on read)
514
- if (!n.autoPosition)
515
- delete n.autoPosition;
516
- if (!n.noResize)
517
- delete n.noResize;
518
- if (!n.noMove)
519
- delete n.noMove;
520
- if (!n.locked)
521
- delete n.locked;
522
- if (n.w === 1 || n.w === n.minW)
523
- delete n.w;
524
- if (n.h === 1 || n.h === n.minH)
525
- delete n.h;
526
- }
527
- /** return the closest parent (or itself) matching the given class */
528
- // static closestUpByClass(el: HTMLElement, name: string): HTMLElement {
529
- // while (el) {
530
- // if (el.classList.contains(name)) return el;
531
- // el = el.parentElement
532
- // }
533
- // return null;
534
- // }
535
- /** delay calling the given function for given delay, preventing new calls from happening while waiting */
536
- static throttle(func, delay) {
537
- let isWaiting = false;
538
- return (...args) => {
539
- if (!isWaiting) {
540
- isWaiting = true;
541
- setTimeout(() => { func(...args); isWaiting = false; }, delay);
542
- }
543
- };
544
- }
545
- static removePositioningStyles(el) {
546
- const style = el.style;
547
- if (style.position) {
548
- style.removeProperty('position');
549
- }
550
- if (style.left) {
551
- style.removeProperty('left');
552
- }
553
- if (style.top) {
554
- style.removeProperty('top');
555
- }
556
- if (style.width) {
557
- style.removeProperty('width');
558
- }
559
- if (style.height) {
560
- style.removeProperty('height');
561
- }
562
- }
563
- /** @internal returns the passed element if scrollable, else the closest parent that will, up to the entire document scrolling element */
564
- static getScrollElement(el) {
565
- if (!el)
566
- return document.scrollingElement || document.documentElement; // IE support
567
- const style = getComputedStyle(el);
568
- const overflowRegex = /(auto|scroll)/;
569
- if (overflowRegex.test(style.overflow + style.overflowY)) {
570
- return el;
571
- }
572
- else {
573
- return Utils.getScrollElement(el.parentElement);
574
- }
575
- }
576
- /** @internal */
577
- static updateScrollPosition(el, position, distance) {
578
- const scrollEl = Utils.getScrollElement(el);
579
- if (!scrollEl)
580
- return;
581
- const elRect = el.getBoundingClientRect();
582
- const scrollRect = scrollEl.getBoundingClientRect();
583
- const innerHeightOrClientHeight = (window.innerHeight || document.documentElement.clientHeight);
584
- const offsetDiffDown = elRect.bottom - Math.min(scrollRect.bottom, innerHeightOrClientHeight);
585
- const offsetDiffUp = elRect.top - Math.max(scrollRect.top, 0);
586
- const prevScroll = scrollEl.scrollTop;
587
- if (offsetDiffUp < 0 && distance < 0) {
588
- // scroll up
589
- if (el.offsetHeight > scrollRect.height) {
590
- scrollEl.scrollTop += distance;
591
- }
592
- else {
593
- scrollEl.scrollTop += Math.abs(offsetDiffUp) > Math.abs(distance) ? distance : offsetDiffUp;
594
- }
595
- }
596
- else if (offsetDiffDown > 0 && distance > 0) {
597
- // scroll down
598
- if (el.offsetHeight > scrollRect.height) {
599
- scrollEl.scrollTop += distance;
600
- }
601
- else {
602
- scrollEl.scrollTop += offsetDiffDown > distance ? distance : offsetDiffDown;
603
- }
604
- }
605
- position.top += scrollEl.scrollTop - prevScroll;
606
- }
607
- /**
608
- * @internal Function used to scroll the page.
609
- *
610
- * @param event `MouseEvent` that triggers the resize
611
- * @param el `HTMLElement` that's being resized
612
- * @param distance Distance from the V edges to start scrolling
613
- */
614
- static updateScrollResize(event, el, distance) {
615
- const scrollEl = Utils.getScrollElement(el);
616
- const height = scrollEl.clientHeight;
617
- // #1727 event.clientY is relative to viewport, so must compare this against position of scrollEl getBoundingClientRect().top
618
- // #1745 Special situation if scrollEl is document 'html': here browser spec states that
619
- // clientHeight is height of viewport, but getBoundingClientRect() is rectangle of html element;
620
- // this discrepancy arises because in reality scrollbar is attached to viewport, not html element itself.
621
- const offsetTop = (scrollEl === Utils.getScrollElement()) ? 0 : scrollEl.getBoundingClientRect().top;
622
- const pointerPosY = event.clientY - offsetTop;
623
- const top = pointerPosY < distance;
624
- const bottom = pointerPosY > height - distance;
625
- if (top) {
626
- // This also can be done with a timeout to keep scrolling while the mouse is
627
- // in the scrolling zone. (will have smoother behavior)
628
- scrollEl.scrollBy({ behavior: 'smooth', top: pointerPosY - distance });
629
- }
630
- else if (bottom) {
631
- scrollEl.scrollBy({ behavior: 'smooth', top: distance - (height - pointerPosY) });
632
- }
633
- }
634
- /** single level clone, returning a new object with same top fields. This will share sub objects and arrays */
635
- static clone(obj) {
636
- if (obj === null || obj === undefined || typeof (obj) !== 'object') {
637
- return obj;
638
- }
639
- // return Object.assign({}, obj);
640
- if (obj instanceof Array) {
641
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
642
- return [...obj];
643
- }
644
- return { ...obj };
645
- }
646
- /**
647
- * Recursive clone version that returns a full copy, checking for nested objects and arrays ONLY.
648
- * Note: this will use as-is any key starting with double __ (and not copy inside) some lib have circular dependencies.
649
- */
650
- static cloneDeep(obj) {
651
- // list of fields we will skip during cloneDeep (nested objects, other internal)
652
- const skipFields = ['parentGrid', 'el', 'grid', 'subGrid', 'engine'];
653
- // return JSON.parse(JSON.stringify(obj)); // doesn't work with date format ?
654
- const ret = Utils.clone(obj);
655
- for (const key in ret) {
656
- // NOTE: we don't support function/circular dependencies so skip those properties for now...
657
- if (ret.hasOwnProperty(key) && typeof (ret[key]) === 'object' && key.substring(0, 2) !== '__' && !skipFields.find(k => k === key)) {
658
- ret[key] = Utils.cloneDeep(obj[key]);
659
- }
660
- }
661
- return ret;
662
- }
663
- /** deep clone the given HTML node, removing teh unique id field */
664
- static cloneNode(el) {
665
- const node = el.cloneNode(true);
666
- node.removeAttribute('id');
667
- return node;
668
- }
669
- static appendTo(el, parent) {
670
- let parentNode;
671
- if (typeof parent === 'string') {
672
- parentNode = Utils.getElement(parent);
673
- }
674
- else {
675
- parentNode = parent;
676
- }
677
- if (parentNode) {
678
- parentNode.appendChild(el);
679
- }
680
- }
681
- // public static setPositionRelative(el: HTMLElement): void {
682
- // if (!(/^(?:r|a|f)/).test(getComputedStyle(el).position)) {
683
- // el.style.position = "relative";
684
- // }
685
- // }
686
- static addElStyles(el, styles) {
687
- if (styles instanceof Object) {
688
- for (const s in styles) {
689
- if (styles.hasOwnProperty(s)) {
690
- if (Array.isArray(styles[s])) {
691
- // support fallback value
692
- styles[s].forEach(val => {
693
- el.style[s] = val;
694
- });
695
- }
696
- else {
697
- el.style[s] = styles[s];
698
- }
699
- }
700
- }
701
- }
702
- }
703
- static initEvent(e, info) {
704
- const evt = { type: info.type };
705
- const obj = {
706
- button: 0,
707
- which: 0,
708
- buttons: 1,
709
- bubbles: true,
710
- cancelable: true,
711
- target: info.target ? info.target : e.target
712
- };
713
- ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].forEach(p => evt[p] = e[p]); // keys
714
- ['pageX', 'pageY', 'clientX', 'clientY', 'screenX', 'screenY'].forEach(p => evt[p] = e[p]); // point info
715
- return { ...evt, ...obj };
716
- }
717
- /** copies the MouseEvent (or convert Touch) properties and sends it as another event to the given target */
718
- static simulateMouseEvent(e, simulatedType, target) {
719
- const me = e;
720
- const simulatedEvent = new MouseEvent(simulatedType, {
721
- bubbles: true,
722
- composed: true,
723
- cancelable: true,
724
- view: window,
725
- detail: 1,
726
- screenX: e.screenX,
727
- screenY: e.screenY,
728
- clientX: e.clientX,
729
- clientY: e.clientY,
730
- ctrlKey: me.ctrlKey ?? false,
731
- altKey: me.altKey ?? false,
732
- shiftKey: me.shiftKey ?? false,
733
- metaKey: me.metaKey ?? false,
734
- button: 0,
735
- relatedTarget: e.target
736
- });
737
- (target || e.target).dispatchEvent(simulatedEvent);
738
- }
739
- /**
740
- * defines an element that is used to get the offset and scale from grid transforms
741
- * returns the scale and offsets from said element
742
- */
743
- static getValuesFromTransformedElement(parent) {
744
- const transformReference = document.createElement('div');
745
- Utils.addElStyles(transformReference, {
746
- opacity: '0',
747
- position: 'fixed',
748
- top: 0 + 'px',
749
- left: 0 + 'px',
750
- width: '1px',
751
- height: '1px',
752
- zIndex: '-999999',
753
- });
754
- parent.appendChild(transformReference);
755
- const transformValues = transformReference.getBoundingClientRect();
756
- parent.removeChild(transformReference);
757
- transformReference.remove();
758
- return {
759
- xScale: 1 / transformValues.width,
760
- yScale: 1 / transformValues.height,
761
- xOffset: transformValues.left,
762
- yOffset: transformValues.top,
763
- };
764
- }
765
- /** swap the given object 2 field values */
766
- static swap(o, a, b) {
767
- if (!o)
768
- return;
769
- const tmp = o[a];
770
- o[a] = o[b];
771
- o[b] = tmp;
772
- }
773
- /** returns true if event is inside the given element rectangle */
774
- // Note: Safari Mac has null event.relatedTarget which causes #1684 so check if DragEvent is inside the coordinates instead
775
- // Utils.el.contains(event.relatedTarget as HTMLElement)
776
- // public static inside(e: MouseEvent, el: HTMLElement): boolean {
777
- // // srcElement, toElement, target: all set to placeholder when leaving simple grid, so we can't use that (Chrome)
778
- // const target: HTMLElement = e.relatedTarget || (e as any).fromElement;
779
- // if (!target) {
780
- // const { bottom, left, right, top } = el.getBoundingClientRect();
781
- // return (e.x < right && e.x > left && e.y < bottom && e.y > top);
782
- // }
783
- // return el.contains(target);
784
- // }
785
- /** true if the item can be rotated (checking for prop, not space available) */
786
- static canBeRotated(n) {
787
- return !(!n || n.w === n.h || n.locked || n.noResize || n.grid?.opts.disableResize || (n.minW && n.minW === n.maxW) || (n.minH && n.minH === n.maxH));
788
- }
789
- }
790
- //# sourceMappingURL=utils.js.map