N°8641 - Dashboard editor front-end first commit for Form SDK integration.

* No dashlet edition
* Dashboard are not persisted
* Unable to load a dashboard from an endpoint (refresh)
* Grid library need proper npm integration
This commit is contained in:
Stephen Abello
2026-01-06 15:23:51 +01:00
parent 3e879c64a7
commit a713e1b56e
167 changed files with 32266 additions and 763 deletions

69
node_modules/gridstack/dist/src/dd-base-impl.d.ts generated vendored Normal file
View File

@@ -0,0 +1,69 @@
/**
* dd-base-impl.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
/**
* Type for event callback functions used in drag & drop operations.
* Can return boolean to indicate if the event should continue propagation.
*/
export type EventCallback = (event: Event) => boolean | void;
/**
* Abstract base class for all drag & drop implementations.
* Provides common functionality for event handling, enable/disable state,
* and lifecycle management used by draggable, droppable, and resizable implementations.
*/
export declare abstract class DDBaseImplement {
/**
* Returns the current disabled state.
* Note: Use enable()/disable() methods to change state as other operations need to happen.
*/
get disabled(): boolean;
/**
* Register an event callback for the specified event.
*
* @param event - Event name to listen for
* @param callback - Function to call when event occurs
*/
on(event: string, callback: EventCallback): void;
/**
* Unregister an event callback for the specified event.
*
* @param event - Event name to stop listening for
*/
off(event: string): void;
/**
* Enable this drag & drop implementation.
* Subclasses should override to perform additional setup.
*/
enable(): void;
/**
* Disable this drag & drop implementation.
* Subclasses should override to perform additional cleanup.
*/
disable(): void;
/**
* Destroy this drag & drop implementation and clean up resources.
* Removes all event handlers and clears internal state.
*/
destroy(): void;
/**
* Trigger a registered event callback if one exists and the implementation is enabled.
*
* @param eventName - Name of the event to trigger
* @param event - DOM event object to pass to the callback
* @returns Result from the callback function, if any
*/
triggerEvent(eventName: string, event: Event): boolean | void;
}
/**
* Interface for HTML elements extended with drag & drop options.
* Used to associate DD configuration with DOM elements.
*/
export interface HTMLElementExtendOpt<T> {
/** The HTML element being extended */
el: HTMLElement;
/** The drag & drop options/configuration */
option: T;
/** Method to update the options and return the DD implementation */
updateOption(T: any): DDBaseImplement;
}

70
node_modules/gridstack/dist/src/dd-base-impl.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
/**
* dd-base-impl.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
/**
* Abstract base class for all drag & drop implementations.
* Provides common functionality for event handling, enable/disable state,
* and lifecycle management used by draggable, droppable, and resizable implementations.
*/
export class DDBaseImplement {
constructor() {
/** @internal */
this._eventRegister = {};
}
/**
* Returns the current disabled state.
* Note: Use enable()/disable() methods to change state as other operations need to happen.
*/
get disabled() { return this._disabled; }
/**
* Register an event callback for the specified event.
*
* @param event - Event name to listen for
* @param callback - Function to call when event occurs
*/
on(event, callback) {
this._eventRegister[event] = callback;
}
/**
* Unregister an event callback for the specified event.
*
* @param event - Event name to stop listening for
*/
off(event) {
delete this._eventRegister[event];
}
/**
* Enable this drag & drop implementation.
* Subclasses should override to perform additional setup.
*/
enable() {
this._disabled = false;
}
/**
* Disable this drag & drop implementation.
* Subclasses should override to perform additional cleanup.
*/
disable() {
this._disabled = true;
}
/**
* Destroy this drag & drop implementation and clean up resources.
* Removes all event handlers and clears internal state.
*/
destroy() {
delete this._eventRegister;
}
/**
* Trigger a registered event callback if one exists and the implementation is enabled.
*
* @param eventName - Name of the event to trigger
* @param event - DOM event object to pass to the callback
* @returns Result from the callback function, if any
*/
triggerEvent(eventName, event) {
if (!this.disabled && this._eventRegister && this._eventRegister[eventName])
return this._eventRegister[eventName](event);
}
}
//# sourceMappingURL=dd-base-impl.js.map

1
node_modules/gridstack/dist/src/dd-base-impl.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"dd-base-impl.js","sourceRoot":"","sources":["../../src/dd-base-impl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;GAIG;AACH,MAAM,OAAgB,eAAe;IAArC;QASE,gBAAgB;QACN,mBAAc,GAEpB,EAAE,CAAC;IAwDT,CAAC;IAnEC;;;OAGG;IACH,IAAW,QAAQ,KAAgB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAS3D;;;;;OAKG;IACI,EAAE,CAAC,KAAa,EAAE,QAAuB;QAC9C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IACxC,CAAC;IAED;;;;OAIG;IACI,GAAG,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED;;;OAGG;IACI,MAAM;QACX,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;;OAGG;IACI,OAAO;QACZ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED;;;OAGG;IACI,OAAO;QACZ,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;;;;;OAMG;IACI,YAAY,CAAC,SAAiB,EAAE,KAAY;QACjD,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;YACzE,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["/**\n * dd-base-impl.ts 12.3.3\n * Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license\n */\n\n/**\n * Type for event callback functions used in drag & drop operations.\n * Can return boolean to indicate if the event should continue propagation.\n */\nexport type EventCallback = (event: Event) => boolean|void;\n\n/**\n * Abstract base class for all drag & drop implementations.\n * Provides common functionality for event handling, enable/disable state,\n * and lifecycle management used by draggable, droppable, and resizable implementations.\n */\nexport abstract class DDBaseImplement {\n /**\n * Returns the current disabled state.\n * Note: Use enable()/disable() methods to change state as other operations need to happen.\n */\n public get disabled(): boolean { return this._disabled; }\n\n /** @internal */\n protected _disabled: boolean; // initial state to differentiate from false\n /** @internal */\n protected _eventRegister: {\n [eventName: string]: EventCallback;\n } = {};\n\n /**\n * Register an event callback for the specified event.\n *\n * @param event - Event name to listen for\n * @param callback - Function to call when event occurs\n */\n public on(event: string, callback: EventCallback): void {\n this._eventRegister[event] = callback;\n }\n\n /**\n * Unregister an event callback for the specified event.\n *\n * @param event - Event name to stop listening for\n */\n public off(event: string): void {\n delete this._eventRegister[event];\n }\n\n /**\n * Enable this drag & drop implementation.\n * Subclasses should override to perform additional setup.\n */\n public enable(): void {\n this._disabled = false;\n }\n\n /**\n * Disable this drag & drop implementation.\n * Subclasses should override to perform additional cleanup.\n */\n public disable(): void {\n this._disabled = true;\n }\n\n /**\n * Destroy this drag & drop implementation and clean up resources.\n * Removes all event handlers and clears internal state.\n */\n public destroy(): void {\n delete this._eventRegister;\n }\n\n /**\n * Trigger a registered event callback if one exists and the implementation is enabled.\n *\n * @param eventName - Name of the event to trigger\n * @param event - DOM event object to pass to the callback\n * @returns Result from the callback function, if any\n */\n public triggerEvent(eventName: string, event: Event): boolean|void {\n if (!this.disabled && this._eventRegister && this._eventRegister[eventName])\n return this._eventRegister[eventName](event);\n }\n}\n\n/**\n * Interface for HTML elements extended with drag & drop options.\n * Used to associate DD configuration with DOM elements.\n */\nexport interface HTMLElementExtendOpt<T> {\n /** The HTML element being extended */\n el: HTMLElement;\n /** The drag & drop options/configuration */\n option: T;\n /** Method to update the options and return the DD implementation */\n updateOption(T): DDBaseImplement;\n}\n"]}

20
node_modules/gridstack/dist/src/dd-draggable.d.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/**
* dd-draggable.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
import { GridItemHTMLElement, DDDragOpt } from './types';
type DDDragEvent = 'drag' | 'dragstart' | 'dragstop';
export declare class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt<DDDragOpt> {
el: GridItemHTMLElement;
option: DDDragOpt;
helper: HTMLElement;
constructor(el: GridItemHTMLElement, option?: DDDragOpt);
on(event: DDDragEvent, callback: (event: DragEvent) => void): void;
off(event: DDDragEvent): void;
enable(): void;
disable(forDestroy?: boolean): void;
destroy(): void;
updateOption(opts: DDDragOpt): DDDraggable;
}
export {};

364
node_modules/gridstack/dist/src/dd-draggable.js generated vendored Normal file
View File

@@ -0,0 +1,364 @@
/**
* dd-draggable.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDManager } from './dd-manager';
import { Utils } from './utils';
import { DDBaseImplement } from './dd-base-impl';
import { isTouch, touchend, touchmove, touchstart, pointerdown } from './dd-touch';
// make sure we are not clicking on known object that handles mouseDown
const skipMouseDown = 'input,textarea,button,select,option,[contenteditable="true"],.ui-resizable-handle';
// let count = 0; // TEST
class DDDraggable extends DDBaseImplement {
constructor(el, option = {}) {
super();
this.el = el;
this.option = option;
/** @internal */
this.dragTransform = {
xScale: 1,
yScale: 1,
xOffset: 0,
yOffset: 0
};
// get the element that is actually supposed to be dragged by
const handleName = option?.handle?.substring(1);
const n = el.gridstackNode;
this.dragEls = !handleName || el.classList.contains(handleName) ? [el] : (n?.subGrid ? [el.querySelector(option.handle) || el] : Array.from(el.querySelectorAll(option.handle)));
if (this.dragEls.length === 0) {
this.dragEls = [el];
}
// create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions)
this._mouseDown = this._mouseDown.bind(this);
this._mouseMove = this._mouseMove.bind(this);
this._mouseUp = this._mouseUp.bind(this);
this._keyEvent = this._keyEvent.bind(this);
this.enable();
}
on(event, callback) {
super.on(event, callback);
}
off(event) {
super.off(event);
}
enable() {
if (this.disabled === false)
return;
super.enable();
this.dragEls.forEach(dragEl => {
dragEl.addEventListener('mousedown', this._mouseDown);
if (isTouch) {
dragEl.addEventListener('touchstart', touchstart);
dragEl.addEventListener('pointerdown', pointerdown);
// dragEl.style.touchAction = 'none'; // not needed unlike pointerdown doc comment
}
});
this.el.classList.remove('ui-draggable-disabled');
}
disable(forDestroy = false) {
if (this.disabled === true)
return;
super.disable();
this.dragEls.forEach(dragEl => {
dragEl.removeEventListener('mousedown', this._mouseDown);
if (isTouch) {
dragEl.removeEventListener('touchstart', touchstart);
dragEl.removeEventListener('pointerdown', pointerdown);
}
});
if (!forDestroy)
this.el.classList.add('ui-draggable-disabled');
}
destroy() {
if (this.dragTimeout)
window.clearTimeout(this.dragTimeout);
delete this.dragTimeout;
if (this.mouseDownEvent)
this._mouseUp(this.mouseDownEvent);
this.disable(true);
delete this.el;
delete this.helper;
delete this.option;
super.destroy();
}
updateOption(opts) {
Object.keys(opts).forEach(key => this.option[key] = opts[key]);
return this;
}
/** @internal call when mouse goes down before a dragstart happens */
_mouseDown(e) {
// don't let more than one widget handle mouseStart
if (DDManager.mouseHandled)
return;
if (e.button !== 0)
return true; // only left click
// make sure we are not clicking on known object that handles mouseDown, or ones supplied by the user
if (!this.dragEls.find(el => el === e.target) && e.target.closest(skipMouseDown))
return true;
if (this.option.cancel) {
if (e.target.closest(this.option.cancel))
return true;
}
this.mouseDownEvent = e;
delete this.dragging;
delete DDManager.dragElement;
delete DDManager.dropElement;
// document handler so we can continue receiving moves as the item is 'fixed' position, and capture=true so WE get a first crack
document.addEventListener('mousemove', this._mouseMove, { capture: true, passive: true }); // true=capture, not bubble
document.addEventListener('mouseup', this._mouseUp, true);
if (isTouch) {
e.currentTarget.addEventListener('touchmove', touchmove);
e.currentTarget.addEventListener('touchend', touchend);
}
e.preventDefault();
// preventDefault() prevents blur event which occurs just after mousedown event.
// if an editable content has focus, then blur must be call
if (document.activeElement)
document.activeElement.blur();
DDManager.mouseHandled = true;
return true;
}
/** @internal method to call actual drag event */
_callDrag(e) {
if (!this.dragging)
return;
const ev = Utils.initEvent(e, { target: this.el, type: 'drag' });
if (this.option.drag) {
this.option.drag(ev, this.ui());
}
this.triggerEvent('drag', ev);
}
/** @internal called when the main page (after successful mousedown) receives a move event to drag the item around the screen */
_mouseMove(e) {
// console.log(`${count++} move ${e.x},${e.y}`)
const s = this.mouseDownEvent;
this.lastDrag = e;
if (this.dragging) {
this._dragFollow(e);
// delay actual grid handling drag until we pause for a while if set
if (DDManager.pauseDrag) {
const pause = Number.isInteger(DDManager.pauseDrag) ? DDManager.pauseDrag : 100;
if (this.dragTimeout)
window.clearTimeout(this.dragTimeout);
this.dragTimeout = window.setTimeout(() => this._callDrag(e), pause);
}
else {
this._callDrag(e);
}
}
else if (Math.abs(e.x - s.x) + Math.abs(e.y - s.y) > 3) {
/**
* don't start unless we've moved at least 3 pixels
*/
this.dragging = true;
DDManager.dragElement = this;
// if we're dragging an actual grid item, set the current drop as the grid (to detect enter/leave)
const grid = this.el.gridstackNode?.grid;
if (grid) {
DDManager.dropElement = grid.el.ddElement.ddDroppable;
}
else {
delete DDManager.dropElement;
}
this.helper = this._createHelper();
this._setupHelperContainmentStyle();
this.dragTransform = Utils.getValuesFromTransformedElement(this.helperContainment);
this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment);
this._setupHelperStyle(e);
const ev = Utils.initEvent(e, { target: this.el, type: 'dragstart' });
if (this.option.start) {
this.option.start(ev, this.ui());
}
this.triggerEvent('dragstart', ev);
// now track keyboard events to cancel or rotate
document.addEventListener('keydown', this._keyEvent);
}
// e.preventDefault(); // passive = true. OLD: was needed otherwise we get text sweep text selection as we drag around
return true;
}
/** @internal call when the mouse gets released to drop the item at current location */
_mouseUp(e) {
document.removeEventListener('mousemove', this._mouseMove, true);
document.removeEventListener('mouseup', this._mouseUp, true);
if (isTouch && e.currentTarget) { // destroy() during nested grid call us again wit fake _mouseUp
e.currentTarget.removeEventListener('touchmove', touchmove, true);
e.currentTarget.removeEventListener('touchend', touchend, true);
}
if (this.dragging) {
delete this.dragging;
delete this.el.gridstackNode?._origRotate;
document.removeEventListener('keydown', this._keyEvent);
// reset the drop target if dragging over ourself (already parented, just moving during stop callback below)
if (DDManager.dropElement?.el === this.el.parentElement) {
delete DDManager.dropElement;
}
this.helperContainment.style.position = this.parentOriginStylePosition || null;
if (this.helper !== this.el)
this.helper.remove(); // hide now
this._removeHelperStyle();
const ev = Utils.initEvent(e, { target: this.el, type: 'dragstop' });
if (this.option.stop) {
this.option.stop(ev); // NOTE: destroy() will be called when removing item, so expect NULL ptr after!
}
this.triggerEvent('dragstop', ev);
// call the droppable method to receive the item
if (DDManager.dropElement) {
DDManager.dropElement.drop(e);
}
}
delete this.helper;
delete this.mouseDownEvent;
delete DDManager.dragElement;
delete DDManager.dropElement;
delete DDManager.mouseHandled;
e.preventDefault();
}
/** @internal call when keys are being pressed - use Esc to cancel, R to rotate */
_keyEvent(e) {
const n = this.el.gridstackNode;
const grid = n?.grid || DDManager.dropElement?.el?.gridstack;
if (e.key === 'Escape') {
if (n && n._origRotate) {
n._orig = n._origRotate;
delete n._origRotate;
}
grid?.cancelDrag();
this._mouseUp(this.mouseDownEvent);
}
else if (n && grid && (e.key === 'r' || e.key === 'R')) {
if (!Utils.canBeRotated(n))
return;
n._origRotate = n._origRotate || { ...n._orig }; // store the real orig size in case we Esc after doing rotation
delete n._moving; // force rotate to happen (move waits for >50% coverage otherwise)
grid.setAnimation(false) // immediate rotate so _getDragOffset() gets the right dom size below
.rotate(n.el, { top: -this.dragOffset.offsetTop, left: -this.dragOffset.offsetLeft })
.setAnimation();
n._moving = true;
this.dragOffset = this._getDragOffset(this.lastDrag, n.el, this.helperContainment);
this.helper.style.width = this.dragOffset.width + 'px';
this.helper.style.height = this.dragOffset.height + 'px';
Utils.swap(n._orig, 'w', 'h');
delete n._rect;
this._mouseMove(this.lastDrag);
}
}
/** @internal create a clone copy (or user defined method) of the original drag item if set */
_createHelper() {
let helper = this.el;
if (typeof this.option.helper === 'function') {
helper = this.option.helper(this.el);
}
else if (this.option.helper === 'clone') {
helper = Utils.cloneNode(this.el);
}
if (!helper.parentElement) {
Utils.appendTo(helper, this.option.appendTo === 'parent' ? this.el.parentElement : this.option.appendTo);
}
this.dragElementOriginStyle = DDDraggable.originStyleProp.map(prop => this.el.style[prop]);
return helper;
}
/** @internal set the fix position of the dragged item */
_setupHelperStyle(e) {
this.helper.classList.add('ui-draggable-dragging');
this.el.gridstackNode?.grid?.el.classList.add('grid-stack-dragging');
// TODO: set all at once with style.cssText += ... ? https://stackoverflow.com/questions/3968593
const style = this.helper.style;
style.pointerEvents = 'none'; // needed for over items to get enter/leave
// style.cursor = 'move'; // TODO: can't set with pointerEvents=none ! (no longer in CSS either as no-op)
style.width = this.dragOffset.width + 'px';
style.height = this.dragOffset.height + 'px';
style.willChange = 'left, top';
style.position = 'fixed'; // let us drag between grids by not clipping as parent .grid-stack is position: 'relative'
this._dragFollow(e); // now position it
style.transition = 'none'; // show up instantly
setTimeout(() => {
if (this.helper) {
style.transition = null; // recover animation
}
}, 0);
return this;
}
/** @internal restore back the original style before dragging */
_removeHelperStyle() {
this.helper.classList.remove('ui-draggable-dragging');
this.el.gridstackNode?.grid?.el.classList.remove('grid-stack-dragging');
const node = this.helper?.gridstackNode;
// don't bother restoring styles if we're gonna remove anyway...
if (!node?._isAboutToRemove && this.dragElementOriginStyle) {
const helper = this.helper;
// don't animate, otherwise we animate offseted when switching back to 'absolute' from 'fixed'.
// TODO: this also removes resizing animation which doesn't have this issue, but others.
// Ideally both would animate ('move' would immediately restore 'absolute' and adjust coordinate to match,
// then trigger a delay (repaint) to restore to final dest with animate) but then we need to make sure 'resizestop'
// is called AFTER 'transitionend' event is received (see https://github.com/gridstack/gridstack.js/issues/2033)
const transition = this.dragElementOriginStyle['transition'] || null;
helper.style.transition = this.dragElementOriginStyle['transition'] = 'none'; // can't be NULL #1973
DDDraggable.originStyleProp.forEach(prop => helper.style[prop] = this.dragElementOriginStyle[prop] || null);
setTimeout(() => helper.style.transition = transition, 50); // recover animation from saved vars after a pause (0 isn't enough #1973)
}
delete this.dragElementOriginStyle;
return this;
}
/** @internal updates the top/left position to follow the mouse */
_dragFollow(e) {
const containmentRect = { left: 0, top: 0 };
// if (this.helper.style.position === 'absolute') { // we use 'fixed'
// const { left, top } = this.helperContainment.getBoundingClientRect();
// containmentRect = { left, top };
// }
const style = this.helper.style;
const offset = this.dragOffset;
style.left = (e.clientX + offset.offsetLeft - containmentRect.left) * this.dragTransform.xScale + 'px';
style.top = (e.clientY + offset.offsetTop - containmentRect.top) * this.dragTransform.yScale + 'px';
}
/** @internal */
_setupHelperContainmentStyle() {
this.helperContainment = this.helper.parentElement;
if (this.helper.style.position !== 'fixed') {
this.parentOriginStylePosition = this.helperContainment.style.position;
if (getComputedStyle(this.helperContainment).position.match(/static/)) {
this.helperContainment.style.position = 'relative';
}
}
return this;
}
/** @internal */
_getDragOffset(event, el, parent) {
// in case ancestor has transform/perspective css properties that change the viewpoint
let xformOffsetX = 0;
let xformOffsetY = 0;
if (parent) {
xformOffsetX = this.dragTransform.xOffset;
xformOffsetY = this.dragTransform.yOffset;
}
const targetOffset = el.getBoundingClientRect();
return {
left: targetOffset.left,
top: targetOffset.top,
offsetLeft: -event.clientX + targetOffset.left - xformOffsetX,
offsetTop: -event.clientY + targetOffset.top - xformOffsetY,
width: targetOffset.width * this.dragTransform.xScale,
height: targetOffset.height * this.dragTransform.yScale
};
}
/** @internal TODO: set to public as called by DDDroppable! */
ui() {
const containmentEl = this.el.parentElement;
const containmentRect = containmentEl.getBoundingClientRect();
const offset = this.helper.getBoundingClientRect();
return {
position: {
top: (offset.top - containmentRect.top) * this.dragTransform.yScale,
left: (offset.left - containmentRect.left) * this.dragTransform.xScale
}
/* not used by GridStack for now...
helper: [this.helper], //The object arr representing the helper that's being dragged.
offset: { top: offset.top, left: offset.left } // Current offset position of the helper as { top, left } object.
*/
};
}
}
/** @internal properties we change during dragging, and restore back */
DDDraggable.originStyleProp = ['width', 'height', 'transform', 'transform-origin', 'transition', 'pointerEvents', 'position', 'left', 'top', 'minWidth', 'willChange'];
export { DDDraggable };
//# sourceMappingURL=dd-draggable.js.map

1
node_modules/gridstack/dist/src/dd-draggable.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

26
node_modules/gridstack/dist/src/dd-droppable.d.ts generated vendored Normal file
View File

@@ -0,0 +1,26 @@
/**
* dd-droppable.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
import { DDUIData } from './types';
export interface DDDroppableOpt {
accept?: string | ((el: HTMLElement) => boolean);
drop?: (event: DragEvent, ui: DDUIData) => void;
over?: (event: DragEvent, ui: DDUIData) => void;
out?: (event: DragEvent, ui: DDUIData) => void;
}
export declare class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt<DDDroppableOpt> {
el: HTMLElement;
option: DDDroppableOpt;
accept: (el: HTMLElement) => boolean;
constructor(el: HTMLElement, option?: DDDroppableOpt);
on(event: 'drop' | 'dropover' | 'dropout', callback: (event: DragEvent) => void): void;
off(event: 'drop' | 'dropover' | 'dropout'): void;
enable(): void;
disable(forDestroy?: boolean): void;
destroy(): void;
updateOption(opts: DDDroppableOpt): DDDroppable;
/** item is being dropped on us - called by the drag mouseup handler - this calls the client drop event */
drop(e: MouseEvent): void;
}

149
node_modules/gridstack/dist/src/dd-droppable.js generated vendored Normal file
View File

@@ -0,0 +1,149 @@
/**
* dd-droppable.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDManager } from './dd-manager';
import { DDBaseImplement } from './dd-base-impl';
import { Utils } from './utils';
import { isTouch, pointerenter, pointerleave } from './dd-touch';
// let count = 0; // TEST
export class DDDroppable extends DDBaseImplement {
constructor(el, option = {}) {
super();
this.el = el;
this.option = option;
// create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions)
this._mouseEnter = this._mouseEnter.bind(this);
this._mouseLeave = this._mouseLeave.bind(this);
this.enable();
this._setupAccept();
}
on(event, callback) {
super.on(event, callback);
}
off(event) {
super.off(event);
}
enable() {
if (this.disabled === false)
return;
super.enable();
this.el.classList.add('ui-droppable');
this.el.classList.remove('ui-droppable-disabled');
this.el.addEventListener('mouseenter', this._mouseEnter);
this.el.addEventListener('mouseleave', this._mouseLeave);
if (isTouch) {
this.el.addEventListener('pointerenter', pointerenter);
this.el.addEventListener('pointerleave', pointerleave);
}
}
disable(forDestroy = false) {
if (this.disabled === true)
return;
super.disable();
this.el.classList.remove('ui-droppable');
if (!forDestroy)
this.el.classList.add('ui-droppable-disabled');
this.el.removeEventListener('mouseenter', this._mouseEnter);
this.el.removeEventListener('mouseleave', this._mouseLeave);
if (isTouch) {
this.el.removeEventListener('pointerenter', pointerenter);
this.el.removeEventListener('pointerleave', pointerleave);
}
}
destroy() {
this.disable(true);
this.el.classList.remove('ui-droppable');
this.el.classList.remove('ui-droppable-disabled');
super.destroy();
}
updateOption(opts) {
Object.keys(opts).forEach(key => this.option[key] = opts[key]);
this._setupAccept();
return this;
}
/** @internal called when the cursor enters our area - prepare for a possible drop and track leaving */
_mouseEnter(e) {
// console.log(`${count++} Enter ${this.el.id || (this.el as GridHTMLElement).gridstack.opts.id}`); // TEST
if (!DDManager.dragElement)
return;
if (!this._canDrop(DDManager.dragElement.el))
return;
e.preventDefault();
e.stopPropagation();
// make sure when we enter this, that the last one gets a leave FIRST to correctly cleanup as we don't always do
if (DDManager.dropElement && DDManager.dropElement !== this) {
DDManager.dropElement._mouseLeave(e, true); // calledByEnter = true
}
DDManager.dropElement = this;
const ev = Utils.initEvent(e, { target: this.el, type: 'dropover' });
if (this.option.over) {
this.option.over(ev, this._ui(DDManager.dragElement));
}
this.triggerEvent('dropover', ev);
this.el.classList.add('ui-droppable-over');
// console.log('tracking'); // TEST
}
/** @internal called when the item is leaving our area, stop tracking if we had moving item */
_mouseLeave(e, calledByEnter = false) {
// console.log(`${count++} Leave ${this.el.id || (this.el as GridHTMLElement).gridstack.opts.id}`); // TEST
if (!DDManager.dragElement || DDManager.dropElement !== this)
return;
e.preventDefault();
e.stopPropagation();
const ev = Utils.initEvent(e, { target: this.el, type: 'dropout' });
if (this.option.out) {
this.option.out(ev, this._ui(DDManager.dragElement));
}
this.triggerEvent('dropout', ev);
if (DDManager.dropElement === this) {
delete DDManager.dropElement;
// console.log('not tracking'); // TEST
// if we're still over a parent droppable, send it an enter as we don't get one from leaving nested children
if (!calledByEnter) {
let parentDrop;
let parent = this.el.parentElement;
while (!parentDrop && parent) {
parentDrop = parent.ddElement?.ddDroppable;
parent = parent.parentElement;
}
if (parentDrop) {
parentDrop._mouseEnter(e);
}
}
}
}
/** item is being dropped on us - called by the drag mouseup handler - this calls the client drop event */
drop(e) {
e.preventDefault();
const ev = Utils.initEvent(e, { target: this.el, type: 'drop' });
if (this.option.drop) {
this.option.drop(ev, this._ui(DDManager.dragElement));
}
this.triggerEvent('drop', ev);
}
/** @internal true if element matches the string/method accept option */
_canDrop(el) {
return el && (!this.accept || this.accept(el));
}
/** @internal */
_setupAccept() {
if (!this.option.accept)
return this;
if (typeof this.option.accept === 'string') {
this.accept = (el) => el.classList.contains(this.option.accept) || el.matches(this.option.accept);
}
else {
this.accept = this.option.accept;
}
return this;
}
/** @internal */
_ui(drag) {
return {
draggable: drag.el,
...drag.ui()
};
}
}
//# sourceMappingURL=dd-droppable.js.map

1
node_modules/gridstack/dist/src/dd-droppable.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

27
node_modules/gridstack/dist/src/dd-element.d.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
/**
* dd-elements.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDResizable, DDResizableOpt } from './dd-resizable';
import { DDDragOpt, GridItemHTMLElement } from './types';
import { DDDraggable } from './dd-draggable';
import { DDDroppable, DDDroppableOpt } from './dd-droppable';
export interface DDElementHost extends GridItemHTMLElement {
ddElement?: DDElement;
}
export declare class DDElement {
el: DDElementHost;
static init(el: DDElementHost): DDElement;
ddDraggable?: DDDraggable;
ddDroppable?: DDDroppable;
ddResizable?: DDResizable;
constructor(el: DDElementHost);
on(eventName: string, callback: (event: MouseEvent) => void): DDElement;
off(eventName: string): DDElement;
setupDraggable(opts: DDDragOpt): DDElement;
cleanDraggable(): DDElement;
setupResizable(opts: DDResizableOpt): DDElement;
cleanResizable(): DDElement;
setupDroppable(opts: DDDroppableOpt): DDElement;
cleanDroppable(): DDElement;
}

91
node_modules/gridstack/dist/src/dd-element.js generated vendored Normal file
View File

@@ -0,0 +1,91 @@
/**
* dd-elements.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDResizable } from './dd-resizable';
import { DDDraggable } from './dd-draggable';
import { DDDroppable } from './dd-droppable';
export class DDElement {
static init(el) {
if (!el.ddElement) {
el.ddElement = new DDElement(el);
}
return el.ddElement;
}
constructor(el) {
this.el = el;
}
on(eventName, callback) {
if (this.ddDraggable && ['drag', 'dragstart', 'dragstop'].indexOf(eventName) > -1) {
this.ddDraggable.on(eventName, callback);
}
else if (this.ddDroppable && ['drop', 'dropover', 'dropout'].indexOf(eventName) > -1) {
this.ddDroppable.on(eventName, callback);
}
else if (this.ddResizable && ['resizestart', 'resize', 'resizestop'].indexOf(eventName) > -1) {
this.ddResizable.on(eventName, callback);
}
return this;
}
off(eventName) {
if (this.ddDraggable && ['drag', 'dragstart', 'dragstop'].indexOf(eventName) > -1) {
this.ddDraggable.off(eventName);
}
else if (this.ddDroppable && ['drop', 'dropover', 'dropout'].indexOf(eventName) > -1) {
this.ddDroppable.off(eventName);
}
else if (this.ddResizable && ['resizestart', 'resize', 'resizestop'].indexOf(eventName) > -1) {
this.ddResizable.off(eventName);
}
return this;
}
setupDraggable(opts) {
if (!this.ddDraggable) {
this.ddDraggable = new DDDraggable(this.el, opts);
}
else {
this.ddDraggable.updateOption(opts);
}
return this;
}
cleanDraggable() {
if (this.ddDraggable) {
this.ddDraggable.destroy();
delete this.ddDraggable;
}
return this;
}
setupResizable(opts) {
if (!this.ddResizable) {
this.ddResizable = new DDResizable(this.el, opts);
}
else {
this.ddResizable.updateOption(opts);
}
return this;
}
cleanResizable() {
if (this.ddResizable) {
this.ddResizable.destroy();
delete this.ddResizable;
}
return this;
}
setupDroppable(opts) {
if (!this.ddDroppable) {
this.ddDroppable = new DDDroppable(this.el, opts);
}
else {
this.ddDroppable.updateOption(opts);
}
return this;
}
cleanDroppable() {
if (this.ddDroppable) {
this.ddDroppable.destroy();
delete this.ddDroppable;
}
return this;
}
}
//# sourceMappingURL=dd-element.js.map

1
node_modules/gridstack/dist/src/dd-element.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

82
node_modules/gridstack/dist/src/dd-gridstack.d.ts generated vendored Normal file
View File

@@ -0,0 +1,82 @@
/**
* dd-gridstack.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { GridItemHTMLElement, GridStackElement, DDDragOpt } from './types';
import { DDElementHost } from './dd-element';
/**
* Drag & Drop options for drop targets.
* Configures which elements can be dropped onto a grid.
*/
export type DDDropOpt = {
/** Function to determine if an element can be dropped (see GridStackOptions.acceptWidgets) */
accept?: (el: GridItemHTMLElement) => boolean;
};
/**
* Drag & Drop operation types used throughout the DD system.
* Can be control commands or configuration objects.
*/
export type DDOpts = 'enable' | 'disable' | 'destroy' | 'option' | string | any;
/**
* Keys for DD configuration options that can be set via the 'option' command.
*/
export type DDKey = 'minWidth' | 'minHeight' | 'maxWidth' | 'maxHeight' | 'maxHeightMoveUp' | 'maxWidthMoveLeft';
/**
* Values for DD configuration options (numbers or strings with units).
*/
export type DDValue = number | string;
/**
* Callback function type for drag & drop events.
*
* @param event - The DOM event that triggered the callback
* @param arg2 - The grid item element being dragged/dropped
* @param helper - Optional helper element used during drag operations
*/
export type DDCallback = (event: Event, arg2: GridItemHTMLElement, helper?: GridItemHTMLElement) => void;
/**
* HTML Native Mouse and Touch Events Drag and Drop functionality.
*
* This class provides the main drag & drop implementation for GridStack,
* handling resizing, dragging, and dropping of grid items using native HTML5 events.
* It manages the interaction between different DD components and the grid system.
*/
export declare class DDGridStack {
/**
* Enable/disable/configure resizing for grid elements.
*
* @param el - Grid item element(s) to configure
* @param opts - Resize options or command ('enable', 'disable', 'destroy', 'option', or config object)
* @param key - Option key when using 'option' command
* @param value - Option value when using 'option' command
* @returns this instance for chaining
*
* @example
* dd.resizable(element, 'enable'); // Enable resizing
* dd.resizable(element, 'option', 'minWidth', 100); // Set minimum width
*/
resizable(el: GridItemHTMLElement, opts: DDOpts, key?: DDKey, value?: DDValue): DDGridStack;
/**
* Enable/disable/configure dragging for grid elements.
*
* @param el - Grid item element(s) to configure
* @param opts - Drag options or command ('enable', 'disable', 'destroy', 'option', or config object)
* @param key - Option key when using 'option' command
* @param value - Option value when using 'option' command
* @returns this instance for chaining
*
* @example
* dd.draggable(element, 'enable'); // Enable dragging
* dd.draggable(element, {handle: '.drag-handle'}); // Configure drag handle
*/
draggable(el: GridItemHTMLElement, opts: DDOpts, key?: DDKey, value?: DDValue): DDGridStack;
dragIn(el: GridStackElement, opts: DDDragOpt): DDGridStack;
droppable(el: GridItemHTMLElement, opts: DDOpts | DDDropOpt, key?: DDKey, value?: DDValue): DDGridStack;
/** true if element is droppable */
isDroppable(el: DDElementHost): boolean;
/** true if element is draggable */
isDraggable(el: DDElementHost): boolean;
/** true if element is draggable */
isResizable(el: DDElementHost): boolean;
on(el: GridItemHTMLElement, name: string, callback: DDCallback): DDGridStack;
off(el: GridItemHTMLElement, name: string): DDGridStack;
}

165
node_modules/gridstack/dist/src/dd-gridstack.js generated vendored Normal file
View File

@@ -0,0 +1,165 @@
/**
* dd-gridstack.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { Utils } from './utils';
import { DDManager } from './dd-manager';
import { DDElement } from './dd-element';
// let count = 0; // TEST
/**
* HTML Native Mouse and Touch Events Drag and Drop functionality.
*
* This class provides the main drag & drop implementation for GridStack,
* handling resizing, dragging, and dropping of grid items using native HTML5 events.
* It manages the interaction between different DD components and the grid system.
*/
export class DDGridStack {
/**
* Enable/disable/configure resizing for grid elements.
*
* @param el - Grid item element(s) to configure
* @param opts - Resize options or command ('enable', 'disable', 'destroy', 'option', or config object)
* @param key - Option key when using 'option' command
* @param value - Option value when using 'option' command
* @returns this instance for chaining
*
* @example
* dd.resizable(element, 'enable'); // Enable resizing
* dd.resizable(element, 'option', 'minWidth', 100); // Set minimum width
*/
resizable(el, opts, key, value) {
this._getDDElements(el, opts).forEach(dEl => {
if (opts === 'disable' || opts === 'enable') {
dEl.ddResizable && dEl.ddResizable[opts](); // can't create DD as it requires options for setupResizable()
}
else if (opts === 'destroy') {
dEl.ddResizable && dEl.cleanResizable();
}
else if (opts === 'option') {
dEl.setupResizable({ [key]: value });
}
else {
const n = dEl.el.gridstackNode;
const grid = n.grid;
let handles = dEl.el.getAttribute('gs-resize-handles') || grid.opts.resizable.handles || 'e,s,se';
if (handles === 'all')
handles = 'n,e,s,w,se,sw,ne,nw';
// NOTE: keep the resize handles as e,w don't have enough space (10px) to show resize corners anyway. limit during drag instead
// restrict vertical resize if height is done to match content anyway... odd to have it spring back
// if (Utils.shouldSizeToContent(n, true)) {
// const doE = handles.indexOf('e') !== -1;
// const doW = handles.indexOf('w') !== -1;
// handles = doE ? (doW ? 'e,w' : 'e') : (doW ? 'w' : '');
// }
const autoHide = !grid.opts.alwaysShowResizeHandle;
dEl.setupResizable({
...grid.opts.resizable,
...{ handles, autoHide },
...{
start: opts.start,
stop: opts.stop,
resize: opts.resize
}
});
}
});
return this;
}
/**
* Enable/disable/configure dragging for grid elements.
*
* @param el - Grid item element(s) to configure
* @param opts - Drag options or command ('enable', 'disable', 'destroy', 'option', or config object)
* @param key - Option key when using 'option' command
* @param value - Option value when using 'option' command
* @returns this instance for chaining
*
* @example
* dd.draggable(element, 'enable'); // Enable dragging
* dd.draggable(element, {handle: '.drag-handle'}); // Configure drag handle
*/
draggable(el, opts, key, value) {
this._getDDElements(el, opts).forEach(dEl => {
if (opts === 'disable' || opts === 'enable') {
dEl.ddDraggable && dEl.ddDraggable[opts](); // can't create DD as it requires options for setupDraggable()
}
else if (opts === 'destroy') {
dEl.ddDraggable && dEl.cleanDraggable();
}
else if (opts === 'option') {
dEl.setupDraggable({ [key]: value });
}
else {
const grid = dEl.el.gridstackNode.grid;
dEl.setupDraggable({
...grid.opts.draggable,
...{
// containment: (grid.parentGridNode && grid.opts.dragOut === false) ? grid.el.parentElement : (grid.opts.draggable.containment || null),
start: opts.start,
stop: opts.stop,
drag: opts.drag
}
});
}
});
return this;
}
dragIn(el, opts) {
this._getDDElements(el).forEach(dEl => dEl.setupDraggable(opts));
return this;
}
droppable(el, opts, key, value) {
if (typeof opts.accept === 'function' && !opts._accept) {
opts._accept = opts.accept;
opts.accept = (el) => opts._accept(el);
}
this._getDDElements(el, opts).forEach(dEl => {
if (opts === 'disable' || opts === 'enable') {
dEl.ddDroppable && dEl.ddDroppable[opts]();
}
else if (opts === 'destroy') {
dEl.ddDroppable && dEl.cleanDroppable();
}
else if (opts === 'option') {
dEl.setupDroppable({ [key]: value });
}
else {
dEl.setupDroppable(opts);
}
});
return this;
}
/** true if element is droppable */
isDroppable(el) {
return !!(el?.ddElement?.ddDroppable && !el.ddElement.ddDroppable.disabled);
}
/** true if element is draggable */
isDraggable(el) {
return !!(el?.ddElement?.ddDraggable && !el.ddElement.ddDraggable.disabled);
}
/** true if element is draggable */
isResizable(el) {
return !!(el?.ddElement?.ddResizable && !el.ddElement.ddResizable.disabled);
}
on(el, name, callback) {
this._getDDElements(el).forEach(dEl => dEl.on(name, (event) => {
callback(event, DDManager.dragElement ? DDManager.dragElement.el : event.target, DDManager.dragElement ? DDManager.dragElement.helper : null);
}));
return this;
}
off(el, name) {
this._getDDElements(el).forEach(dEl => dEl.off(name));
return this;
}
/** @internal returns a list of DD elements, creating them on the fly by default unless option is to destroy or disable */
_getDDElements(els, opts) {
// don't force create if we're going to destroy it, unless it's a grid which is used as drop target for it's children
const create = els.gridstack || opts !== 'destroy' && opts !== 'disable';
const hosts = Utils.getElements(els);
if (!hosts.length)
return [];
const list = hosts.map(e => e.ddElement || (create ? DDElement.init(e) : null)).filter(d => d); // remove nulls
return list;
}
}
//# sourceMappingURL=dd-gridstack.js.map

1
node_modules/gridstack/dist/src/dd-gridstack.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

43
node_modules/gridstack/dist/src/dd-manager.d.ts generated vendored Normal file
View File

@@ -0,0 +1,43 @@
/**
* dd-manager.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDDraggable } from './dd-draggable';
import { DDDroppable } from './dd-droppable';
import { DDResizable } from './dd-resizable';
/**
* Global state manager for all Drag & Drop instances.
*
* This class maintains shared state across all drag & drop operations,
* ensuring proper coordination between multiple grids and drag/drop elements.
* All properties are static to provide global access throughout the DD system.
*/
export declare class DDManager {
/**
* Controls drag operation pausing behavior.
* If set to true or a number (milliseconds), dragging placement and collision
* detection will only happen after the user pauses movement.
* This improves performance during rapid mouse movements.
*/
static pauseDrag: boolean | number;
/**
* Flag indicating if a mouse down event was already handled.
* Prevents multiple handlers from processing the same mouse event.
*/
static mouseHandled: boolean;
/**
* Reference to the element currently being dragged.
* Used to track the active drag operation across the system.
*/
static dragElement: DDDraggable;
/**
* Reference to the drop target element currently under the cursor.
* Used to handle drop operations and hover effects.
*/
static dropElement: DDDroppable;
/**
* Reference to the element currently being resized.
* Helps ignore nested grid resize handles during resize operations.
*/
static overResizeElement: DDResizable;
}

14
node_modules/gridstack/dist/src/dd-manager.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
/**
* dd-manager.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
/**
* Global state manager for all Drag & Drop instances.
*
* This class maintains shared state across all drag & drop operations,
* ensuring proper coordination between multiple grids and drag/drop elements.
* All properties are static to provide global access throughout the DD system.
*/
export class DDManager {
}
//# sourceMappingURL=dd-manager.js.map

1
node_modules/gridstack/dist/src/dd-manager.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"dd-manager.js","sourceRoot":"","sources":["../../src/dd-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;;;;;GAMG;AACH,MAAM,OAAO,SAAS;CAiCrB","sourcesContent":["/**\n * dd-manager.ts 12.3.3\n * Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license\n */\n\nimport { DDDraggable } from './dd-draggable';\nimport { DDDroppable } from './dd-droppable';\nimport { DDResizable } from './dd-resizable';\n\n/**\n * Global state manager for all Drag & Drop instances.\n *\n * This class maintains shared state across all drag & drop operations,\n * ensuring proper coordination between multiple grids and drag/drop elements.\n * All properties are static to provide global access throughout the DD system.\n */\nexport class DDManager {\n /**\n * Controls drag operation pausing behavior.\n * If set to true or a number (milliseconds), dragging placement and collision\n * detection will only happen after the user pauses movement.\n * This improves performance during rapid mouse movements.\n */\n public static pauseDrag: boolean | number;\n\n /**\n * Flag indicating if a mouse down event was already handled.\n * Prevents multiple handlers from processing the same mouse event.\n */\n public static mouseHandled: boolean;\n\n /**\n * Reference to the element currently being dragged.\n * Used to track the active drag operation across the system.\n */\n public static dragElement: DDDraggable;\n\n /**\n * Reference to the drop target element currently under the cursor.\n * Used to handle drop operations and hover effects.\n */\n public static dropElement: DDDroppable;\n\n /**\n * Reference to the element currently being resized.\n * Helps ignore nested grid resize handles during resize operations.\n */\n public static overResizeElement: DDResizable;\n\n}\n"]}

View File

@@ -0,0 +1,18 @@
/**
* dd-resizable-handle.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { GridItemHTMLElement } from './gridstack';
export interface DDResizableHandleOpt {
start?: (event: any) => void;
move?: (event: any) => void;
stop?: (event: any) => void;
}
export declare class DDResizableHandle {
protected host: GridItemHTMLElement;
protected dir: string;
protected option: DDResizableHandleOpt;
constructor(host: GridItemHTMLElement, dir: string, option: DDResizableHandleOpt);
/** call this when resize handle needs to be removed and cleaned up */
destroy(): DDResizableHandle;
}

113
node_modules/gridstack/dist/src/dd-resizable-handle.js generated vendored Normal file
View File

@@ -0,0 +1,113 @@
/**
* dd-resizable-handle.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { isTouch, pointerdown, touchend, touchmove, touchstart } from './dd-touch';
class DDResizableHandle {
constructor(host, dir, option) {
this.host = host;
this.dir = dir;
this.option = option;
/** @internal true after we've moved enough pixels to start a resize */
this.moving = false;
// create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions)
this._mouseDown = this._mouseDown.bind(this);
this._mouseMove = this._mouseMove.bind(this);
this._mouseUp = this._mouseUp.bind(this);
this._keyEvent = this._keyEvent.bind(this);
this._init();
}
/** @internal */
_init() {
const el = this.el = document.createElement('div');
el.classList.add('ui-resizable-handle');
el.classList.add(`${DDResizableHandle.prefix}${this.dir}`);
el.style.zIndex = '100';
el.style.userSelect = 'none';
this.host.appendChild(this.el);
this.el.addEventListener('mousedown', this._mouseDown);
if (isTouch) {
this.el.addEventListener('touchstart', touchstart);
this.el.addEventListener('pointerdown', pointerdown);
// this.el.style.touchAction = 'none'; // not needed unlike pointerdown doc comment
}
return this;
}
/** call this when resize handle needs to be removed and cleaned up */
destroy() {
if (this.moving)
this._mouseUp(this.mouseDownEvent);
this.el.removeEventListener('mousedown', this._mouseDown);
if (isTouch) {
this.el.removeEventListener('touchstart', touchstart);
this.el.removeEventListener('pointerdown', pointerdown);
}
this.host.removeChild(this.el);
delete this.el;
delete this.host;
return this;
}
/** @internal called on mouse down on us: capture move on the entire document (mouse might not stay on us) until we release the mouse */
_mouseDown(e) {
this.mouseDownEvent = e;
document.addEventListener('mousemove', this._mouseMove, { capture: true, passive: true }); // capture, not bubble
document.addEventListener('mouseup', this._mouseUp, true);
if (isTouch) {
this.el.addEventListener('touchmove', touchmove);
this.el.addEventListener('touchend', touchend);
}
e.stopPropagation();
e.preventDefault();
}
/** @internal */
_mouseMove(e) {
const s = this.mouseDownEvent;
if (this.moving) {
this._triggerEvent('move', e);
}
else if (Math.abs(e.x - s.x) + Math.abs(e.y - s.y) > 2) {
// don't start unless we've moved at least 3 pixels
this.moving = true;
this._triggerEvent('start', this.mouseDownEvent);
this._triggerEvent('move', e);
// now track keyboard events to cancel
document.addEventListener('keydown', this._keyEvent);
}
e.stopPropagation();
// e.preventDefault(); passive = true
}
/** @internal */
_mouseUp(e) {
if (this.moving) {
this._triggerEvent('stop', e);
document.removeEventListener('keydown', this._keyEvent);
}
document.removeEventListener('mousemove', this._mouseMove, true);
document.removeEventListener('mouseup', this._mouseUp, true);
if (isTouch) {
this.el.removeEventListener('touchmove', touchmove);
this.el.removeEventListener('touchend', touchend);
}
delete this.moving;
delete this.mouseDownEvent;
e.stopPropagation();
e.preventDefault();
}
/** @internal call when keys are being pressed - use Esc to cancel */
_keyEvent(e) {
if (e.key === 'Escape') {
this.host.gridstackNode?.grid?.engine.restoreInitial();
this._mouseUp(this.mouseDownEvent);
}
}
/** @internal */
_triggerEvent(name, event) {
if (this.option[name])
this.option[name](event);
return this;
}
}
/** @internal */
DDResizableHandle.prefix = 'ui-resizable-';
export { DDResizableHandle };
//# sourceMappingURL=dd-resizable-handle.js.map

File diff suppressed because one or more lines are too long

30
node_modules/gridstack/dist/src/dd-resizable.d.ts generated vendored Normal file
View File

@@ -0,0 +1,30 @@
/**
* dd-resizable.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
import { DDUIData, GridItemHTMLElement } from './types';
export interface DDResizableOpt {
autoHide?: boolean;
handles?: string;
maxHeight?: number;
maxHeightMoveUp?: number;
maxWidth?: number;
maxWidthMoveLeft?: number;
minHeight?: number;
minWidth?: number;
start?: (event: Event, ui: DDUIData) => void;
stop?: (event: Event) => void;
resize?: (event: Event, ui: DDUIData) => void;
}
export declare class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt<DDResizableOpt> {
el: GridItemHTMLElement;
option: DDResizableOpt;
constructor(el: GridItemHTMLElement, option?: DDResizableOpt);
on(event: 'resizestart' | 'resize' | 'resizestop', callback: (event: DragEvent) => void): void;
off(event: 'resizestart' | 'resize' | 'resizestop'): void;
enable(): void;
disable(): void;
destroy(): void;
updateOption(opts: DDResizableOpt): DDResizable;
}

304
node_modules/gridstack/dist/src/dd-resizable.js generated vendored Normal file
View File

@@ -0,0 +1,304 @@
/**
* dd-resizable.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDResizableHandle } from './dd-resizable-handle';
import { DDBaseImplement } from './dd-base-impl';
import { Utils } from './utils';
import { DDManager } from './dd-manager';
class DDResizable extends DDBaseImplement {
// have to be public else complains for HTMLElementExtendOpt ?
constructor(el, option = {}) {
super();
this.el = el;
this.option = option;
/** @internal */
this.rectScale = { x: 1, y: 1 };
/** @internal */
this._ui = () => {
const containmentEl = this.el.parentElement;
const containmentRect = containmentEl.getBoundingClientRect();
const newRect = {
width: this.originalRect.width,
height: this.originalRect.height + this.scrolled,
left: this.originalRect.left,
top: this.originalRect.top - this.scrolled
};
const rect = this.temporalRect || newRect;
return {
position: {
left: (rect.left - containmentRect.left) * this.rectScale.x,
top: (rect.top - containmentRect.top) * this.rectScale.y
},
size: {
width: rect.width * this.rectScale.x,
height: rect.height * this.rectScale.y
}
/* Gridstack ONLY needs position set above... keep around in case.
element: [this.el], // The object representing the element to be resized
helper: [], // TODO: not support yet - The object representing the helper that's being resized
originalElement: [this.el],// we don't wrap here, so simplify as this.el //The object representing the original element before it is wrapped
originalPosition: { // The position represented as { left, top } before the resizable is resized
left: this.originalRect.left - containmentRect.left,
top: this.originalRect.top - containmentRect.top
},
originalSize: { // The size represented as { width, height } before the resizable is resized
width: this.originalRect.width,
height: this.originalRect.height
}
*/
};
};
// create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions)
this._mouseOver = this._mouseOver.bind(this);
this._mouseOut = this._mouseOut.bind(this);
this.enable();
this._setupAutoHide(this.option.autoHide);
this._setupHandlers();
}
on(event, callback) {
super.on(event, callback);
}
off(event) {
super.off(event);
}
enable() {
super.enable();
this.el.classList.remove('ui-resizable-disabled');
this._setupAutoHide(this.option.autoHide);
}
disable() {
super.disable();
this.el.classList.add('ui-resizable-disabled');
this._setupAutoHide(false);
}
destroy() {
this._removeHandlers();
this._setupAutoHide(false);
delete this.el;
super.destroy();
}
updateOption(opts) {
const updateHandles = (opts.handles && opts.handles !== this.option.handles);
const updateAutoHide = (opts.autoHide && opts.autoHide !== this.option.autoHide);
Object.keys(opts).forEach(key => this.option[key] = opts[key]);
if (updateHandles) {
this._removeHandlers();
this._setupHandlers();
}
if (updateAutoHide) {
this._setupAutoHide(this.option.autoHide);
}
return this;
}
/** @internal turns auto hide on/off */
_setupAutoHide(auto) {
if (auto) {
this.el.classList.add('ui-resizable-autohide');
// use mouseover and not mouseenter to get better performance and track for nested cases
this.el.addEventListener('mouseover', this._mouseOver);
this.el.addEventListener('mouseout', this._mouseOut);
}
else {
this.el.classList.remove('ui-resizable-autohide');
this.el.removeEventListener('mouseover', this._mouseOver);
this.el.removeEventListener('mouseout', this._mouseOut);
if (DDManager.overResizeElement === this) {
delete DDManager.overResizeElement;
}
}
return this;
}
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_mouseOver(e) {
// console.log(`${count++} pre-enter ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
// already over a child, ignore. Ideally we just call e.stopPropagation() but see https://github.com/gridstack/gridstack.js/issues/2018
if (DDManager.overResizeElement || DDManager.dragElement)
return;
DDManager.overResizeElement = this;
// console.log(`${count++} enter ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
this.el.classList.remove('ui-resizable-autohide');
}
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_mouseOut(e) {
// console.log(`${count++} pre-leave ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
if (DDManager.overResizeElement !== this)
return;
delete DDManager.overResizeElement;
// console.log(`${count++} leave ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
this.el.classList.add('ui-resizable-autohide');
}
/** @internal */
_setupHandlers() {
this.handlers = this.option.handles.split(',')
.map(dir => dir.trim())
.map(dir => new DDResizableHandle(this.el, dir, {
start: (event) => {
this._resizeStart(event);
},
stop: (event) => {
this._resizeStop(event);
},
move: (event) => {
this._resizing(event, dir);
}
}));
return this;
}
/** @internal */
_resizeStart(event) {
this.sizeToContent = Utils.shouldSizeToContent(this.el.gridstackNode, true); // strick true only and not number
this.originalRect = this.el.getBoundingClientRect();
this.scrollEl = Utils.getScrollElement(this.el);
this.scrollY = this.scrollEl.scrollTop;
this.scrolled = 0;
this.startEvent = event;
this._setupHelper();
this._applyChange();
const ev = Utils.initEvent(event, { type: 'resizestart', target: this.el });
if (this.option.start) {
this.option.start(ev, this._ui());
}
this.el.classList.add('ui-resizable-resizing');
this.triggerEvent('resizestart', ev);
return this;
}
/** @internal */
_resizing(event, dir) {
this.scrolled = this.scrollEl.scrollTop - this.scrollY;
this.temporalRect = this._getChange(event, dir);
this._applyChange();
const ev = Utils.initEvent(event, { type: 'resize', target: this.el });
if (this.option.resize) {
this.option.resize(ev, this._ui());
}
this.triggerEvent('resize', ev);
return this;
}
/** @internal */
_resizeStop(event) {
const ev = Utils.initEvent(event, { type: 'resizestop', target: this.el });
// Remove style attr now, so the stop handler can rebuild style attrs
this._cleanHelper();
if (this.option.stop) {
this.option.stop(ev); // Note: ui() not used by gridstack so don't pass
}
this.el.classList.remove('ui-resizable-resizing');
this.triggerEvent('resizestop', ev);
delete this.startEvent;
delete this.originalRect;
delete this.temporalRect;
delete this.scrollY;
delete this.scrolled;
return this;
}
/** @internal */
_setupHelper() {
this.elOriginStyleVal = DDResizable._originStyleProp.map(prop => this.el.style[prop]);
this.parentOriginStylePosition = this.el.parentElement.style.position;
const parent = this.el.parentElement;
const dragTransform = Utils.getValuesFromTransformedElement(parent);
this.rectScale = {
x: dragTransform.xScale,
y: dragTransform.yScale
};
if (getComputedStyle(this.el.parentElement).position.match(/static/)) {
this.el.parentElement.style.position = 'relative';
}
this.el.style.position = 'absolute';
this.el.style.opacity = '0.8';
return this;
}
/** @internal */
_cleanHelper() {
DDResizable._originStyleProp.forEach((prop, i) => {
this.el.style[prop] = this.elOriginStyleVal[i] || null;
});
this.el.parentElement.style.position = this.parentOriginStylePosition || null;
return this;
}
/** @internal */
_getChange(event, dir) {
const oEvent = this.startEvent;
const newRect = {
width: this.originalRect.width,
height: this.originalRect.height + this.scrolled,
left: this.originalRect.left,
top: this.originalRect.top - this.scrolled
};
const offsetX = event.clientX - oEvent.clientX;
const offsetY = this.sizeToContent ? 0 : event.clientY - oEvent.clientY; // prevent vert resize
let moveLeft;
let moveUp;
if (dir.indexOf('e') > -1) {
newRect.width += offsetX;
}
else if (dir.indexOf('w') > -1) {
newRect.width -= offsetX;
newRect.left += offsetX;
moveLeft = true;
}
if (dir.indexOf('s') > -1) {
newRect.height += offsetY;
}
else if (dir.indexOf('n') > -1) {
newRect.height -= offsetY;
newRect.top += offsetY;
moveUp = true;
}
const constrain = this._constrainSize(newRect.width, newRect.height, moveLeft, moveUp);
if (Math.round(newRect.width) !== Math.round(constrain.width)) { // round to ignore slight round-off errors
if (dir.indexOf('w') > -1) {
newRect.left += newRect.width - constrain.width;
}
newRect.width = constrain.width;
}
if (Math.round(newRect.height) !== Math.round(constrain.height)) {
if (dir.indexOf('n') > -1) {
newRect.top += newRect.height - constrain.height;
}
newRect.height = constrain.height;
}
return newRect;
}
/** @internal constrain the size to the set min/max values */
_constrainSize(oWidth, oHeight, moveLeft, moveUp) {
const o = this.option;
const maxWidth = (moveLeft ? o.maxWidthMoveLeft : o.maxWidth) || Number.MAX_SAFE_INTEGER;
const minWidth = o.minWidth / this.rectScale.x || oWidth;
const maxHeight = (moveUp ? o.maxHeightMoveUp : o.maxHeight) || Number.MAX_SAFE_INTEGER;
const minHeight = o.minHeight / this.rectScale.y || oHeight;
const width = Math.min(maxWidth, Math.max(minWidth, oWidth));
const height = Math.min(maxHeight, Math.max(minHeight, oHeight));
return { width, height };
}
/** @internal */
_applyChange() {
let containmentRect = { left: 0, top: 0, width: 0, height: 0 };
if (this.el.style.position === 'absolute') {
const containmentEl = this.el.parentElement;
const { left, top } = containmentEl.getBoundingClientRect();
containmentRect = { left, top, width: 0, height: 0 };
}
if (!this.temporalRect)
return this;
Object.keys(this.temporalRect).forEach(key => {
const value = this.temporalRect[key];
const scaleReciprocal = key === 'width' || key === 'left' ? this.rectScale.x : key === 'height' || key === 'top' ? this.rectScale.y : 1;
this.el.style[key] = (value - containmentRect[key]) * scaleReciprocal + 'px';
});
return this;
}
/** @internal */
_removeHandlers() {
this.handlers.forEach(handle => handle.destroy());
delete this.handlers;
return this;
}
}
/** @internal */
DDResizable._originStyleProp = ['width', 'height', 'position', 'left', 'top', 'opacity', 'zIndex'];
export { DDResizable };
//# sourceMappingURL=dd-resizable.js.map

1
node_modules/gridstack/dist/src/dd-resizable.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

33
node_modules/gridstack/dist/src/dd-touch.d.ts generated vendored Normal file
View File

@@ -0,0 +1,33 @@
/**
* touch.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
/**
* Detect touch support - Windows Surface devices and other touch devices
* should we use this instead ? (what we had for always showing resize handles)
* /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
*/
export declare const isTouch: boolean;
/**
* Handle the touchstart events
* @param {Object} e The widget element's touchstart event
*/
export declare function touchstart(e: TouchEvent): void;
/**
* Handle the touchmove events
* @param {Object} e The document's touchmove event
*/
export declare function touchmove(e: TouchEvent): void;
/**
* Handle the touchend events
* @param {Object} e The document's touchend event
*/
export declare function touchend(e: TouchEvent): void;
/**
* Note we don't get touchenter/touchleave (which are deprecated)
* see https://stackoverflow.com/questions/27908339/js-touch-equivalent-for-mouseenter
* so instead of PointerEvent to still get enter/leave and send the matching mouse event.
*/
export declare function pointerdown(e: PointerEvent): void;
export declare function pointerenter(e: PointerEvent): void;
export declare function pointerleave(e: PointerEvent): void;

145
node_modules/gridstack/dist/src/dd-touch.js generated vendored Normal file
View File

@@ -0,0 +1,145 @@
/**
* touch.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { DDManager } from './dd-manager';
import { Utils } from './utils';
/**
* Detect touch support - Windows Surface devices and other touch devices
* should we use this instead ? (what we had for always showing resize handles)
* /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
*/
export const isTouch = typeof window !== 'undefined' && typeof document !== 'undefined' &&
('ontouchstart' in document
|| 'ontouchstart' in window
// || !!window.TouchEvent // true on Windows 10 Chrome desktop so don't use this
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|| (window.DocumentTouch && document instanceof window.DocumentTouch)
|| navigator.maxTouchPoints > 0
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|| navigator.msMaxTouchPoints > 0);
// interface TouchCoord {x: number, y: number};
class DDTouch {
}
/**
* Get the x,y position of a touch event
*/
// function getTouchCoords(e: TouchEvent): TouchCoord {
// return {
// x: e.changedTouches[0].pageX,
// y: e.changedTouches[0].pageY
// };
// }
/**
* Simulate a mouse event based on a corresponding touch event
* @param {Object} e A touch event
* @param {String} simulatedType The corresponding mouse event
*/
function simulateMouseEvent(e, simulatedType) {
// Ignore multi-touch events
if (e.touches.length > 1)
return;
// Prevent "Ignored attempt to cancel a touchmove event with cancelable=false" errors
if (e.cancelable)
e.preventDefault();
// Dispatch the simulated event to the target element
Utils.simulateMouseEvent(e.changedTouches[0], simulatedType);
}
/**
* Simulate a mouse event based on a corresponding Pointer event
* @param {Object} e A pointer event
* @param {String} simulatedType The corresponding mouse event
*/
function simulatePointerMouseEvent(e, simulatedType) {
// Prevent "Ignored attempt to cancel a touchmove event with cancelable=false" errors
if (e.cancelable)
e.preventDefault();
// Dispatch the simulated event to the target element
Utils.simulateMouseEvent(e, simulatedType);
}
/**
* Handle the touchstart events
* @param {Object} e The widget element's touchstart event
*/
export function touchstart(e) {
// Ignore the event if another widget is already being handled
if (DDTouch.touchHandled)
return;
DDTouch.touchHandled = true;
// Simulate the mouse events
// simulateMouseEvent(e, 'mouseover');
// simulateMouseEvent(e, 'mousemove');
simulateMouseEvent(e, 'mousedown');
}
/**
* Handle the touchmove events
* @param {Object} e The document's touchmove event
*/
export function touchmove(e) {
// Ignore event if not handled by us
if (!DDTouch.touchHandled)
return;
simulateMouseEvent(e, 'mousemove');
}
/**
* Handle the touchend events
* @param {Object} e The document's touchend event
*/
export function touchend(e) {
// Ignore event if not handled
if (!DDTouch.touchHandled)
return;
// cancel delayed leave event when we release on ourself which happens BEFORE we get this!
if (DDTouch.pointerLeaveTimeout) {
window.clearTimeout(DDTouch.pointerLeaveTimeout);
delete DDTouch.pointerLeaveTimeout;
}
const wasDragging = !!DDManager.dragElement;
// Simulate the mouseup event
simulateMouseEvent(e, 'mouseup');
// simulateMouseEvent(event, 'mouseout');
// If the touch interaction did not move, it should trigger a click
if (!wasDragging) {
simulateMouseEvent(e, 'click');
}
// Unset the flag to allow other widgets to inherit the touch event
DDTouch.touchHandled = false;
}
/**
* Note we don't get touchenter/touchleave (which are deprecated)
* see https://stackoverflow.com/questions/27908339/js-touch-equivalent-for-mouseenter
* so instead of PointerEvent to still get enter/leave and send the matching mouse event.
*/
export function pointerdown(e) {
// console.log("pointer down")
if (e.pointerType === 'mouse')
return;
e.target.releasePointerCapture(e.pointerId); // <- Important!
}
export function pointerenter(e) {
// ignore the initial one we get on pointerdown on ourself
if (!DDManager.dragElement) {
// console.log('pointerenter ignored');
return;
}
// console.log('pointerenter');
if (e.pointerType === 'mouse')
return;
simulatePointerMouseEvent(e, 'mouseenter');
}
export function pointerleave(e) {
// ignore the leave on ourself we get before releasing the mouse over ourself
// by delaying sending the event and having the up event cancel us
if (!DDManager.dragElement) {
// console.log('pointerleave ignored');
return;
}
if (e.pointerType === 'mouse')
return;
DDTouch.pointerLeaveTimeout = window.setTimeout(() => {
delete DDTouch.pointerLeaveTimeout;
// console.log('pointerleave delayed');
simulatePointerMouseEvent(e, 'mouseleave');
}, 10);
}
//# sourceMappingURL=dd-touch.js.map

1
node_modules/gridstack/dist/src/dd-touch.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

321
node_modules/gridstack/dist/src/gridstack-engine.d.ts generated vendored Normal file
View File

@@ -0,0 +1,321 @@
/**
* gridstack-engine.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { GridStackNode, GridStackPosition, GridStackMoveOpts, SaveFcn, CompactOptions } from './types';
/** callback to update the DOM attributes since this class is generic (no HTML or other info) for items that changed - see _notify() */
type OnChangeCB = (nodes: GridStackNode[]) => void;
/** options used during creation - similar to GridStackOptions */
export interface GridStackEngineOptions {
column?: number;
maxRow?: number;
float?: boolean;
nodes?: GridStackNode[];
onChange?: OnChangeCB;
}
/**
* Defines the GridStack engine that handles all grid layout calculations and node positioning.
* This is the core engine that performs grid manipulation without any DOM operations.
*
* The engine manages:
* - Node positioning and collision detection
* - Layout algorithms (compact, float, etc.)
* - Grid resizing and column changes
* - Widget movement and resizing logic
*
* NOTE: Values should not be modified directly - use the main GridStack API instead
* to ensure proper DOM updates and event triggers.
*/
export declare class GridStackEngine {
column: number;
maxRow: number;
nodes: GridStackNode[];
addedNodes: GridStackNode[];
removedNodes: GridStackNode[];
batchMode: boolean;
defaultColumn: number;
/** true when grid.load() already cached the layout and can skip out of bound caching info */
skipCacheUpdate?: boolean;
constructor(opts?: GridStackEngineOptions);
/**
* Enable/disable batch mode for multiple operations to optimize performance.
* When enabled, layout updates are deferred until batch mode is disabled.
*
* @param flag true to enable batch mode, false to disable and apply changes
* @param doPack if true (default), pack/compact nodes when disabling batch mode
* @returns the engine instance for chaining
*
* @example
* // Start batch mode for multiple operations
* engine.batchUpdate(true);
* engine.addNode(node1);
* engine.addNode(node2);
* engine.batchUpdate(false); // Apply all changes at once
*/
batchUpdate(flag?: boolean, doPack?: boolean): GridStackEngine;
protected _useEntireRowArea(node: GridStackNode, nn: GridStackPosition): boolean;
/**
* Return the first node that intercepts/collides with the given node or area.
* Used for collision detection during drag and drop operations.
*
* @param skip the node to skip in collision detection (usually the node being moved)
* @param area the area to check for collisions (defaults to skip node's area)
* @param skip2 optional second node to skip in collision detection
* @returns the first colliding node, or undefined if no collision
*
* @example
* const colliding = engine.collide(draggedNode, {x: 2, y: 1, w: 2, h: 1});
* if (colliding) {
* console.log('Would collide with:', colliding.id);
* }
*/
collide(skip: GridStackNode, area?: GridStackNode, skip2?: GridStackNode): GridStackNode | undefined;
/**
* Return all nodes that intercept/collide with the given node or area.
* Similar to collide() but returns all colliding nodes instead of just the first.
*
* @param skip the node to skip in collision detection
* @param area the area to check for collisions (defaults to skip node's area)
* @param skip2 optional second node to skip in collision detection
* @returns array of all colliding nodes
*
* @example
* const allCollisions = engine.collideAll(draggedNode);
* console.log('Colliding with', allCollisions.length, 'nodes');
*/
collideAll(skip: GridStackNode, area?: GridStackNode, skip2?: GridStackNode): GridStackNode[];
/** does a pixel coverage collision based on where we started, returning the node that has the most coverage that is >50% mid line */
protected directionCollideCoverage(node: GridStackNode, o: GridStackMoveOpts, collides: GridStackNode[]): GridStackNode | undefined;
/**
* Attempt to swap the positions of two nodes if they meet swapping criteria.
* Nodes can swap if they are the same size or in the same column/row, not locked, and touching.
*
* @param a first node to swap
* @param b second node to swap
* @returns true if swap was successful, false if not possible, undefined if not applicable
*
* @example
* const swapped = engine.swap(nodeA, nodeB);
* if (swapped) {
* console.log('Nodes swapped successfully');
* }
*/
swap(a: GridStackNode, b: GridStackNode): boolean | undefined;
/**
* Check if the specified rectangular area is empty (no nodes occupy any part of it).
*
* @param x the x coordinate (column) of the area to check
* @param y the y coordinate (row) of the area to check
* @param w the width in columns of the area to check
* @param h the height in rows of the area to check
* @returns true if the area is completely empty, false if any node overlaps
*
* @example
* if (engine.isAreaEmpty(2, 1, 3, 2)) {
* console.log('Area is available for placement');
* }
*/
isAreaEmpty(x: number, y: number, w: number, h: number): boolean;
/**
* Re-layout grid items to reclaim any empty space.
* This optimizes the grid layout by moving items to fill gaps.
*
* @param layout layout algorithm to use:
* - 'compact' (default): find truly empty spaces, may reorder items
* - 'list': keep the sort order exactly the same, move items up sequentially
* @param doSort if true (default), sort nodes by position before compacting
* @returns the engine instance for chaining
*
* @example
* // Compact to fill empty spaces
* engine.compact();
*
* // Compact preserving item order
* engine.compact('list');
*/
compact(layout?: CompactOptions, doSort?: boolean): GridStackEngine;
/**
* Enable/disable floating widgets (default: `false`).
* When floating is enabled, widgets can move up to fill empty spaces.
* See [example](http://gridstackjs.com/demo/float.html)
*
* @param val true to enable floating, false to disable
*
* @example
* engine.float = true; // Enable floating
* engine.float = false; // Disable floating (default)
*/
set float(val: boolean);
/**
* Get the current floating mode setting.
*
* @returns true if floating is enabled, false otherwise
*
* @example
* const isFloating = engine.float;
* console.log('Floating enabled:', isFloating);
*/
get float(): boolean;
/**
* Sort the nodes array from first to last, or reverse.
* This is called during collision/placement operations to enforce a specific order.
*
* @param dir sort direction: 1 for ascending (first to last), -1 for descending (last to first)
* @returns the engine instance for chaining
*
* @example
* engine.sortNodes(); // Sort ascending (default)
* engine.sortNodes(-1); // Sort descending
*/
sortNodes(dir?: 1 | -1): GridStackEngine;
/**
* Prepare and validate a node's coordinates and values for the current grid.
* This ensures the node has valid position, size, and properties before being added to the grid.
*
* @param node the node to prepare and validate
* @param resizing if true, resize the node down if it's out of bounds; if false, move it to fit
* @returns the prepared node with valid coordinates
*
* @example
* const node = { w: 3, h: 2, content: 'Hello' };
* const prepared = engine.prepareNode(node);
* console.log('Node prepared at:', prepared.x, prepared.y);
*/
prepareNode(node: GridStackNode, resizing?: boolean): GridStackNode;
/**
* Part 2 of preparing a node to fit inside the grid - validates and fixes coordinates and dimensions.
* This ensures the node fits within grid boundaries and respects min/max constraints.
*
* @param node the node to validate and fix
* @param resizing if true, resize the node to fit; if false, move the node to fit
* @returns the engine instance for chaining
*
* @example
* // Fix a node that might be out of bounds
* engine.nodeBoundFix(node, true); // Resize to fit
* engine.nodeBoundFix(node, false); // Move to fit
*/
nodeBoundFix(node: GridStackNode, resizing?: boolean): GridStackEngine;
/**
* Returns a list of nodes that have been modified from their original values.
* This is used to track which nodes need DOM updates.
*
* @param verify if true, performs additional verification by comparing current vs original positions
* @returns array of nodes that have been modified
*
* @example
* const changed = engine.getDirtyNodes();
* console.log('Modified nodes:', changed.length);
*
* // Get verified dirty nodes
* const verified = engine.getDirtyNodes(true);
*/
getDirtyNodes(verify?: boolean): GridStackNode[];
/**
* Find the first available empty spot for the given node dimensions.
* Updates the node's x,y attributes with the found position.
*
* @param node the node to find a position for (w,h must be set)
* @param nodeList optional list of nodes to check against (defaults to engine nodes)
* @param column optional column count (defaults to engine column count)
* @param after optional node to start search after (maintains order)
* @returns true if an empty position was found and node was updated
*
* @example
* const node = { w: 2, h: 1 };
* if (engine.findEmptyPosition(node)) {
* console.log('Found position at:', node.x, node.y);
* }
*/
findEmptyPosition(node: GridStackNode, nodeList?: GridStackNode[], column?: number, after?: GridStackNode): boolean;
/**
* Add the given node to the grid, handling collision detection and re-packing.
* This is the main method for adding new widgets to the engine.
*
* @param node the node to add to the grid
* @param triggerAddEvent if true, adds node to addedNodes list for event triggering
* @param after optional node to place this node after (for ordering)
* @returns the added node (or existing node if duplicate)
*
* @example
* const node = { x: 0, y: 0, w: 2, h: 1, content: 'Hello' };
* const added = engine.addNode(node, true);
*/
addNode(node: GridStackNode, triggerAddEvent?: boolean, after?: GridStackNode): GridStackNode;
/**
* Remove the given node from the grid.
*
* @param node the node to remove
* @param removeDOM if true (default), marks node for DOM removal
* @param triggerEvent if true, adds node to removedNodes list for event triggering
* @returns the engine instance for chaining
*
* @example
* engine.removeNode(node, true, true);
*/
removeNode(node: GridStackNode, removeDOM?: boolean, triggerEvent?: boolean): GridStackEngine;
/**
* Remove all nodes from the grid.
*
* @param removeDOM if true (default), marks all nodes for DOM removal
* @param triggerEvent if true (default), triggers removal events
* @returns the engine instance for chaining
*
* @example
* engine.removeAll(); // Remove all nodes
*/
removeAll(removeDOM?: boolean, triggerEvent?: boolean): GridStackEngine;
/**
* Check if a node can be moved to a new position, considering layout constraints.
* This is a safer version of moveNode() that validates the move first.
*
* For complex cases (like maxRow constraints), it simulates the move in a clone first,
* then applies the changes only if they meet all specifications.
*
* @param node the node to move
* @param o move options including target position
* @returns true if the node was successfully moved
*
* @example
* const canMove = engine.moveNodeCheck(node, { x: 2, y: 1 });
* if (canMove) {
* console.log('Node moved successfully');
* }
*/
moveNodeCheck(node: GridStackNode, o: GridStackMoveOpts): boolean;
/** return true if can fit in grid height constrain only (always true if no maxRow) */
willItFit(node: GridStackNode): boolean;
/** true if x,y or w,h are different after clamping to min/max */
changedPosConstrain(node: GridStackNode, p: GridStackPosition): boolean;
/** return true if the passed in node was actually moved (checks for no-op and locked) */
moveNode(node: GridStackNode, o: GridStackMoveOpts): boolean;
getRow(): number;
beginUpdate(node: GridStackNode): GridStackEngine;
endUpdate(): GridStackEngine;
/** saves a copy of the largest column layout (eg 12 even when rendering 1 column) so we don't loose orig layout, unless explicity column
* count to use is given. returning a list of widgets for serialization
* @param saveElement if true (default), the element will be saved to GridStackWidget.el field, else it will be removed.
* @param saveCB callback for each node -> widget, so application can insert additional data to be saved into the widget data structure.
* @param column if provided, the grid will be saved for the given column count (IFF we have matching internal saved layout, or current layout).
* Note: nested grids will ALWAYS save the container w to match overall layouts (parent + child) to be consistent.
*/
save(saveElement?: boolean, saveCB?: SaveFcn, column?: number): GridStackNode[];
/**
* call to cache the given layout internally to the given location so we can restore back when column changes size
* @param nodes list of nodes
* @param column corresponding column index to save it under
* @param clear if true, will force other caches to be removed (default false)
*/
cacheLayout(nodes: GridStackNode[], column: number, clear?: boolean): GridStackEngine;
/**
* call to cache the given node layout internally to the given location so we can restore back when column changes size
* @param node single node to cache
* @param column corresponding column index to save it under
*/
cacheOneLayout(n: GridStackNode, column: number): GridStackEngine;
protected findCacheLayout(n: GridStackNode, column: number): number | undefined;
removeNodeFromLayoutCache(n: GridStackNode): void;
/** called to remove all internal values but the _id */
cleanupNode(node: GridStackNode): GridStackEngine;
}
export {};

1272
node_modules/gridstack/dist/src/gridstack-engine.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

802
node_modules/gridstack/dist/src/gridstack.d.ts generated vendored Normal file
View File

@@ -0,0 +1,802 @@
/*!
* GridStack 12.3.3
* https://gridstackjs.com/
*
* Copyright (c) 2021-2025 Alain Dumesny
* see root license https://github.com/gridstack/gridstack.js/tree/master/LICENSE
*/
import { GridStackEngine } from './gridstack-engine';
import { Utils } from './utils';
import { ColumnOptions, GridItemHTMLElement, GridStackElement, GridStackEventHandlerCallback, GridStackNode, GridStackWidget, numberOrString, DDDragOpt, GridStackOptions, GridStackEventHandler, GridStackNodesHandler, AddRemoveFcn, SaveFcn, CompactOptions, ResizeToContentFcn, GridStackDroppedHandler, GridStackElementHandler, Position, RenderFcn } from './types';
import { DDGridStack } from './dd-gridstack';
export * from './types';
export * from './utils';
export * from './gridstack-engine';
export * from './dd-gridstack';
export * from './dd-manager';
export * from './dd-element';
export * from './dd-draggable';
export * from './dd-droppable';
export * from './dd-resizable';
export * from './dd-resizable-handle';
export * from './dd-base-impl';
export interface GridHTMLElement extends HTMLElement {
gridstack?: GridStack;
}
/** list of possible events, or space separated list of them */
export type GridStackEvent = 'added' | 'change' | 'disable' | 'drag' | 'dragstart' | 'dragstop' | 'dropped' | 'enable' | 'removed' | 'resize' | 'resizestart' | 'resizestop' | 'resizecontent';
/** Defines the coordinates of an object */
export interface MousePosition {
top: number;
left: number;
}
/** Defines the position of a cell inside the grid*/
export interface CellPosition {
x: number;
y: number;
}
/**
* Main gridstack class - you will need to call `GridStack.init()` first to initialize your grid.
* Note: your grid elements MUST have the following classes for the CSS layout to work:
* @example
* <div class="grid-stack">
* <div class="grid-stack-item">
* <div class="grid-stack-item-content">Item 1</div>
* </div>
* </div>
*/
export declare class GridStack {
el: GridHTMLElement;
opts: GridStackOptions;
/**
* initializing the HTML element, or selector string, into a grid will return the grid. Calling it again will
* simply return the existing instance (ignore any passed options). There is also an initAll() version that support
* multiple grids initialization at once. Or you can use addGrid() to create the entire grid from JSON.
* @param options grid options (optional)
* @param elOrString element or CSS selector (first one used) to convert to a grid (default to '.grid-stack' class selector)
*
* @example
* const grid = GridStack.init();
*
* Note: the HTMLElement (of type GridHTMLElement) will store a `gridstack: GridStack` value that can be retrieve later
* const grid = document.querySelector('.grid-stack').gridstack;
*/
static init(options?: GridStackOptions, elOrString?: GridStackElement): GridStack;
/**
* Will initialize a list of elements (given a selector) and return an array of grids.
* @param options grid options (optional)
* @param selector elements selector to convert to grids (default to '.grid-stack' class selector)
*
* @example
* const grids = GridStack.initAll();
* grids.forEach(...)
*/
static initAll(options?: GridStackOptions, selector?: string): GridStack[];
/**
* call to create a grid with the given options, including loading any children from JSON structure. This will call GridStack.init(), then
* grid.load() on any passed children (recursively). Great alternative to calling init() if you want entire grid to come from
* JSON serialized data, including options.
* @param parent HTML element parent to the grid
* @param opt grids options used to initialize the grid, and list of children
*/
static addGrid(parent: HTMLElement, opt?: GridStackOptions): GridStack;
/** call this method to register your engine instead of the default one.
* See instead `GridStackOptions.engineClass` if you only need to
* replace just one instance.
*/
static registerEngine(engineClass: typeof GridStackEngine): void;
/**
* callback method use when new items|grids needs to be created or deleted, instead of the default
* item: <div class="grid-stack-item"><div class="grid-stack-item-content">w.content</div></div>
* grid: <div class="grid-stack">grid content...</div>
* add = true: the returned DOM element will then be converted to a GridItemHTMLElement using makeWidget()|GridStack:init().
* add = false: the item will be removed from DOM (if not already done)
* grid = true|false for grid vs grid-items
*/
static addRemoveCB?: AddRemoveFcn;
/**
* callback during saving to application can inject extra data for each widget, on top of the grid layout properties
*/
static saveCB?: SaveFcn;
/**
* callback to create the content of widgets so the app can control how to store and restore it
* By default this lib will do 'el.textContent = w.content' forcing text only support for avoiding potential XSS issues.
*/
static renderCB?: RenderFcn;
/** called after a widget has been updated (eg: load() into an existing list of children) so application can do extra work */
static updateCB?: (w: GridStackNode) => void;
/** callback to use for resizeToContent instead of the built in one */
static resizeToContentCB?: ResizeToContentFcn;
/** parent class for sizing content. defaults to '.grid-stack-item-content' */
static resizeToContentParent: string;
/** scoping so users can call GridStack.Utils.sort() for example */
static Utils: typeof Utils;
/** scoping so users can call new GridStack.Engine(12) for example */
static Engine: typeof GridStackEngine;
/** engine used to implement non DOM grid functionality */
engine: GridStackEngine;
/** point to a parent grid item if we're nested (inside a grid-item in between 2 Grids) */
parentGridNode?: GridStackNode;
/** time to wait for animation (if enabled) to be done so content sizing can happen */
animationDelay: number;
protected static engineClass: typeof GridStackEngine;
protected resizeObserver: ResizeObserver;
protected responseLayout: ColumnOptions;
private _skipInitialResize;
/**
* Construct a grid item from the given element and options
* @param el the HTML element tied to this grid after it's been initialized
* @param opts grid options - public for classes to access, but use methods to modify!
*/
constructor(el: GridHTMLElement, opts?: GridStackOptions);
private _updateColumnVar;
/**
* add a new widget and returns it.
*
* Widget will be always placed even if result height is more than actual grid height.
* You need to use `willItFit()` before calling addWidget for additional check.
* See also `makeWidget(el)` for DOM element.
*
* @example
* const grid = GridStack.init();
* grid.addWidget({w: 3, content: 'hello'});
*
* @param w GridStackWidget definition. used MakeWidget(el) if you have dom element instead.
*/
addWidget(w: GridStackWidget): GridItemHTMLElement;
/**
* Create the default grid item divs and content (possibly lazy loaded) by using GridStack.renderCB().
*
* @param n GridStackNode definition containing widget configuration
* @returns the created HTML element with proper grid item structure
*
* @example
* const element = grid.createWidgetDivs({ w: 2, h: 1, content: 'Hello World' });
*/
createWidgetDivs(n: GridStackNode): HTMLElement;
/**
* Convert an existing gridItem element into a sub-grid with the given (optional) options, else inherit them
* from the parent's subGrid options.
* @param el gridItem element to convert
* @param ops (optional) sub-grid options, else default to node, then parent settings, else defaults
* @param nodeToAdd (optional) node to add to the newly created sub grid (used when dragging over existing regular item)
* @param saveContent if true (default) the html inside .grid-stack-content will be saved to child widget
* @returns newly created grid
*/
makeSubGrid(el: GridItemHTMLElement, ops?: GridStackOptions, nodeToAdd?: GridStackNode, saveContent?: boolean): GridStack;
/**
* called when an item was converted into a nested grid to accommodate a dragged over item, but then item leaves - return back
* to the original grid-item. Also called to remove empty sub-grids when last item is dragged out (since re-creating is simple)
*/
removeAsSubGrid(nodeThatRemoved?: GridStackNode): void;
/**
* saves the current layout returning a list of widgets for serialization which might include any nested grids.
* @param saveContent if true (default) the latest html inside .grid-stack-content will be saved to GridStackWidget.content field, else it will
* be removed.
* @param saveGridOpt if true (default false), save the grid options itself, so you can call the new GridStack.addGrid()
* to recreate everything from scratch. GridStackOptions.children would then contain the widget list instead.
* @param saveCB callback for each node -> widget, so application can insert additional data to be saved into the widget data structure.
* @param column if provided, the grid will be saved for the given column size (IFF we have matching internal saved layout, or current layout).
* Otherwise it will use the largest possible layout (say 12 even if rendering at 1 column) so we can restore to all layouts.
* NOTE: if you want to save to currently display layout, pass this.getColumn() as column.
* NOTE2: nested grids will ALWAYS save to the container size to be in sync with parent.
* @returns list of widgets or full grid option, including .children list of widgets
*/
save(saveContent?: boolean, saveGridOpt?: boolean, saveCB?: SaveFcn, column?: number): GridStackWidget[] | GridStackOptions;
/**
* Load widgets from a list. This will call update() on each (matching by id) or add/remove widgets that are not there.
* Used to restore a grid layout for a saved layout list (see `save()`).
*
* @param items list of widgets definition to update/create
* @param addRemove boolean (default true) or callback method can be passed to control if and how missing widgets can be added/removed, giving
* the user control of insertion.
* @returns the grid instance for chaining
*
* @example
* // Basic usage with saved layout
* const savedLayout = grid.save(); // Save current layout
* // ... later restore it
* grid.load(savedLayout);
*
* // Load with custom add/remove callback
* grid.load(layout, (items, grid, add) => {
* if (add) {
* // Custom logic for adding new widgets
* items.forEach(item => {
* const el = document.createElement('div');
* el.innerHTML = item.content || '';
* grid.addWidget(el, item);
* });
* } else {
* // Custom logic for removing widgets
* items.forEach(item => grid.removeWidget(item.el));
* }
* });
*
* // Load without adding/removing missing widgets
* grid.load(layout, false);
*
* @see {@link http://gridstackjs.com/demo/serialization.html} for complete example
*/
load(items: GridStackWidget[], addRemove?: boolean | AddRemoveFcn): GridStack;
/**
* use before calling a bunch of `addWidget()` to prevent un-necessary relayouts in between (more efficient)
* and get a single event callback. You will see no changes until `batchUpdate(false)` is called.
*/
batchUpdate(flag?: boolean): GridStack;
/**
* Gets the current cell height in pixels. This takes into account the unit type and converts to pixels if necessary.
*
* @param forcePixel if true, forces conversion to pixels even when cellHeight is specified in other units
* @returns the cell height in pixels
*
* @example
* const height = grid.getCellHeight();
* console.log('Cell height:', height, 'px');
*
* // Force pixel conversion
* const pixelHeight = grid.getCellHeight(true);
*/
getCellHeight(forcePixel?: boolean): number;
/**
* Update current cell height - see `GridStackOptions.cellHeight` for format by updating eh Browser CSS variable.
*
* @param val the cell height. Options:
* - `undefined`: cells content will be made square (match width minus margin)
* - `0`: the CSS will be generated by the application instead
* - number: height in pixels
* - string: height with units (e.g., '70px', '5rem', '2em')
* @returns the grid instance for chaining
*
* @example
* grid.cellHeight(100); // 100px height
* grid.cellHeight('70px'); // explicit pixel height
* grid.cellHeight('5rem'); // relative to root font size
* grid.cellHeight(grid.cellWidth() * 1.2); // aspect ratio
* grid.cellHeight('auto'); // auto-size based on content
*/
cellHeight(val?: numberOrString): GridStack;
/** Gets current cell width. */
/**
* Gets the current cell width in pixels. This is calculated based on the grid container width divided by the number of columns.
*
* @returns the cell width in pixels
*
* @example
* const width = grid.cellWidth();
* console.log('Cell width:', width, 'px');
*
* // Use cell width to calculate widget dimensions
* const widgetWidth = width * 3; // For a 3-column wide widget
*/
cellWidth(): number;
/** return our expected width (or parent) , and optionally of window for dynamic column check */
protected _widthOrContainer(forBreakpoint?: boolean): number;
/** checks for dynamic column count for our current size, returning true if changed */
protected checkDynamicColumn(): boolean;
/**
* Re-layout grid items to reclaim any empty space. This is useful after removing widgets
* or when you want to optimize the layout.
*
* @param layout layout type. Options:
* - 'compact' (default): might re-order items to fill any empty space
* - 'list': keep the widget left->right order the same, even if that means leaving an empty slot if things don't fit
* @param doSort re-sort items first based on x,y position. Set to false to do your own sorting ahead (default: true)
* @returns the grid instance for chaining
*
* @example
* // Compact layout after removing widgets
* grid.removeWidget('.widget-to-remove');
* grid.compact();
*
* // Use list layout (preserve order)
* grid.compact('list');
*
* // Compact without sorting first
* grid.compact('compact', false);
*/
compact(layout?: CompactOptions, doSort?: boolean): GridStack;
/**
* Set the number of columns in the grid. Will update existing widgets to conform to new number of columns,
* as well as cache the original layout so you can revert back to previous positions without loss.
*
* Requires `gridstack-extra.css` or `gridstack-extra.min.css` for [2-11] columns,
* else you will need to generate correct CSS.
* See: https://github.com/gridstack/gridstack.js#change-grid-columns
*
* @param column Integer > 0 (default 12)
* @param layout specify the type of re-layout that will happen. Options:
* - 'moveScale' (default): scale widget positions and sizes
* - 'move': keep widget sizes, only move positions
* - 'scale': keep widget positions, only scale sizes
* - 'none': don't change widget positions or sizes
* Note: items will never be outside of the current column boundaries.
* Ignored for `column=1` as we always want to vertically stack.
* @returns the grid instance for chaining
*
* @example
* // Change to 6 columns with default scaling
* grid.column(6);
*
* // Change to 4 columns, only move positions
* grid.column(4, 'move');
*
* // Single column layout (vertical stack)
* grid.column(1);
*/
column(column: number, layout?: ColumnOptions): GridStack;
/**
* Get the number of columns in the grid (default 12).
*
* @returns the current number of columns in the grid
*
* @example
* const columnCount = grid.getColumn(); // returns 12 by default
*/
getColumn(): number;
/**
* Returns an array of grid HTML elements (no placeholder) - used to iterate through our children in DOM order.
* This method excludes placeholder elements and returns only actual grid items.
*
* @returns array of GridItemHTMLElement instances representing all grid items
*
* @example
* const items = grid.getGridItems();
* items.forEach(item => {
* console.log('Item ID:', item.gridstackNode.id);
* });
*/
getGridItems(): GridItemHTMLElement[];
/**
* Returns true if change callbacks should be ignored due to column change, sizeToContent, loading, etc.
* This is useful for callers who want to implement dirty flag functionality.
*
* @returns true if change callbacks are currently being ignored
*
* @example
* if (!grid.isIgnoreChangeCB()) {
* // Process the change event
* console.log('Grid layout changed');
* }
*/
isIgnoreChangeCB(): boolean;
/**
* Destroys a grid instance. DO NOT CALL any methods or access any vars after this as it will free up members.
* @param removeDOM if `false` grid and items HTML elements will not be removed from the DOM (Optional. Default `true`).
*/
destroy(removeDOM?: boolean): GridStack;
/**
* Enable/disable floating widgets (default: `false`). When enabled, widgets can float up to fill empty spaces.
* See [example](http://gridstackjs.com/demo/float.html)
*
* @param val true to enable floating, false to disable
* @returns the grid instance for chaining
*
* @example
* grid.float(true); // Enable floating
* grid.float(false); // Disable floating (default)
*/
float(val: boolean): GridStack;
/**
* Get the current float mode setting.
*
* @returns true if floating is enabled, false otherwise
*
* @example
* const isFloating = grid.getFloat();
* console.log('Floating enabled:', isFloating);
*/
getFloat(): boolean;
/**
* Get the position of the cell under a pixel on screen.
* @param position the position of the pixel to resolve in
* absolute coordinates, as an object with top and left properties
* @param useDocRelative if true, value will be based on document position vs parent position (Optional. Default false).
* Useful when grid is within `position: relative` element
*
* Returns an object with properties `x` and `y` i.e. the column and row in the grid.
*/
getCellFromPixel(position: MousePosition, useDocRelative?: boolean): CellPosition;
/**
* Returns the current number of rows, which will be at least `minRow` if set.
* The row count is based on the highest positioned widget in the grid.
*
* @returns the current number of rows in the grid
*
* @example
* const rowCount = grid.getRow();
* console.log('Grid has', rowCount, 'rows');
*/
getRow(): number;
/**
* Checks if the specified rectangular area is empty (no widgets occupy any part of it).
*
* @param x the x coordinate (column) of the area to check
* @param y the y coordinate (row) of the area to check
* @param w the width in columns of the area to check
* @param h the height in rows of the area to check
* @returns true if the area is completely empty, false if any widget overlaps
*
* @example
* // Check if a 2x2 area at position (1,1) is empty
* if (grid.isAreaEmpty(1, 1, 2, 2)) {
* console.log('Area is available for placement');
* }
*/
isAreaEmpty(x: number, y: number, w: number, h: number): boolean;
/**
* If you add elements to your grid by hand (or have some framework creating DOM), you have to tell gridstack afterwards to make them widgets.
* If you want gridstack to add the elements for you, use `addWidget()` instead.
* Makes the given element a widget and returns it.
*
* @param els widget or single selector to convert.
* @param options widget definition to use instead of reading attributes or using default sizing values
* @returns the converted GridItemHTMLElement
*
* @example
* const grid = GridStack.init();
*
* // Create HTML content manually, possibly looking like:
* // <div id="item-1" gs-x="0" gs-y="0" gs-w="3" gs-h="2"></div>
* grid.el.innerHTML = '<div id="item-1" gs-w="3"></div><div id="item-2"></div>';
*
* // Convert existing elements to widgets
* grid.makeWidget('#item-1'); // Uses gs-* attributes from DOM
* grid.makeWidget('#item-2', {w: 2, h: 1, content: 'Hello World'});
*
* // Or pass DOM element directly
* const element = document.getElementById('item-3');
* grid.makeWidget(element, {x: 0, y: 1, w: 4, h: 2});
*/
makeWidget(els: GridStackElement, options?: GridStackWidget): GridItemHTMLElement;
/**
* Register event handler for grid events. You can call this on a single event name, or space separated list.
*
* Supported events:
* - `added`: Called when widgets are being added to a grid
* - `change`: Occurs when widgets change their position/size due to constraints or direct changes
* - `disable`: Called when grid becomes disabled
* - `dragstart`: Called when grid item starts being dragged
* - `drag`: Called while grid item is being dragged (for each new row/column value)
* - `dragstop`: Called after user is done moving the item, with updated DOM attributes
* - `dropped`: Called when an item has been dropped and accepted over a grid
* - `enable`: Called when grid becomes enabled
* - `removed`: Called when items are being removed from the grid
* - `resizestart`: Called before user starts resizing an item
* - `resize`: Called while grid item is being resized (for each new row/column value)
* - `resizestop`: Called after user is done resizing the item, with updated DOM attributes
*
* @param name event name(s) to listen for (space separated for multiple)
* @param callback function to call when event occurs
* @returns the grid instance for chaining
*
* @example
* // Listen to multiple events at once
* grid.on('added removed change', (event, items) => {
* items.forEach(item => console.log('Item changed:', item));
* });
*
* // Listen to individual events
* grid.on('added', (event, items) => {
* items.forEach(item => console.log('Added item:', item));
* });
*/
on(name: 'dropped', callback: GridStackDroppedHandler): GridStack;
on(name: 'enable' | 'disable', callback: GridStackEventHandler): GridStack;
on(name: 'change' | 'added' | 'removed' | 'resizecontent', callback: GridStackNodesHandler): GridStack;
on(name: 'resizestart' | 'resize' | 'resizestop' | 'dragstart' | 'drag' | 'dragstop', callback: GridStackElementHandler): GridStack;
on(name: string, callback: GridStackEventHandlerCallback): GridStack;
/**
* unsubscribe from the 'on' event GridStackEvent
* @param name of the event (see possible values) or list of names space separated
*/
off(name: GridStackEvent | string): GridStack;
/**
* Remove all event handlers from the grid. This is useful for cleanup when destroying a grid.
*
* @returns the grid instance for chaining
*
* @example
* grid.offAll(); // Remove all event listeners
*/
offAll(): GridStack;
/**
* Removes widget from the grid.
* @param el widget or selector to modify
* @param removeDOM if `false` DOM element won't be removed from the tree (Default? true).
* @param triggerEvent if `false` (quiet mode) element will not be added to removed list and no 'removed' callbacks will be called (Default? true).
*/
removeWidget(els: GridStackElement, removeDOM?: boolean, triggerEvent?: boolean): GridStack;
/**
* Removes all widgets from the grid.
* @param removeDOM if `false` DOM elements won't be removed from the tree (Default? `true`).
* @param triggerEvent if `false` (quiet mode) element will not be added to removed list and no 'removed' callbacks will be called (Default? true).
*/
removeAll(removeDOM?: boolean, triggerEvent?: boolean): GridStack;
/**
* Toggle the grid animation state. Toggles the `grid-stack-animate` class.
* @param doAnimate if true the grid will animate.
* @param delay if true setting will be set on next event loop.
*/
setAnimation(doAnimate?: boolean, delay?: boolean): GridStack;
/**
* Toggle the grid static state, which permanently removes/add Drag&Drop support, unlike disable()/enable() that just turns it off/on.
* Also toggle the grid-stack-static class.
* @param val if true the grid become static.
* @param updateClass true (default) if css class gets updated
* @param recurse true (default) if sub-grids also get updated
*/
setStatic(val: boolean, updateClass?: boolean, recurse?: boolean): GridStack;
/**
* Updates the passed in options on the grid (similar to update(widget) for for the grid options).
* @param options PARTIAL grid options to update - only items specified will be updated.
* NOTE: not all options updating are currently supported (lot of code, unlikely to change)
*/
updateOptions(o: GridStackOptions): GridStack;
/**
* Updates widget position/size and other info. This is used to change widget properties after creation.
* Can update position, size, content, and other widget properties.
*
* Note: If you need to call this on all nodes, use load() instead which will update what changed.
* Setting the same x,y for multiple items will be indeterministic and likely unwanted.
*
* @param els widget element(s) or selector to modify
* @param opt new widget options (x,y,w,h, etc.). Only those set will be updated.
* @returns the grid instance for chaining
*
* @example
* // Update widget size and position
* grid.update('.my-widget', { x: 2, y: 1, w: 3, h: 2 });
*
* // Update widget content
* grid.update(widget, { content: '<p>New content</p>' });
*
* // Update multiple properties
* grid.update('#my-widget', {
* w: 4,
* h: 3,
* noResize: true,
* locked: true
* });
*/
update(els: GridStackElement, opt: GridStackWidget): GridStack;
private moveNode;
/**
* Updates widget height to match the content height to avoid vertical scrollbars or dead space.
* This automatically adjusts the widget height based on its content size.
*
* Note: This assumes only 1 child under resizeToContentParent='.grid-stack-item-content'
* (sized to gridItem minus padding) that represents the entire content size.
*
* @param el the grid item element to resize
*
* @example
* // Resize a widget to fit its content
* const widget = document.querySelector('.grid-stack-item');
* grid.resizeToContent(widget);
*
* // This is commonly used with dynamic content:
* widget.querySelector('.content').innerHTML = 'New longer content...';
* grid.resizeToContent(widget);
*/
resizeToContent(el: GridItemHTMLElement): void;
/** call the user resize (so they can do extra work) else our build in version */
private resizeToContentCBCheck;
/**
* Rotate widgets by swapping their width and height. This is typically called when the user presses 'r' during dragging.
* The rotation swaps the w/h dimensions and adjusts min/max constraints accordingly.
*
* @param els widget element(s) or selector to rotate
* @param relative optional pixel coordinate relative to upper/left corner to rotate around (keeps that cell under cursor)
* @returns the grid instance for chaining
*
* @example
* // Rotate a specific widget
* grid.rotate('.my-widget');
*
* // Rotate with relative positioning during drag
* grid.rotate(widget, { left: 50, top: 30 });
*/
rotate(els: GridStackElement, relative?: Position): GridStack;
/**
* Updates the margins which will set all 4 sides at once - see `GridStackOptions.margin` for format options.
* Supports CSS string format of 1, 2, or 4 values or a single number.
*
* @param value margin value - can be:
* - Single number: `10` (applies to all sides)
* - Two values: `'10px 20px'` (top/bottom, left/right)
* - Four values: `'10px 20px 5px 15px'` (top, right, bottom, left)
* @returns the grid instance for chaining
*
* @example
* grid.margin(10); // 10px all sides
* grid.margin('10px 20px'); // 10px top/bottom, 20px left/right
* grid.margin('5px 10px 15px 20px'); // Different for each side
*/
margin(value: numberOrString): GridStack;
/**
* Returns the current margin value as a number (undefined if the 4 sides don't match).
* This only returns a number if all sides have the same margin value.
*
* @returns the margin value in pixels, or undefined if sides have different values
*
* @example
* const margin = grid.getMargin();
* if (margin !== undefined) {
* console.log('Uniform margin:', margin, 'px');
* } else {
* console.log('Margins are different on different sides');
* }
*/
getMargin(): number;
/**
* Returns true if the height of the grid will be less than the vertical
* constraint. Always returns true if grid doesn't have height constraint.
* @param node contains x,y,w,h,auto-position options
*
* @example
* if (grid.willItFit(newWidget)) {
* grid.addWidget(newWidget);
* } else {
* alert('Not enough free space to place the widget');
* }
*/
willItFit(node: GridStackWidget): boolean;
/**
* called when we are being resized - check if the one Column Mode needs to be turned on/off
* and remember the prev columns we used, or get our count from parent, as well as check for cellHeight==='auto' (square)
* or `sizeToContent` gridItem options.
*/
onResize(clientWidth?: number): GridStack;
/** resizes content for given node (or all) if shouldSizeToContent() is true */
private resizeToContentCheck;
/** add or remove the grid element size event handler */
protected _updateResizeEvent(forceRemove?: boolean): GridStack;
/**
* Get the global drag & drop implementation instance.
* This provides access to the underlying drag & drop functionality.
*
* @returns the DDGridStack instance used for drag & drop operations
*
* @example
* const dd = GridStack.getDD();
* // Access drag & drop functionality
*/
static getDD(): DDGridStack;
/**
* call to setup dragging in from the outside (say toolbar), by specifying the class selection and options.
* Called during GridStack.init() as options, but can also be called directly (last param are used) in case the toolbar
* is dynamically create and needs to be set later.
* @param dragIn string selector (ex: '.sidebar-item') or list of dom elements
* @param dragInOptions options - see DDDragOpt. (default: {handle: '.grid-stack-item-content', appendTo: 'body'}
* @param widgets GridStackWidget def to assign to each element which defines what to create on drop
* @param root optional root which defaults to document (for shadow dom pass the parent HTMLDocument)
*/
static setupDragIn(dragIn?: string | HTMLElement[], dragInOptions?: DDDragOpt, widgets?: GridStackWidget[], root?: HTMLElement | Document): void;
/**
* Enables/Disables dragging by the user for specific grid elements.
* For all items and future items, use enableMove() instead. No-op for static grids.
*
* Note: If you want to prevent an item from moving due to being pushed around by another
* during collision, use the 'locked' property instead.
*
* @param els widget element(s) or selector to modify
* @param val if true widget will be draggable, assuming the parent grid isn't noMove or static
* @returns the grid instance for chaining
*
* @example
* // Make specific widgets draggable
* grid.movable('.my-widget', true);
*
* // Disable dragging for specific widgets
* grid.movable('#fixed-widget', false);
*/
movable(els: GridStackElement, val: boolean): GridStack;
/**
* Enables/Disables user resizing for specific grid elements.
* For all items and future items, use enableResize() instead. No-op for static grids.
*
* @param els widget element(s) or selector to modify
* @param val if true widget will be resizable, assuming the parent grid isn't noResize or static
* @returns the grid instance for chaining
*
* @example
* // Make specific widgets resizable
* grid.resizable('.my-widget', true);
*
* // Disable resizing for specific widgets
* grid.resizable('#fixed-size-widget', false);
*/
resizable(els: GridStackElement, val: boolean): GridStack;
/**
* Temporarily disables widgets moving/resizing.
* If you want a more permanent way (which freezes up resources) use `setStatic(true)` instead.
*
* Note: This is a no-op for static grids.
*
* This is a shortcut for:
* ```typescript
* grid.enableMove(false);
* grid.enableResize(false);
* ```
*
* @param recurse if true (default), sub-grids also get updated
* @returns the grid instance for chaining
*
* @example
* // Disable all interactions
* grid.disable();
*
* // Disable only this grid, not sub-grids
* grid.disable(false);
*/
disable(recurse?: boolean): GridStack;
/**
* Re-enables widgets moving/resizing - see disable().
* Note: This is a no-op for static grids.
*
* This is a shortcut for:
* ```typescript
* grid.enableMove(true);
* grid.enableResize(true);
* ```
*
* @param recurse if true (default), sub-grids also get updated
* @returns the grid instance for chaining
*
* @example
* // Re-enable all interactions
* grid.enable();
*
* // Enable only this grid, not sub-grids
* grid.enable(false);
*/
enable(recurse?: boolean): GridStack;
/**
* Enables/disables widget moving for all widgets. No-op for static grids.
* Note: locally defined items (with noMove property) still override this setting.
*
* @param doEnable if true widgets will be movable, if false moving is disabled
* @param recurse if true (default), sub-grids also get updated
* @returns the grid instance for chaining
*
* @example
* // Enable moving for all widgets
* grid.enableMove(true);
*
* // Disable moving for all widgets
* grid.enableMove(false);
*
* // Enable only this grid, not sub-grids
* grid.enableMove(true, false);
*/
enableMove(doEnable: boolean, recurse?: boolean): GridStack;
/**
* Enables/disables widget resizing for all widgets. No-op for static grids.
* Note: locally defined items (with noResize property) still override this setting.
*
* @param doEnable if true widgets will be resizable, if false resizing is disabled
* @param recurse if true (default), sub-grids also get updated
* @returns the grid instance for chaining
*
* @example
* // Enable resizing for all widgets
* grid.enableResize(true);
*
* // Disable resizing for all widgets
* grid.enableResize(false);
*
* // Enable only this grid, not sub-grids
* grid.enableResize(true, false);
*/
enableResize(doEnable: boolean, recurse?: boolean): GridStack;
/**
* prepares the element for drag&drop - this is normally called by makeWidget() unless are are delay loading
* @param el GridItemHTMLElement of the widget
* @param [force=false]
* */
prepareDragDrop(el: GridItemHTMLElement, force?: boolean): GridStack;
/** call given event callback on our main top-most grid (if we're nested) */
protected triggerEvent(event: Event, target: GridItemHTMLElement): void;
commit(): GridStack;
}

2872
node_modules/gridstack/dist/src/gridstack.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

1
node_modules/gridstack/dist/src/gridstack.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

157
node_modules/gridstack/dist/src/gridstack.scss generated vendored Normal file
View File

@@ -0,0 +1,157 @@
/**
* gridstack SASS styles 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
$animation_speed: .3s !default;
@function fixed($float) {
@return calc(round($float * 1000) / 1000); // total 4-5 digits being %
}
@mixin vendor($property, $value...){
// -webkit-#{$property}: $value;
// -moz-#{$property}: $value;
// -ms-#{$property}: $value;
// -o-#{$property}: $value;
#{$property}: $value;
}
.grid-stack {
position: relative;
}
.grid-stack-rtl {
direction: ltr;
> .grid-stack-item {
direction: rtl;
}
}
.grid-stack-placeholder > .placeholder-content {
background-color: rgba(0,0,0,0.1);
margin: 0;
position: absolute;
width: auto;
z-index: 0 !important;
}
// make those more unique as to not conflict with side panel items
.grid-stack > .grid-stack-item {
position: absolute;
padding: 0;
top: 0; left: 0; // some default to reduce at least first row/column inline styles
width: var(--gs-column-width); // reduce 1x1 items inline styles
height: var(--gs-cell-height);
> .grid-stack-item-content {
margin: 0;
position: absolute;
width: auto;
overflow-x: hidden;
overflow-y: auto;
}
&.size-to-content:not(.size-to-content-max) > .grid-stack-item-content {
overflow-y: hidden;
}
}
.grid-stack {
> .grid-stack-item > .grid-stack-item-content,
> .grid-stack-placeholder > .placeholder-content {
top: var(--gs-item-margin-top);
right: var(--gs-item-margin-right);
bottom: var(--gs-item-margin-bottom);
left: var(--gs-item-margin-left);
}
}
.grid-stack-item {
> .ui-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
-ms-touch-action: none;
touch-action: none;
}
&.ui-resizable-disabled > .ui-resizable-handle,
&.ui-resizable-autohide > .ui-resizable-handle { display: none; }
> .ui-resizable-ne,
> .ui-resizable-nw,
> .ui-resizable-se,
> .ui-resizable-sw {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="%23666" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 20 20"><path d="m10 3 2 2H8l2-2v14l-2-2h4l-2 2"/></svg>');
background-repeat: no-repeat;
background-position: center;
}
> .ui-resizable-ne {
@include vendor(transform, rotate(45deg));
}
> .ui-resizable-sw {
@include vendor(transform, rotate(45deg));
}
> .ui-resizable-nw {
@include vendor(transform, rotate(-45deg));
}
> .ui-resizable-se {
@include vendor(transform, rotate(-45deg));
}
> .ui-resizable-nw { cursor: nw-resize; width: 20px; height: 20px; top: var(--gs-item-margin-top); left: var(--gs-item-margin-left); }
> .ui-resizable-n { cursor: n-resize; height: 10px; top: var(--gs-item-margin-top); left: 25px; right: 25px; }
> .ui-resizable-ne { cursor: ne-resize; width: 20px; height: 20px; top: var(--gs-item-margin-top); right: var(--gs-item-margin-right); }
> .ui-resizable-e { cursor: e-resize; width: 10px; top: 15px; bottom: 15px; right: var(--gs-item-margin-right);}
> .ui-resizable-se { cursor: se-resize; width: 20px; height: 20px; bottom: var(--gs-item-margin-bottom); right: var(--gs-item-margin-right); }
> .ui-resizable-s { cursor: s-resize; height: 10px; left: 25px; bottom: var(--gs-item-margin-bottom); right: 25px; }
> .ui-resizable-sw { cursor: sw-resize; width: 20px; height: 20px; bottom: var(--gs-item-margin-bottom); left: var(--gs-item-margin-left); }
> .ui-resizable-w { cursor: w-resize; width: 10px; top: 15px; bottom: 15px; left: var(--gs-item-margin-left); }
&.ui-draggable-dragging {
&> .ui-resizable-handle {
display: none !important;
}
}
&.ui-draggable-dragging {
will-change: left, top;
}
&.ui-resizable-resizing {
will-change: width, height;
}
}
// not .grid-stack-item specific to also affect dragIn regions
.ui-draggable-dragging,
.ui-resizable-resizing {
z-index: 10000; // bootstrap modal has a z-index of 1050
> .grid-stack-item-content {
box-shadow: 1px 4px 6px rgba(0, 0, 0, 0.2);
opacity: 0.8;
}
}
.grid-stack-animate,
.grid-stack-animate .grid-stack-item {
@include vendor(transition, left $animation_speed, top $animation_speed, height $animation_speed, width $animation_speed);
}
.grid-stack-animate .grid-stack-item.ui-draggable-dragging,
.grid-stack-animate .grid-stack-item.ui-resizable-resizing,
.grid-stack-animate .grid-stack-item.grid-stack-placeholder{
@include vendor(transition, left 0s, top 0s, height 0s, width 0s);
}
// make those more unique as to not conflict with side panel items, but apply to all column layouts (so not in loop below)
.grid-stack > .grid-stack-item[gs-y="0"] {
top: 0px;
}
.grid-stack > .grid-stack-item[gs-x="0"] {
left: 0%;
}

427
node_modules/gridstack/dist/src/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,427 @@
/**
* types.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { GridStack } from './gridstack';
import { GridStackEngine } from './gridstack-engine';
/**
* Default values for grid options - used during initialization and when saving out grid configuration.
* These values are applied when options are not explicitly provided.
*/
export declare const gridDefaults: GridStackOptions;
/**
* Different layout options when changing the number of columns.
*
* These options control how widgets are repositioned when the grid column count changes.
* Note: The new list may be partially filled if there's a cached layout for that size.
*
* Options:
* - `'list'`: Treat items as a sorted list, keeping them sequentially without resizing (unless too big)
* - `'compact'`: Similar to list, but uses compact() method to fill empty slots by reordering
* - `'moveScale'`: Scale and move items by the ratio of newColumnCount / oldColumnCount
* - `'move'`: Only move items, keep their sizes
* - `'scale'`: Only scale items, keep their positions
* - `'none'`: Leave items unchanged unless they don't fit in the new column count
* - Custom function: Provide your own layout logic
*/
export type ColumnOptions = 'list' | 'compact' | 'moveScale' | 'move' | 'scale' | 'none' | ((column: number, oldColumn: number, nodes: GridStackNode[], oldNodes: GridStackNode[]) => void);
/**
* Options for the compact() method to reclaim empty space.
* - `'list'`: Keep items in order, move them up sequentially
* - `'compact'`: Find truly empty spaces, may reorder items for optimal fit
*/
export type CompactOptions = 'list' | 'compact';
/**
* Type representing values that can be either numbers or strings (e.g., dimensions with units).
* Used for properties like width, height, margins that accept both numeric and string values.
*/
export type numberOrString = number | string;
/**
* Extended HTMLElement interface for grid items.
* All grid item DOM elements implement this interface to provide access to their grid data.
*/
export interface GridItemHTMLElement extends HTMLElement {
/** Pointer to the associated grid node instance containing position, size, and other widget data */
gridstackNode?: GridStackNode;
}
/**
* Type representing various ways to specify grid elements.
* Can be a CSS selector string, HTMLElement, or GridItemHTMLElement.
*/
export type GridStackElement = string | HTMLElement | GridItemHTMLElement;
/**
* Event handler function types for the .on() method.
* Different handlers receive different parameters based on the event type.
*/
/** General event handler that receives only the event */
export type GridStackEventHandler = (event: Event) => void;
/** Element-specific event handler that receives event and affected element */
export type GridStackElementHandler = (event: Event, el: GridItemHTMLElement) => void;
/** Node-based event handler that receives event and array of affected nodes */
export type GridStackNodesHandler = (event: Event, nodes: GridStackNode[]) => void;
/** Drop event handler that receives previous and new node states */
export type GridStackDroppedHandler = (event: Event, previousNode: GridStackNode, newNode: GridStackNode) => void;
/** Union type of all possible event handler types */
export type GridStackEventHandlerCallback = GridStackEventHandler | GridStackElementHandler | GridStackNodesHandler | GridStackDroppedHandler;
/**
* Optional callback function called during load() operations.
* Allows custom handling of widget addition/removal for framework integration.
*
* @param parent - The parent HTML element
* @param w - The widget definition
* @param add - True if adding, false if removing
* @param grid - True if this is a grid operation
* @returns The created/modified HTML element, or undefined
*/
export type AddRemoveFcn = (parent: HTMLElement, w: GridStackWidget, add: boolean, grid: boolean) => HTMLElement | undefined;
/**
* Optional callback function called during save() operations.
* Allows adding custom data to the saved widget structure.
*
* @param node - The internal grid node
* @param w - The widget structure being saved (can be modified)
*/
export type SaveFcn = (node: GridStackNode, w: GridStackWidget) => void;
/**
* Optional callback function for custom widget content rendering.
* Called during load()/addWidget() to create custom content beyond plain text.
*
* @param el - The widget's content container element
* @param w - The widget definition with content and other properties
*/
export type RenderFcn = (el: HTMLElement, w: GridStackWidget) => void;
/**
* Optional callback function for custom resize-to-content behavior.
* Called when a widget needs to resize to fit its content.
*
* @param el - The grid item element to resize
*/
export type ResizeToContentFcn = (el: GridItemHTMLElement) => void;
/**
* Configuration for responsive grid behavior.
*
* Defines how the grid responds to different screen sizes by changing column counts.
* NOTE: Make sure to include the appropriate CSS (gridstack-extra.css) to support responsive behavior.
*/
export interface Responsive {
/** wanted width to maintain (+-50%) to dynamically pick a column count. NOTE: make sure to have correct extra CSS to support this. */
columnWidth?: number;
/** maximum number of columns allowed (default: 12). NOTE: make sure to have correct extra CSS to support this. */
columnMax?: number;
/** explicit width:column breakpoints instead of automatic 'columnWidth'. NOTE: make sure to have correct extra CSS to support this. */
breakpoints?: Breakpoint[];
/** specify if breakpoints are for window size or grid size (default:false = grid) */
breakpointForWindow?: boolean;
/** global re-layout mode when changing columns */
layout?: ColumnOptions;
}
/**
* Defines a responsive breakpoint for automatic column count changes.
* Used with the responsive.breakpoints option.
*/
export interface Breakpoint {
/** Maximum width (in pixels) for this breakpoint to be active */
w?: number;
/** Number of columns to use when this breakpoint is active */
c: number;
/** Layout mode for this specific breakpoint (overrides global responsive.layout) */
layout?: ColumnOptions;
}
/**
* Defines the options for a Grid
*/
export interface GridStackOptions {
/**
* Accept widgets dragged from other grids or from outside (default: `false`). Can be:
* - `true`: will accept HTML elements having 'grid-stack-item' as class attribute
* - `false`: will not accept any external widgets
* - string: explicit class name to accept instead of default
* - function: callback called before an item will be accepted when entering a grid
*
* @example
* // Accept all grid items
* acceptWidgets: true
*
* // Accept only items with specific class
* acceptWidgets: 'my-draggable-item'
*
* // Custom validation function
* acceptWidgets: (el) => {
* return el.getAttribute('data-accept') === 'true';
* }
*
* @see {@link http://gridstack.github.io/gridstack.js/demo/two.html} for complete example
*/
acceptWidgets?: boolean | string | ((element: Element) => boolean);
/** possible values (default: `mobile`) - does not apply to non-resizable widgets
* `false` the resizing handles are only shown while hovering over a widget
* `true` the resizing handles are always shown
* 'mobile' if running on a mobile device, default to `true` (since there is no hovering per say), else `false`.
See [example](http://gridstack.github.io/gridstack.js/demo/mobile.html) */
alwaysShowResizeHandle?: true | false | 'mobile';
/** turns animation on (default?: true) */
animate?: boolean;
/** if false gridstack will not initialize existing items (default?: true) */
auto?: boolean;
/**
* One cell height (default: 'auto'). Can be:
* - an integer (px): fixed pixel height
* - a string (ex: '100px', '10em', '10rem'): CSS length value
* - 0: library will not generate styles for rows (define your own CSS)
* - 'auto': height calculated for square cells (width / column) and updated live on window resize
* - 'initial': similar to 'auto' but stays fixed size during window resizing
*
* Note: % values don't work correctly - see demo/cell-height.html
*
* @example
* // Fixed 100px height
* cellHeight: 100
*
* // CSS units
* cellHeight: '5rem'
* cellHeight: '100px'
*
* // Auto-sizing for square cells
* cellHeight: 'auto'
*
* // No CSS generation (custom styles)
* cellHeight: 0
*/
cellHeight?: numberOrString;
/** throttle time delay (in ms) used when cellHeight='auto' to improve performance vs usability (default?: 100).
* A value of 0 will make it instant at a cost of re-creating the CSS file at ever window resize event!
* */
cellHeightThrottle?: number;
/** (internal) unit for cellHeight (default? 'px') which is set when a string cellHeight with a unit is passed (ex: '10rem') */
cellHeightUnit?: string;
/** list of children item to create when calling load() or addGrid() */
children?: GridStackWidget[];
/** number of columns (default?: 12). Note: IF you change this, CSS also have to change. See https://github.com/gridstack/gridstack.js#change-grid-columns.
* Note: for nested grids, it is recommended to use 'auto' which will always match the container grid-item current width (in column) to keep inside and outside
* items always the same. flag is NOT supported for regular non-nested grids.
*/
column?: number | 'auto';
/** responsive column layout for width:column behavior */
columnOpts?: Responsive;
/** additional class on top of '.grid-stack' (which is required for our CSS) to differentiate this instance.
Note: only used by addGrid(), else your element should have the needed class */
class?: string;
/** disallows dragging of widgets (default?: false) */
disableDrag?: boolean;
/** disallows resizing of widgets (default?: false). */
disableResize?: boolean;
/** allows to override UI draggable options. (default?: { handle?: '.grid-stack-item-content', appendTo?: 'body' }) */
draggable?: DDDragOpt;
/** let user drag nested grid items out of a parent or not (default true - not supported yet) */
/** the type of engine to create (so you can subclass) default to GridStackEngine */
engineClass?: typeof GridStackEngine;
/** enable floating widgets (default?: false) See example (http://gridstack.github.io/gridstack.js/demo/float.html) */
float?: boolean;
/** draggable handle selector (default?: '.grid-stack-item-content') */
handle?: string;
/** draggable handle class (e.g. 'grid-stack-item-content'). If set 'handle' is ignored (default?: null) */
handleClass?: string;
/** additional widget class (default?: 'grid-stack-item') */
itemClass?: string;
/** re-layout mode when we're a subgrid and we are being resized. default to 'list' */
layout?: ColumnOptions;
/** true when widgets are only created when they scroll into view (visible) */
lazyLoad?: boolean;
/**
* gap between grid item and content (default?: 10). This will set all 4 sides and support the CSS formats below
* an integer (px)
* a string with possible units (ex: '2em', '20px', '2rem')
* string with space separated values (ex: '5px 10px 0 20px' for all 4 sides, or '5em 10em' for top/bottom and left/right pairs like CSS).
* Note: all sides must have same units (last one wins, default px)
*/
margin?: numberOrString;
/** OLD way to optionally set each side - use margin: '5px 10px 0 20px' instead. Used internally to store each side. */
marginTop?: numberOrString;
marginRight?: numberOrString;
marginBottom?: numberOrString;
marginLeft?: numberOrString;
/** (internal) unit for margin (default? 'px') set when `margin` is set as string with unit (ex: 2rem') */
marginUnit?: string;
/** maximum rows amount. Default? is 0 which means no maximum rows */
maxRow?: number;
/** minimum rows amount which is handy to prevent grid from collapsing when empty. Default is `0`.
* When no set the `min-height` CSS attribute on the grid div (in pixels) can be used, which will round to the closest row.
*/
minRow?: number;
/** If you are using a nonce-based Content Security Policy, pass your nonce here and
* GridStack will add it to the <style> elements it creates. */
nonce?: string;
/** class for placeholder (default?: 'grid-stack-placeholder') */
placeholderClass?: string;
/** placeholder default content (default?: '') */
placeholderText?: string;
/** allows to override UI resizable options. (default?: { handles: 'se' }) */
resizable?: DDResizeOpt;
/**
* if true widgets could be removed by dragging outside of the grid. It could also be a selector string (ex: ".trash"),
* in this case widgets will be removed by dropping them there (default?: false)
* See example (http://gridstack.github.io/gridstack.js/demo/two.html)
*/
removable?: boolean | string;
/** allows to override UI removable options. (default?: { accept: '.grid-stack-item' }) */
removableOptions?: DDRemoveOpt;
/** fix grid number of rows. This is a shortcut of writing `minRow:N, maxRow:N`. (default `0` no constrain) */
row?: number;
/**
* if true turns grid to RTL. Possible values are true, false, 'auto' (default?: 'auto')
* See [example](http://gridstack.github.io/gridstack.js/demo/right-to-left(rtl).html)
*/
rtl?: boolean | 'auto';
/** set to true if all grid items (by default, but item can also override) height should be based on content size instead of WidgetItem.h to avoid v-scrollbars.
* Note: this is still row based, not pixels, so it will use ceil(getBoundingClientRect().height / getCellHeight())
*/
sizeToContent?: boolean;
/**
* makes grid static (default?: false). If `true` widgets are not movable/resizable.
* You don't even need draggable/resizable. A CSS class
* 'grid-stack-static' is also added to the element.
*/
staticGrid?: boolean;
/**
* @deprecated Not used anymore, styles are now implemented with local CSS variables
*/
styleInHead?: boolean;
/** list of differences in options for automatically created sub-grids under us (inside our grid-items) */
subGridOpts?: GridStackOptions;
/** enable/disable the creation of sub-grids on the fly by dragging items completely
* over others (nest) vs partially (push). Forces `DDDragOpt.pause=true` to accomplish that. */
subGridDynamic?: boolean;
}
/** options used during GridStackEngine.moveNode() */
export interface GridStackMoveOpts extends GridStackPosition {
/** node to skip collision */
skip?: GridStackNode;
/** do we pack (default true) */
pack?: boolean;
/** true if we are calling this recursively to prevent simple swap or coverage collision - default false*/
nested?: boolean;
/** vars to calculate other cells coordinates */
cellWidth?: number;
cellHeight?: number;
marginTop?: number;
marginBottom?: number;
marginLeft?: number;
marginRight?: number;
/** position in pixels of the currently dragged items (for overlap check) */
rect?: GridStackPosition;
/** true if we're live resizing */
resizing?: boolean;
/** best node (most coverage) we collied with */
collide?: GridStackNode;
/** for collision check even if we don't move */
forceCollide?: boolean;
}
export interface GridStackPosition {
/** widget position x (default?: 0) */
x?: number;
/** widget position y (default?: 0) */
y?: number;
/** widget dimension width (default?: 1) */
w?: number;
/** widget dimension height (default?: 1) */
h?: number;
}
/**
* GridStack Widget creation options
*/
export interface GridStackWidget extends GridStackPosition {
/** if true then x, y parameters will be ignored and widget will be places on the first available position (default?: false) */
autoPosition?: boolean;
/** minimum width allowed during resize/creation (default?: undefined = un-constrained) */
minW?: number;
/** maximum width allowed during resize/creation (default?: undefined = un-constrained) */
maxW?: number;
/** minimum height allowed during resize/creation (default?: undefined = un-constrained) */
minH?: number;
/** maximum height allowed during resize/creation (default?: undefined = un-constrained) */
maxH?: number;
/** prevent direct resizing by the user (default?: undefined = un-constrained) */
noResize?: boolean;
/** prevents direct moving by the user (default?: undefined = un-constrained) */
noMove?: boolean;
/** prevents being pushed by other widgets or api (default?: undefined = un-constrained), which is different from `noMove` (user action only) */
locked?: boolean;
/** value for `gs-id` stored on the widget (default?: undefined) */
id?: string;
/** html to append inside as content */
content?: string;
/** true when widgets are only created when they scroll into view (visible) */
lazyLoad?: boolean;
/** local (vs grid) override - see GridStackOptions.
* Note: This also allow you to set a maximum h value (but user changeable during normal resizing) to prevent unlimited content from taking too much space (get scrollbar) */
sizeToContent?: boolean | number;
/** local override of GridStack.resizeToContentParent that specify the class to use for the parent (actual) vs child (wanted) height */
resizeToContentParent?: string;
/** optional nested grid options and list of children, which then turns into actual instance at runtime to get options from */
subGridOpts?: GridStackOptions;
}
/** Drag&Drop resize options */
export interface DDResizeOpt {
/** do resize handle hide by default until mouse over ? - default: true on desktop, false on mobile*/
autoHide?: boolean;
/**
* sides where you can resize from (ex: 'e, se, s, sw, w') - default 'se' (south-east)
* Note: it is not recommended to resize from the top sides as weird side effect may occur.
*/
handles?: string;
}
/** Drag&Drop remove options */
export interface DDRemoveOpt {
/** class that can be removed (default?: opts.itemClass) */
accept?: string;
/** class that cannot be removed (default: 'grid-stack-non-removable') */
decline?: string;
}
/** Drag&Drop dragging options */
export interface DDDragOpt {
/** class selector of items that can be dragged. default to '.grid-stack-item-content' */
handle?: string;
/** default to 'body' */
appendTo?: string;
/** if set (true | msec), dragging placement (collision) will only happen after a pause by the user. Note: this is Global */
pause?: boolean | number;
/** default to `true` */
scroll?: boolean;
/** prevents dragging from starting on specified elements, listed as comma separated selectors (eg: '.no-drag'). default built in is 'input,textarea,button,select,option' */
cancel?: string;
/** helper function when dropping: 'clone' or your own method */
helper?: 'clone' | ((el: HTMLElement) => HTMLElement);
/** callbacks */
start?: (event: Event, ui: DDUIData) => void;
stop?: (event: Event) => void;
drag?: (event: Event, ui: DDUIData) => void;
}
export interface Size {
width: number;
height: number;
}
export interface Position {
top: number;
left: number;
}
export interface Rect extends Size, Position {
}
/** data that is passed during drag and resizing callbacks */
export interface DDUIData {
position?: Position;
size?: Size;
draggable?: HTMLElement;
}
/**
* internal runtime descriptions describing the widgets in the grid
*/
export interface GridStackNode extends GridStackWidget {
/** pointer back to HTML element */
el?: GridItemHTMLElement;
/** pointer back to parent Grid instance */
grid?: GridStack;
/** actual sub-grid instance */
subGrid?: GridStack;
/** allow delay creation when visible */
visibleObservable?: IntersectionObserver;
}

38
node_modules/gridstack/dist/src/types.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
/**
* types.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
/**
* Default values for grid options - used during initialization and when saving out grid configuration.
* These values are applied when options are not explicitly provided.
*/
export const gridDefaults = {
alwaysShowResizeHandle: 'mobile',
animate: true,
auto: true,
cellHeight: 'auto',
cellHeightThrottle: 100,
cellHeightUnit: 'px',
column: 12,
draggable: { handle: '.grid-stack-item-content', appendTo: 'body', scroll: true },
handle: '.grid-stack-item-content',
itemClass: 'grid-stack-item',
margin: 10,
marginUnit: 'px',
maxRow: 0,
minRow: 0,
placeholderClass: 'grid-stack-placeholder',
placeholderText: '',
removableOptions: { accept: 'grid-stack-item', decline: 'grid-stack-non-removable' },
resizable: { handles: 'se' },
rtl: 'auto',
// **** same as not being set ****
// disableDrag: false,
// disableResize: false,
// float: false,
// handleClass: null,
// removable: false,
// staticGrid: false,
//removable
};
//# sourceMappingURL=types.js.map

1
node_modules/gridstack/dist/src/types.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

283
node_modules/gridstack/dist/src/utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,283 @@
/**
* utils.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
import { GridStackElement, GridStackNode, numberOrString, GridStackPosition, GridStackWidget } from './types';
export interface HeightData {
h: number;
unit: string;
}
export interface DragTransform {
xScale: number;
yScale: number;
xOffset: number;
yOffset: number;
}
/**
* Collection of utility methods used throughout GridStack.
* These are general-purpose helper functions for DOM manipulation,
* positioning calculations, object operations, and more.
*/
export declare class Utils {
/**
* Convert a potential selector into an actual list of HTML elements.
* Supports CSS selectors, element references, and special ID handling.
*
* @param els selector string, HTMLElement, or array of elements
* @param root optional root element to search within (defaults to document, useful for shadow DOM)
* @returns array of HTML elements matching the selector
*
* @example
* const elements = Utils.getElements('.grid-item');
* const byId = Utils.getElements('#myWidget');
* const fromShadow = Utils.getElements('.item', shadowRoot);
*/
static getElements(els: GridStackElement, root?: HTMLElement | Document): HTMLElement[];
/**
* Convert a potential selector into a single HTML element.
* Similar to getElements() but returns only the first match.
*
* @param els selector string or HTMLElement
* @param root optional root element to search within (defaults to document)
* @returns the first HTML element matching the selector, or null if not found
*
* @example
* const element = Utils.getElement('#myWidget');
* const first = Utils.getElement('.grid-item');
*/
static getElement(els: GridStackElement, root?: HTMLElement | Document): HTMLElement;
/**
* Check if a widget should be lazy loaded based on node or grid settings.
*
* @param n the grid node to check
* @returns true if the item should be lazy loaded
*
* @example
* if (Utils.lazyLoad(node)) {
* // Set up intersection observer for lazy loading
* }
*/
static lazyLoad(n: GridStackNode): boolean;
/**
* Create a div element with the specified CSS classes.
*
* @param classes array of CSS class names to add
* @param parent optional parent element to append the div to
* @returns the created div element
*
* @example
* const div = Utils.createDiv(['grid-item', 'draggable']);
* const nested = Utils.createDiv(['content'], parentDiv);
*/
static createDiv(classes: string[], parent?: HTMLElement): HTMLElement;
/**
* Check if a widget should resize to fit its content.
*
* @param n the grid node to check (can be undefined)
* @param strict if true, only returns true for explicit sizeToContent:true (not numbers)
* @returns true if the widget should resize to content
*
* @example
* if (Utils.shouldSizeToContent(node)) {
* // Trigger content-based resizing
* }
*/
static shouldSizeToContent(n: GridStackNode | undefined, strict?: boolean): boolean;
/**
* Check if two grid positions overlap/intersect.
*
* @param a first position with x, y, w, h properties
* @param b second position with x, y, w, h properties
* @returns true if the positions overlap
*
* @example
* const overlaps = Utils.isIntercepted(
* {x: 0, y: 0, w: 2, h: 1},
* {x: 1, y: 0, w: 2, h: 1}
* ); // true - they overlap
*/
static isIntercepted(a: GridStackPosition, b: GridStackPosition): boolean;
/**
* Check if two grid positions are touching (edges or corners).
*
* @param a first position
* @param b second position
* @returns true if the positions are touching
*
* @example
* const touching = Utils.isTouching(
* {x: 0, y: 0, w: 2, h: 1},
* {x: 2, y: 0, w: 1, h: 1}
* ); // true - they share an edge
*/
static isTouching(a: GridStackPosition, b: GridStackPosition): boolean;
/**
* Calculate the overlapping area between two grid positions.
*
* @param a first position
* @param b second position
* @returns the area of overlap (0 if no overlap)
*
* @example
* const overlap = Utils.areaIntercept(
* {x: 0, y: 0, w: 3, h: 2},
* {x: 1, y: 0, w: 3, h: 2}
* ); // returns 4 (2x2 overlap)
*/
static areaIntercept(a: GridStackPosition, b: GridStackPosition): number;
/**
* Calculate the total area of a grid position.
*
* @param a position with width and height
* @returns the total area (width * height)
*
* @example
* const area = Utils.area({x: 0, y: 0, w: 3, h: 2}); // returns 6
*/
static area(a: GridStackPosition): number;
/**
* Sort an array of grid nodes by position (y first, then x).
*
* @param nodes array of nodes to sort
* @param dir sort direction: 1 for ascending (top-left first), -1 for descending
* @returns the sorted array (modifies original)
*
* @example
* const sorted = Utils.sort(nodes); // Sort top-left to bottom-right
* const reverse = Utils.sort(nodes, -1); // Sort bottom-right to top-left
*/
static sort(nodes: GridStackNode[], dir?: 1 | -1): GridStackNode[];
/**
* Find a grid node by its ID.
*
* @param nodes array of nodes to search
* @param id the ID to search for
* @returns the node with matching ID, or undefined if not found
*
* @example
* const node = Utils.find(nodes, 'widget-1');
* if (node) console.log('Found node at:', node.x, node.y);
*/
static find(nodes: GridStackNode[], id: string): GridStackNode | undefined;
/**
* Convert various value types to boolean.
* Handles strings like 'false', 'no', '0' as false.
*
* @param v value to convert
* @returns boolean representation
*
* @example
* Utils.toBool('true'); // true
* Utils.toBool('false'); // false
* Utils.toBool('no'); // false
* Utils.toBool('1'); // true
*/
static toBool(v: unknown): boolean;
/**
* Convert a string value to a number, handling null and empty strings.
*
* @param value string or null value to convert
* @returns number value, or undefined for null/empty strings
*
* @example
* Utils.toNumber('42'); // 42
* Utils.toNumber(''); // undefined
* Utils.toNumber(null); // undefined
*/
static toNumber(value: null | string): number;
/**
* Parse a height value with units into numeric value and unit string.
* Supports px, em, rem, vh, vw, %, cm, mm units.
*
* @param val height value as number or string with units
* @returns object with h (height) and unit properties
*
* @example
* Utils.parseHeight('100px'); // {h: 100, unit: 'px'}
* Utils.parseHeight('2rem'); // {h: 2, unit: 'rem'}
* Utils.parseHeight(50); // {h: 50, unit: 'px'}
*/
static parseHeight(val: numberOrString): HeightData;
/**
* Copy unset fields from source objects to target object (shallow merge with defaults).
* Similar to Object.assign but only sets undefined/null fields.
*
* @param target the object to copy defaults into
* @param sources one or more source objects to copy defaults from
* @returns the modified target object
*
* @example
* const config = { width: 100 };
* Utils.defaults(config, { width: 200, height: 50 });
* // config is now { width: 100, height: 50 }
*/
static defaults(target: any, ...sources: any[]): {};
/**
* Compare two objects for equality (shallow comparison).
* Checks if objects have the same fields and values at one level deep.
*
* @param a first object to compare
* @param b second object to compare
* @returns true if objects have the same values
*
* @example
* Utils.same({x: 1, y: 2}, {x: 1, y: 2}); // true
* Utils.same({x: 1}, {x: 1, y: 2}); // false
*/
static same(a: unknown, b: unknown): boolean;
/**
* Copy position and size properties from one widget to another.
* Copies x, y, w, h and optionally min/max constraints.
*
* @param a target widget to copy to
* @param b source widget to copy from
* @param doMinMax if true, also copy min/max width/height constraints
* @returns the target widget (a)
*
* @example
* Utils.copyPos(widget1, widget2); // Copy position/size
* Utils.copyPos(widget1, widget2, true); // Also copy constraints
*/
static copyPos(a: GridStackWidget, b: GridStackWidget, doMinMax?: boolean): GridStackWidget;
/** true if a and b has same size & position */
static samePos(a: GridStackPosition, b: GridStackPosition): boolean;
/** given a node, makes sure it's min/max are valid */
static sanitizeMinMax(node: GridStackNode): void;
/** removes field from the first object if same as the second objects (like diffing) and internal '_' for saving */
static removeInternalAndSame(a: unknown, b: unknown): void;
/** removes internal fields '_' and default values for saving */
static removeInternalForSave(n: GridStackNode, removeEl?: boolean): void;
/** return the closest parent (or itself) matching the given class */
/** delay calling the given function for given delay, preventing new calls from happening while waiting */
static throttle(func: () => void, delay: number): () => void;
static removePositioningStyles(el: HTMLElement): void;
/** single level clone, returning a new object with same top fields. This will share sub objects and arrays */
static clone<T>(obj: T): T;
/**
* Recursive clone version that returns a full copy, checking for nested objects and arrays ONLY.
* Note: this will use as-is any key starting with double __ (and not copy inside) some lib have circular dependencies.
*/
static cloneDeep<T>(obj: T): T;
/** deep clone the given HTML node, removing teh unique id field */
static cloneNode(el: HTMLElement): HTMLElement;
static appendTo(el: HTMLElement, parent: string | HTMLElement): void;
static addElStyles(el: HTMLElement, styles: {
[prop: string]: string | string[];
}): void;
static initEvent<T>(e: DragEvent | MouseEvent, info: {
type: string;
target?: EventTarget;
}): T;
/** copies the MouseEvent (or convert Touch) properties and sends it as another event to the given target */
static simulateMouseEvent(e: MouseEvent | Touch, simulatedType: string, target?: EventTarget): void;
/**
* defines an element that is used to get the offset and scale from grid transforms
* returns the scale and offsets from said element
*/
static getValuesFromTransformedElement(parent: HTMLElement): DragTransform;
/** swap the given object 2 field values */
static swap(o: unknown, a: string, b: string): void;
/** returns true if event is inside the given element rectangle */
/** true if the item can be rotated (checking for prop, not space available) */
static canBeRotated(n: GridStackNode): boolean;
}

790
node_modules/gridstack/dist/src/utils.js generated vendored Normal file
View File

@@ -0,0 +1,790 @@
/**
* utils.ts 12.3.3
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
*/
/**
* @internal Checks for obsolete method names and provides deprecation warnings.
* Creates a wrapper function that logs a deprecation warning when called.
*
* @param self the object context to apply the function to
* @param f the new function to call
* @param oldName the deprecated method name
* @param newName the new method name to use instead
* @param rev the version when the deprecation was introduced
* @returns a wrapper function that warns about deprecation
*/
// eslint-disable-next-line
export function obsolete(self, f, oldName, newName, rev) {
const wrapper = (...args) => {
console.warn('gridstack.js: Function `' + oldName + '` is deprecated in ' + rev + ' and has been replaced ' +
'with `' + newName + '`. It will be **removed** in a future release');
return f.apply(self, args);
};
wrapper.prototype = f.prototype;
return wrapper;
}
/**
* @internal Checks for obsolete grid options and migrates them to new names.
* Automatically copies old option values to new option names and shows deprecation warnings.
*
* @param opts the options object to check and migrate
* @param oldName the deprecated option name
* @param newName the new option name to use instead
* @param rev the version when the deprecation was introduced
*/
export function obsoleteOpts(opts, oldName, newName, rev) {
if (opts[oldName] !== undefined) {
opts[newName] = opts[oldName];
console.warn('gridstack.js: Option `' + oldName + '` is deprecated in ' + rev + ' and has been replaced with `' +
newName + '`. It will be **removed** in a future release');
}
}
/**
* @internal Checks for obsolete grid options that have been completely removed.
* Shows deprecation warnings for options that are no longer supported.
*
* @param opts the options object to check
* @param oldName the removed option name
* @param rev the version when the option was removed
* @param info additional information about the removal
*/
export function obsoleteOptsDel(opts, oldName, rev, info) {
if (opts[oldName] !== undefined) {
console.warn('gridstack.js: Option `' + oldName + '` is deprecated in ' + rev + info);
}
}
/**
* @internal Checks for obsolete HTML element attributes and migrates them.
* Automatically copies old attribute values to new attribute names and shows deprecation warnings.
*
* @param el the HTML element to check and migrate
* @param oldName the deprecated attribute name
* @param newName the new attribute name to use instead
* @param rev the version when the deprecation was introduced
*/
export function obsoleteAttr(el, oldName, newName, rev) {
const oldAttr = el.getAttribute(oldName);
if (oldAttr !== null) {
el.setAttribute(newName, oldAttr);
console.warn('gridstack.js: attribute `' + oldName + '`=' + oldAttr + ' is deprecated on this object in ' + rev + ' and has been replaced with `' +
newName + '`. It will be **removed** in a future release');
}
}
/**
* Collection of utility methods used throughout GridStack.
* These are general-purpose helper functions for DOM manipulation,
* positioning calculations, object operations, and more.
*/
export class Utils {
/**
* Convert a potential selector into an actual list of HTML elements.
* Supports CSS selectors, element references, and special ID handling.
*
* @param els selector string, HTMLElement, or array of elements
* @param root optional root element to search within (defaults to document, useful for shadow DOM)
* @returns array of HTML elements matching the selector
*
* @example
* const elements = Utils.getElements('.grid-item');
* const byId = Utils.getElements('#myWidget');
* const fromShadow = Utils.getElements('.item', shadowRoot);
*/
static getElements(els, root = document) {
if (typeof els === 'string') {
const doc = ('getElementById' in root) ? root : undefined;
// Note: very common for people use to id='1,2,3' which is only legal as HTML5 id, but not CSS selectors
// so if we start with a number, assume it's an id and just return that one item...
// see https://github.com/gridstack/gridstack.js/issues/2234#issuecomment-1523796562
if (doc && !isNaN(+els[0])) { // start with digit
const el = doc.getElementById(els);
return el ? [el] : [];
}
let list = root.querySelectorAll(els);
if (!list.length && els[0] !== '.' && els[0] !== '#') {
list = root.querySelectorAll('.' + els);
if (!list.length) {
list = root.querySelectorAll('#' + els);
}
}
return Array.from(list);
}
return [els];
}
/**
* Convert a potential selector into a single HTML element.
* Similar to getElements() but returns only the first match.
*
* @param els selector string or HTMLElement
* @param root optional root element to search within (defaults to document)
* @returns the first HTML element matching the selector, or null if not found
*
* @example
* const element = Utils.getElement('#myWidget');
* const first = Utils.getElement('.grid-item');
*/
static getElement(els, root = document) {
if (typeof els === 'string') {
const doc = ('getElementById' in root) ? root : undefined;
if (!els.length)
return null;
if (doc && els[0] === '#') {
return doc.getElementById(els.substring(1));
}
if (els[0] === '#' || els[0] === '.' || els[0] === '[') {
return root.querySelector(els);
}
// if we start with a digit, assume it's an id (error calling querySelector('#1')) as class are not valid CSS
if (doc && !isNaN(+els[0])) { // start with digit
return doc.getElementById(els);
}
// finally try string, then id, then class
let el = root.querySelector(els);
if (doc && !el) {
el = doc.getElementById(els);
}
if (!el) {
el = root.querySelector('.' + els);
}
return el;
}
return els;
}
/**
* Check if a widget should be lazy loaded based on node or grid settings.
*
* @param n the grid node to check
* @returns true if the item should be lazy loaded
*
* @example
* if (Utils.lazyLoad(node)) {
* // Set up intersection observer for lazy loading
* }
*/
static lazyLoad(n) {
return n.lazyLoad || n.grid?.opts?.lazyLoad && n.lazyLoad !== false;
}
/**
* Create a div element with the specified CSS classes.
*
* @param classes array of CSS class names to add
* @param parent optional parent element to append the div to
* @returns the created div element
*
* @example
* const div = Utils.createDiv(['grid-item', 'draggable']);
* const nested = Utils.createDiv(['content'], parentDiv);
*/
static createDiv(classes, parent) {
const el = document.createElement('div');
classes.forEach(c => { if (c)
el.classList.add(c); });
parent?.appendChild(el);
return el;
}
/**
* Check if a widget should resize to fit its content.
*
* @param n the grid node to check (can be undefined)
* @param strict if true, only returns true for explicit sizeToContent:true (not numbers)
* @returns true if the widget should resize to content
*
* @example
* if (Utils.shouldSizeToContent(node)) {
* // Trigger content-based resizing
* }
*/
static shouldSizeToContent(n, strict = false) {
return n?.grid && (strict ?
(n.sizeToContent === true || (n.grid.opts.sizeToContent === true && n.sizeToContent === undefined)) :
(!!n.sizeToContent || (n.grid.opts.sizeToContent && n.sizeToContent !== false)));
}
/**
* Check if two grid positions overlap/intersect.
*
* @param a first position with x, y, w, h properties
* @param b second position with x, y, w, h properties
* @returns true if the positions overlap
*
* @example
* const overlaps = Utils.isIntercepted(
* {x: 0, y: 0, w: 2, h: 1},
* {x: 1, y: 0, w: 2, h: 1}
* ); // true - they overlap
*/
static isIntercepted(a, b) {
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);
}
/**
* Check if two grid positions are touching (edges or corners).
*
* @param a first position
* @param b second position
* @returns true if the positions are touching
*
* @example
* const touching = Utils.isTouching(
* {x: 0, y: 0, w: 2, h: 1},
* {x: 2, y: 0, w: 1, h: 1}
* ); // true - they share an edge
*/
static isTouching(a, b) {
return Utils.isIntercepted(a, { x: b.x - 0.5, y: b.y - 0.5, w: b.w + 1, h: b.h + 1 });
}
/**
* Calculate the overlapping area between two grid positions.
*
* @param a first position
* @param b second position
* @returns the area of overlap (0 if no overlap)
*
* @example
* const overlap = Utils.areaIntercept(
* {x: 0, y: 0, w: 3, h: 2},
* {x: 1, y: 0, w: 3, h: 2}
* ); // returns 4 (2x2 overlap)
*/
static areaIntercept(a, b) {
const x0 = (a.x > b.x) ? a.x : b.x;
const x1 = (a.x + a.w < b.x + b.w) ? a.x + a.w : b.x + b.w;
if (x1 <= x0)
return 0; // no overlap
const y0 = (a.y > b.y) ? a.y : b.y;
const y1 = (a.y + a.h < b.y + b.h) ? a.y + a.h : b.y + b.h;
if (y1 <= y0)
return 0; // no overlap
return (x1 - x0) * (y1 - y0);
}
/**
* Calculate the total area of a grid position.
*
* @param a position with width and height
* @returns the total area (width * height)
*
* @example
* const area = Utils.area({x: 0, y: 0, w: 3, h: 2}); // returns 6
*/
static area(a) {
return a.w * a.h;
}
/**
* Sort an array of grid nodes by position (y first, then x).
*
* @param nodes array of nodes to sort
* @param dir sort direction: 1 for ascending (top-left first), -1 for descending
* @returns the sorted array (modifies original)
*
* @example
* const sorted = Utils.sort(nodes); // Sort top-left to bottom-right
* const reverse = Utils.sort(nodes, -1); // Sort bottom-right to top-left
*/
static sort(nodes, dir = 1) {
const und = 10000;
return nodes.sort((a, b) => {
const diffY = dir * ((a.y ?? und) - (b.y ?? und));
if (diffY === 0)
return dir * ((a.x ?? und) - (b.x ?? und));
return diffY;
});
}
/**
* Find a grid node by its ID.
*
* @param nodes array of nodes to search
* @param id the ID to search for
* @returns the node with matching ID, or undefined if not found
*
* @example
* const node = Utils.find(nodes, 'widget-1');
* if (node) console.log('Found node at:', node.x, node.y);
*/
static find(nodes, id) {
return id ? nodes.find(n => n.id === id) : undefined;
}
/**
* Convert various value types to boolean.
* Handles strings like 'false', 'no', '0' as false.
*
* @param v value to convert
* @returns boolean representation
*
* @example
* Utils.toBool('true'); // true
* Utils.toBool('false'); // false
* Utils.toBool('no'); // false
* Utils.toBool('1'); // true
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static toBool(v) {
if (typeof v === 'boolean') {
return v;
}
if (typeof v === 'string') {
v = v.toLowerCase();
return !(v === '' || v === 'no' || v === 'false' || v === '0');
}
return Boolean(v);
}
/**
* Convert a string value to a number, handling null and empty strings.
*
* @param value string or null value to convert
* @returns number value, or undefined for null/empty strings
*
* @example
* Utils.toNumber('42'); // 42
* Utils.toNumber(''); // undefined
* Utils.toNumber(null); // undefined
*/
static toNumber(value) {
return (value === null || value.length === 0) ? undefined : Number(value);
}
/**
* Parse a height value with units into numeric value and unit string.
* Supports px, em, rem, vh, vw, %, cm, mm units.
*
* @param val height value as number or string with units
* @returns object with h (height) and unit properties
*
* @example
* Utils.parseHeight('100px'); // {h: 100, unit: 'px'}
* Utils.parseHeight('2rem'); // {h: 2, unit: 'rem'}
* Utils.parseHeight(50); // {h: 50, unit: 'px'}
*/
static parseHeight(val) {
let h;
let unit = 'px';
if (typeof val === 'string') {
if (val === 'auto' || val === '')
h = 0;
else {
const match = val.match(/^(-[0-9]+\.[0-9]+|[0-9]*\.[0-9]+|-[0-9]+|[0-9]+)(px|em|rem|vh|vw|%|cm|mm)?$/);
if (!match) {
throw new Error(`Invalid height val = ${val}`);
}
unit = match[2] || 'px';
h = parseFloat(match[1]);
}
}
else {
h = val;
}
return { h, unit };
}
/**
* Copy unset fields from source objects to target object (shallow merge with defaults).
* Similar to Object.assign but only sets undefined/null fields.
*
* @param target the object to copy defaults into
* @param sources one or more source objects to copy defaults from
* @returns the modified target object
*
* @example
* const config = { width: 100 };
* Utils.defaults(config, { width: 200, height: 50 });
* // config is now { width: 100, height: 50 }
*/
// eslint-disable-next-line
static defaults(target, ...sources) {
sources.forEach(source => {
for (const key in source) {
if (!source.hasOwnProperty(key))
return;
if (target[key] === null || target[key] === undefined) {
target[key] = source[key];
}
else if (typeof source[key] === 'object' && typeof target[key] === 'object') {
// property is an object, recursively add it's field over... #1373
Utils.defaults(target[key], source[key]);
}
}
});
return target;
}
/**
* Compare two objects for equality (shallow comparison).
* Checks if objects have the same fields and values at one level deep.
*
* @param a first object to compare
* @param b second object to compare
* @returns true if objects have the same values
*
* @example
* Utils.same({x: 1, y: 2}, {x: 1, y: 2}); // true
* Utils.same({x: 1}, {x: 1, y: 2}); // false
*/
static same(a, b) {
if (typeof a !== 'object')
return a == b;
if (typeof a !== typeof b)
return false;
// else we have object, check just 1 level deep for being same things...
if (Object.keys(a).length !== Object.keys(b).length)
return false;
for (const key in a) {
if (a[key] !== b[key])
return false;
}
return true;
}
/**
* Copy position and size properties from one widget to another.
* Copies x, y, w, h and optionally min/max constraints.
*
* @param a target widget to copy to
* @param b source widget to copy from
* @param doMinMax if true, also copy min/max width/height constraints
* @returns the target widget (a)
*
* @example
* Utils.copyPos(widget1, widget2); // Copy position/size
* Utils.copyPos(widget1, widget2, true); // Also copy constraints
*/
static copyPos(a, b, doMinMax = false) {
if (b.x !== undefined)
a.x = b.x;
if (b.y !== undefined)
a.y = b.y;
if (b.w !== undefined)
a.w = b.w;
if (b.h !== undefined)
a.h = b.h;
if (doMinMax) {
if (b.minW)
a.minW = b.minW;
if (b.minH)
a.minH = b.minH;
if (b.maxW)
a.maxW = b.maxW;
if (b.maxH)
a.maxH = b.maxH;
}
return a;
}
/** true if a and b has same size & position */
static samePos(a, b) {
return a && b && a.x === b.x && a.y === b.y && (a.w || 1) === (b.w || 1) && (a.h || 1) === (b.h || 1);
}
/** given a node, makes sure it's min/max are valid */
static sanitizeMinMax(node) {
// remove 0, undefine, null
if (!node.minW) {
delete node.minW;
}
if (!node.minH) {
delete node.minH;
}
if (!node.maxW) {
delete node.maxW;
}
if (!node.maxH) {
delete node.maxH;
}
}
/** removes field from the first object if same as the second objects (like diffing) and internal '_' for saving */
static removeInternalAndSame(a, b) {
if (typeof a !== 'object' || typeof b !== 'object')
return;
// skip arrays as we don't know how to hydrate them (unlike object spread operator)
if (Array.isArray(a) || Array.isArray(b))
return;
for (let key in a) {
const aVal = a[key];
const bVal = b[key];
if (key[0] === '_' || aVal === bVal) {
delete a[key];
}
else if (aVal && typeof aVal === 'object' && bVal !== undefined) {
Utils.removeInternalAndSame(aVal, bVal);
if (!Object.keys(aVal).length) {
delete a[key];
}
}
}
}
/** removes internal fields '_' and default values for saving */
static removeInternalForSave(n, removeEl = true) {
for (let key in n) {
if (key[0] === '_' || n[key] === null || n[key] === undefined)
delete n[key];
}
delete n.grid;
if (removeEl)
delete n.el;
// delete default values (will be re-created on read)
if (!n.autoPosition)
delete n.autoPosition;
if (!n.noResize)
delete n.noResize;
if (!n.noMove)
delete n.noMove;
if (!n.locked)
delete n.locked;
if (n.w === 1 || n.w === n.minW)
delete n.w;
if (n.h === 1 || n.h === n.minH)
delete n.h;
}
/** return the closest parent (or itself) matching the given class */
// static closestUpByClass(el: HTMLElement, name: string): HTMLElement {
// while (el) {
// if (el.classList.contains(name)) return el;
// el = el.parentElement
// }
// return null;
// }
/** delay calling the given function for given delay, preventing new calls from happening while waiting */
static throttle(func, delay) {
let isWaiting = false;
return (...args) => {
if (!isWaiting) {
isWaiting = true;
setTimeout(() => { func(...args); isWaiting = false; }, delay);
}
};
}
static removePositioningStyles(el) {
const style = el.style;
if (style.position) {
style.removeProperty('position');
}
if (style.left) {
style.removeProperty('left');
}
if (style.top) {
style.removeProperty('top');
}
if (style.width) {
style.removeProperty('width');
}
if (style.height) {
style.removeProperty('height');
}
}
/** @internal returns the passed element if scrollable, else the closest parent that will, up to the entire document scrolling element */
static getScrollElement(el) {
if (!el)
return document.scrollingElement || document.documentElement; // IE support
const style = getComputedStyle(el);
const overflowRegex = /(auto|scroll)/;
if (overflowRegex.test(style.overflow + style.overflowY)) {
return el;
}
else {
return Utils.getScrollElement(el.parentElement);
}
}
/** @internal */
static updateScrollPosition(el, position, distance) {
const scrollEl = Utils.getScrollElement(el);
if (!scrollEl)
return;
const elRect = el.getBoundingClientRect();
const scrollRect = scrollEl.getBoundingClientRect();
const innerHeightOrClientHeight = (window.innerHeight || document.documentElement.clientHeight);
const offsetDiffDown = elRect.bottom - Math.min(scrollRect.bottom, innerHeightOrClientHeight);
const offsetDiffUp = elRect.top - Math.max(scrollRect.top, 0);
const prevScroll = scrollEl.scrollTop;
if (offsetDiffUp < 0 && distance < 0) {
// scroll up
if (el.offsetHeight > scrollRect.height) {
scrollEl.scrollTop += distance;
}
else {
scrollEl.scrollTop += Math.abs(offsetDiffUp) > Math.abs(distance) ? distance : offsetDiffUp;
}
}
else if (offsetDiffDown > 0 && distance > 0) {
// scroll down
if (el.offsetHeight > scrollRect.height) {
scrollEl.scrollTop += distance;
}
else {
scrollEl.scrollTop += offsetDiffDown > distance ? distance : offsetDiffDown;
}
}
position.top += scrollEl.scrollTop - prevScroll;
}
/**
* @internal Function used to scroll the page.
*
* @param event `MouseEvent` that triggers the resize
* @param el `HTMLElement` that's being resized
* @param distance Distance from the V edges to start scrolling
*/
static updateScrollResize(event, el, distance) {
const scrollEl = Utils.getScrollElement(el);
const height = scrollEl.clientHeight;
// #1727 event.clientY is relative to viewport, so must compare this against position of scrollEl getBoundingClientRect().top
// #1745 Special situation if scrollEl is document 'html': here browser spec states that
// clientHeight is height of viewport, but getBoundingClientRect() is rectangle of html element;
// this discrepancy arises because in reality scrollbar is attached to viewport, not html element itself.
const offsetTop = (scrollEl === Utils.getScrollElement()) ? 0 : scrollEl.getBoundingClientRect().top;
const pointerPosY = event.clientY - offsetTop;
const top = pointerPosY < distance;
const bottom = pointerPosY > height - distance;
if (top) {
// This also can be done with a timeout to keep scrolling while the mouse is
// in the scrolling zone. (will have smoother behavior)
scrollEl.scrollBy({ behavior: 'smooth', top: pointerPosY - distance });
}
else if (bottom) {
scrollEl.scrollBy({ behavior: 'smooth', top: distance - (height - pointerPosY) });
}
}
/** single level clone, returning a new object with same top fields. This will share sub objects and arrays */
static clone(obj) {
if (obj === null || obj === undefined || typeof (obj) !== 'object') {
return obj;
}
// return Object.assign({}, obj);
if (obj instanceof Array) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return [...obj];
}
return { ...obj };
}
/**
* Recursive clone version that returns a full copy, checking for nested objects and arrays ONLY.
* Note: this will use as-is any key starting with double __ (and not copy inside) some lib have circular dependencies.
*/
static cloneDeep(obj) {
// list of fields we will skip during cloneDeep (nested objects, other internal)
const skipFields = ['parentGrid', 'el', 'grid', 'subGrid', 'engine'];
// return JSON.parse(JSON.stringify(obj)); // doesn't work with date format ?
const ret = Utils.clone(obj);
for (const key in ret) {
// NOTE: we don't support function/circular dependencies so skip those properties for now...
if (ret.hasOwnProperty(key) && typeof (ret[key]) === 'object' && key.substring(0, 2) !== '__' && !skipFields.find(k => k === key)) {
ret[key] = Utils.cloneDeep(obj[key]);
}
}
return ret;
}
/** deep clone the given HTML node, removing teh unique id field */
static cloneNode(el) {
const node = el.cloneNode(true);
node.removeAttribute('id');
return node;
}
static appendTo(el, parent) {
let parentNode;
if (typeof parent === 'string') {
parentNode = Utils.getElement(parent);
}
else {
parentNode = parent;
}
if (parentNode) {
parentNode.appendChild(el);
}
}
// public static setPositionRelative(el: HTMLElement): void {
// if (!(/^(?:r|a|f)/).test(getComputedStyle(el).position)) {
// el.style.position = "relative";
// }
// }
static addElStyles(el, styles) {
if (styles instanceof Object) {
for (const s in styles) {
if (styles.hasOwnProperty(s)) {
if (Array.isArray(styles[s])) {
// support fallback value
styles[s].forEach(val => {
el.style[s] = val;
});
}
else {
el.style[s] = styles[s];
}
}
}
}
}
static initEvent(e, info) {
const evt = { type: info.type };
const obj = {
button: 0,
which: 0,
buttons: 1,
bubbles: true,
cancelable: true,
target: info.target ? info.target : e.target
};
['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].forEach(p => evt[p] = e[p]); // keys
['pageX', 'pageY', 'clientX', 'clientY', 'screenX', 'screenY'].forEach(p => evt[p] = e[p]); // point info
return { ...evt, ...obj };
}
/** copies the MouseEvent (or convert Touch) properties and sends it as another event to the given target */
static simulateMouseEvent(e, simulatedType, target) {
const me = e;
const simulatedEvent = new MouseEvent(simulatedType, {
bubbles: true,
composed: true,
cancelable: true,
view: window,
detail: 1,
screenX: e.screenX,
screenY: e.screenY,
clientX: e.clientX,
clientY: e.clientY,
ctrlKey: me.ctrlKey ?? false,
altKey: me.altKey ?? false,
shiftKey: me.shiftKey ?? false,
metaKey: me.metaKey ?? false,
button: 0,
relatedTarget: e.target
});
(target || e.target).dispatchEvent(simulatedEvent);
}
/**
* defines an element that is used to get the offset and scale from grid transforms
* returns the scale and offsets from said element
*/
static getValuesFromTransformedElement(parent) {
const transformReference = document.createElement('div');
Utils.addElStyles(transformReference, {
opacity: '0',
position: 'fixed',
top: 0 + 'px',
left: 0 + 'px',
width: '1px',
height: '1px',
zIndex: '-999999',
});
parent.appendChild(transformReference);
const transformValues = transformReference.getBoundingClientRect();
parent.removeChild(transformReference);
transformReference.remove();
return {
xScale: 1 / transformValues.width,
yScale: 1 / transformValues.height,
xOffset: transformValues.left,
yOffset: transformValues.top,
};
}
/** swap the given object 2 field values */
static swap(o, a, b) {
if (!o)
return;
const tmp = o[a];
o[a] = o[b];
o[b] = tmp;
}
/** returns true if event is inside the given element rectangle */
// Note: Safari Mac has null event.relatedTarget which causes #1684 so check if DragEvent is inside the coordinates instead
// Utils.el.contains(event.relatedTarget as HTMLElement)
// public static inside(e: MouseEvent, el: HTMLElement): boolean {
// // srcElement, toElement, target: all set to placeholder when leaving simple grid, so we can't use that (Chrome)
// const target: HTMLElement = e.relatedTarget || (e as any).fromElement;
// if (!target) {
// const { bottom, left, right, top } = el.getBoundingClientRect();
// return (e.x < right && e.x > left && e.y < bottom && e.y > top);
// }
// return el.contains(target);
// }
/** true if the item can be rotated (checking for prop, not space available) */
static canBeRotated(n) {
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));
}
}
//# sourceMappingURL=utils.js.map

1
node_modules/gridstack/dist/src/utils.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long